Example #1
0
// Try to lock a file with name based on host ID,
// to prevent 2 schedulers from running at same time for same host.
// Return:
// 0 if successful
//    In this case store file descriptor in reply struct so we can unlock later
//    In other cases store -1 in reply struct
// PID (>0) if another process has lock
// -1 if error (e.g. can't create file)
//
int lock_sched() {
    char filename[256];
    char pid_string[16];
    int fd, pid, count;

    g_reply->lockfile_fd=-1;

    sprintf(filename, "%s/CGI_%07d",
            config.sched_lockfile_dir, g_reply->host.id
           );

    fd = open(filename, O_WRONLY|O_CREAT, S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH);
    if (fd < 0) return -1;

    // if we can't get an advisory write lock on the file,
    // return the PID of the process that DOES hold the lock.
    // (or -1 if failure)
    //
    pid = mylockf(fd);
    if (pid) {
        close(fd);
        return pid;
    }

    // write PID into the CGI_<HOSTID> file and flush to disk
    //
    count = sprintf(pid_string, "%d\n", getpid());
    ssize_t n = write(fd, pid_string, count);
    if (n < 0) {
        close(fd);
        return -1;
    }
    fsync(fd);

    g_reply->lockfile_fd = fd;
    return 0;
}
Example #2
0
// always returns HTML reply
//
int handle_get_file_size(char* file_name) {
    struct stat sbuf;
    char path[MAXPATHLEN], buf[256];
    int retval, pid, fd;

    // TODO: check to ensure path doesn't point somewhere bad
    // Use 64-bit variant
    //
    retval = dir_hier_path(
        file_name, config.upload_dir, config.uldl_dir_fanout, path
    );
    if (retval) {
        log_messages.printf(MSG_CRITICAL,
            "Failed to find/create directory for file '%s' in '%s'.\n",
            file_name, config.upload_dir
        );
        return return_error(ERR_TRANSIENT, "can't open file");
    }

    // if the volume is full, report a transient error
    // to prevent the client from starting a transfer
    //
    if (volume_full(config.upload_dir)) {
        return return_error(ERR_TRANSIENT, "Server is out of disk space");
    }

    fd = open(path, O_WRONLY|O_APPEND);

    if (fd<0 && ENOENT==errno) {
        // file does not exist: return zero length
        //
        log_messages.printf(MSG_NORMAL,
            "handle_get_file_size(): [%s] returning zero\n", file_name
        );
        return return_success("<file_size>0</file_size>");
    }

    if (fd<0) {
        // can't get file descriptor: try again later
        //
        log_messages.printf(MSG_CRITICAL,
            "handle_get_file_size(): cannot open [%s] %s\n",
            file_name, strerror(errno)
        );
        return return_error(ERR_TRANSIENT, "can't open file");
    }

    if ((pid=mylockf(fd))) {
        // file locked by another file_upload_handler: try again later
        //
        close(fd);
        log_messages.printf(MSG_CRITICAL,
            "handle_get_file_size(): [%s] returning error\n", file_name
        );
        return return_error(ERR_TRANSIENT,
            "[%s] locked by file_upload_handler PID=%d", file_name, pid
        );
    }
    // file exists, writable, not locked by anyone else, so return length.
    //
    retval = stat(path, &sbuf);
    close(fd);
    if (retval) {
        // file DOES perhaps exist, but can't stat it: try again later
        //
        log_messages.printf(MSG_CRITICAL,
            "handle_get_file_size(): [%s] returning error %s\n",
            file_name, strerror(errno)
        );
        return return_error(ERR_TRANSIENT, "cannot stat file" );
    }

    log_messages.printf(MSG_NORMAL,
        "handle_get_file_size(): [%s] returning %d\n",
        file_name, (int)sbuf.st_size
    );
    sprintf(buf, "<file_size>%d</file_size>", (int)sbuf.st_size);
    return return_success(buf);
}
Example #3
0
// read from socket, write to file
// ALWAYS returns an HTML reply
//
int copy_socket_to_file(FILE* in, char* path, double offset, double nbytes) {
    unsigned char buf[BLOCK_SIZE];
    struct stat sbuf;
    int pid;

    // open file.  Use raw IO not buffered IO so that we can use reliable
    // posix file locking.
    // Advisory file locking is not guaranteed reliable when
    // used with stream buffered IO.
    //
    int fd = open(path,
        O_WRONLY|O_CREAT,
        S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH
    );
    if (fd<0) {
        return return_error(ERR_TRANSIENT,
            "can't open file %s: %s\n", path, strerror(errno)
        );
    }

    // Put an advisory lock on the file.
    // This will prevent OTHER instances of file_upload_handler
    // from being able to write to the file.
    //
    pid = mylockf(fd);
    if (pid>0) {
        close(fd);
        return return_error(ERR_TRANSIENT,
            "can't lock file %s: %s locked by PID=%d\n",
            path, strerror(errno), pid
        );
    } else if (pid < 0) {
        close(fd);
        return return_error(ERR_TRANSIENT, "can't lock file %s\n", path);
    }

    // check that file length corresponds to offset
    // TODO: use a 64-bit variant
    //
    if (stat(path, &sbuf)) {
        close(fd);
        return return_error(ERR_TRANSIENT,
            "can't stat file %s: %s\n", path, strerror(errno)
        );
    }
    if (sbuf.st_size < offset) {
        close(fd);
        return return_error(ERR_TRANSIENT,
            "length of file %s %d bytes < offset %.0f bytes",
            path, (int)sbuf.st_size, offset
        );
    }
    if (offset) lseek(fd, offset, SEEK_SET);
    if (sbuf.st_size > offset) {
        log_messages.printf(MSG_CRITICAL,
            "file %s length on disk %d bytes; host upload starting at %.0f bytes.\n",
             this_filename, (int)sbuf.st_size, offset
        );
    }

    // caller guarantees that nbytes > offset
    //
    bytes_left = nbytes - offset;

    while (bytes_left > 0) {

        int n, m, to_write;

        m = bytes_left<(double)BLOCK_SIZE ? (int)bytes_left : BLOCK_SIZE;

        // try to get m bytes from socket (n>=0 is number actually returned)
        //
        n = fread(buf, 1, m, in);

        // try to write n bytes to file
        //
        to_write=n;
        while (to_write > 0) {
            ssize_t ret = write(fd, buf+n-to_write, to_write);
            if (ret < 0) {
                close(fd);
                const char* errmsg;
                if (errno == ENOSPC) {
                    errmsg = "No space left on server";
                } else {
                    errmsg = strerror(errno);
                }
                return return_error(ERR_TRANSIENT,
                    "can't write file %s: %s\n", path, errmsg
                );
            }
            to_write -= ret;
        }

        // check that we got all bytes from socket that were requested
        // Note: fread() reads less than requested only if there's
        // an error or EOF (see the man page)
        //
        if (n != m) {
            close(fd);
            if (feof(in)) {
                return return_error(ERR_TRANSIENT,
                    "EOF on socket read : asked for %d, got %d\n",
                    m, n
                );
            } else if (ferror(in)) {
                return return_error(ERR_TRANSIENT,
                    "error %d (%s) on socket read: asked for %d, got %d\n",
                    ferror(in), strerror(ferror(in)), m, n
                );
            } else {
                return return_error(ERR_TRANSIENT,
                    "incomplete socket read: asked for %d, got %d\n",
                    m, n
                );
            }
        }

        bytes_left -= n;
    }
    close(fd);
    return return_success(0);
}