Beispiel #1
0
/**
 * Moves a file from the temp to the destination directory
 */
void move_file_individual(struct group_list_t *group, const char *local_temp,
                          const char *local_dest, const char *filename)
{
    char temppath[MAXPATHNAME], destpath[MAXPATHNAME];
    stat_struct temp_stat, dest_stat;
    int len, found_dir;

    len = snprintf(temppath, sizeof(temppath), "%s%c%s", local_temp,
                   PATH_SEP, filename);
    if ((len >= sizeof(temppath)) || (len == -1)) {
        glog0(group, "Max pathname length exceeded: %s%c%s", local_temp,
                     PATH_SEP, filename);
        return;
    }
    len = snprintf(destpath, sizeof(destpath), "%s%c%s", local_dest,
                   PATH_SEP, filename);
    if ((len >= sizeof(destpath)) || (len == -1)) {
        glog0(group, "Max pathname length exceeded: %s%c%s", local_dest,
                     PATH_SEP, filename);
        return;
    }

    if (lstat_func(temppath, &temp_stat) == -1) {
        gsyserror(group, "Error getting file status for %s", temppath);
        return;
    }
    if (S_ISDIR(temp_stat.st_mode)) {
        found_dir = 0;
        if (lstat_func(destpath, &dest_stat) != -1) {
            if (!S_ISDIR(dest_stat.st_mode)) {
                clear_path(destpath, group);
            } else {
                found_dir = 1;
            }
        }
        if (!found_dir) {
            if (mkdir(destpath, 0755) == -1) {
                gsyserror(group, "Failed to create directory %s", destpath);
                return;
            }
        }
        move_files_individual(group, temppath, destpath);
    } else {
        clear_path(destpath, group);
#ifdef WINDOWS
        if (!MoveFile(temppath, destpath)) {
            char errbuf[300];
            FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL,
                    GetLastError(), 0, errbuf, sizeof(errbuf),NULL);
            glog0(group, "error (%d): %s", GetLastError(), errbuf);
        }
#else
        if (rename(temppath, destpath) == -1) {
            gsyserror(group, "Couldn't move file");
        }
#endif
        run_postreceive(group, destpath);
    }
}
Beispiel #2
0
/**
 * Flushes the cache to disk
 * Returns 1 on success, 0 on failure
 */
int flush_disk_cache(struct group_list_t *group)
{
    f_offset_t offset, seek_rval;
    int wrote_len;
    uint32_t i;

    if (group->fileinfo.cache_len == 0) return 1;
    offset = (f_offset_t) group->fileinfo.cache_start * group->blocksize;
    if ((seek_rval = lseek_func(group->fileinfo.fd,
            offset - group->fileinfo.curr_offset, SEEK_CUR)) == -1) {
        gsyserror(group, "lseek failed for file");
    }
    if (seek_rval != offset) {
        glog2(group, "offset is %s", printll(seek_rval));
        glog2(group, "  should be %s", printll(offset));
        if ((seek_rval = lseek_func(group->fileinfo.fd, offset,
                                    SEEK_SET)) == -1) {
            gsyserror(group, "lseek failed for file");
            return 0;
        }
    }
    if ((wrote_len = write(group->fileinfo.fd, group->fileinfo.cache,
                           group->fileinfo.cache_len)) == -1) {
        gsyserror(group, "Write failed for blocks %d - %d",
                        group->fileinfo.cache_start, group->fileinfo.cache_end);
        return 0;
    } else {
        group->fileinfo.curr_offset = offset + wrote_len;
        if (wrote_len != group->fileinfo.cache_len) {
            glog0(group, "Write failed for blocks %d - %d, only wrote %d bytes",
                        group->fileinfo.cache_start, group->fileinfo.cache_end);
            return 0;
        } else {
            glog4(group, "Wrote blocks %d - %d to disk from cache",
                        group->fileinfo.cache_start, group->fileinfo.cache_end);
            for (i = group->fileinfo.cache_start;
                    i <= group->fileinfo.cache_end; i++) {
                int status_idx = i - group->fileinfo.cache_start;
                if (group->fileinfo.cache_status[status_idx]) {
                    group->fileinfo.naklist[i] = 0;
                }
            }
            group->fileinfo.cache_start = group->fileinfo.cache_end + 1;
            while ((group->fileinfo.cache_start < group->fileinfo.blocks) &&
                    (!group->fileinfo.naklist[group->fileinfo.cache_start])) {
                group->fileinfo.cache_start++;
            }
            group->fileinfo.cache_end = group->fileinfo.cache_start;
            group->fileinfo.cache_len = 0;
            memset(group->fileinfo.cache, 0, cache_len);
            memset(group->fileinfo.cache_status,0,cache_len / group->blocksize);
            return 1;
        }
    }
}
Beispiel #3
0
/**
 * Move all files from temp to destination directory if at end of group.
 * Called recursively to move each file individually.
 */
void move_files_individual(struct group_list_t *group, const char *local_temp,
                           char *local_dest)
{
    int emptydir;

    {
#ifdef WINDOWS
        intptr_t ffhandle;
        struct _finddatai64_t finfo;
        char dirglob[MAXPATHNAME];

        snprintf(dirglob, sizeof(dirglob), "%s%c*", local_temp, PATH_SEP);
        if ((ffhandle = _findfirsti64(dirglob, &finfo)) == -1) {
            gsyserror(group, "Failed to open directory %s", dirglob);
            return;
        }
        emptydir = 1;
        do {
            if (strcmp(finfo.name, ".") && strcmp(finfo.name, "..")) {
                emptydir = 0;
                move_file_individual(group, local_temp, local_dest, finfo.name);
            }
        } while (_findnexti64(ffhandle, &finfo) == 0);
        _findclose(ffhandle);
#else
        DIR *dir;
        struct dirent *de;

        if ((dir = opendir(local_temp)) == NULL) {
            gsyserror(group, "Failed to open directory %s", local_temp);
            return;
        }
        emptydir = 1;
        // errno needs to be set to 0 before calling readdir, otherwise
        // we'll report a false error when we exhaust the directory
        while ((errno = 0, de = readdir(dir)) != NULL) {
            if (strcmp(de->d_name, ".") && strcmp(de->d_name, "..")) {
                emptydir = 0;
                move_file_individual(group, local_temp, local_dest, de->d_name);
            }
        }
        if (errno && (errno != ENOENT)) {
            gsyserror(group, "Failed to read directory %s", tempdir);
        }
        closedir(dir);
#endif
    }
    if (emptydir) {
        run_postreceive(group, local_dest);
    }
    if (rmdir(local_temp) == -1) {
        gsyserror(group, "Failed remove temp directory %s", local_temp);
    }
}
Beispiel #4
0
/**
 * Save the state of a failed transfer so it can restarted later.
 */
void write_restart_file(struct group_list_t *group)
{
    struct file_t *fileinfo;
    struct client_restart_t restart;
    char restart_name[MAXPATHNAME];
    int fd;

    // Don't bother if we're not using a temp directory.
    if (!strcmp(tempdir, "")) {
        return;
    }

    glog2(group, "Writing restart file");
    memset(&restart, 0, sizeof(restart));
    fileinfo = &group->fileinfo;
    if (group->phase != PHASE_MIDGROUP) {
        restart.blocks = fileinfo->blocks;
        restart.sections = fileinfo->sections;
        restart.size = fileinfo->size;
        strncpy(restart.name, fileinfo->name, sizeof(restart.name));
        restart.name[sizeof(restart.name)-1] = '\x0';
    }

    snprintf(restart_name, sizeof(restart_name), "%s%c_group_%08X_restart",
             tempdir, PATH_SEP, group->group_id);
    if ((fd = open(restart_name, OPENWRITE | O_CREAT | O_TRUNC, 0644)) == -1) {
        gsyserror(group, "Failed to create restart file");
        return;
    }

    if (file_write(fd, &restart, sizeof(restart)) == -1) {
        glog0(group, "Failed to write header for restart file");
        goto errexit;
    }
    if (fileinfo->blocks && fileinfo->naklist) {
        if (file_write(fd, fileinfo->naklist, fileinfo->blocks) == -1) {
            glog0(group, "Failed to write NAK list for restart file");
            goto errexit;
        }
    }
    if (fileinfo->sections && fileinfo->section_done) {
        if (file_write(fd, fileinfo->section_done, fileinfo->sections) == -1) {
            glog0(group, "Failed to write section_done list for restart file");
            goto errexit;
        }
    }
    close(fd);
    return;

errexit:
    close(fd);
    unlink(restart_name);
}
Beispiel #5
0
/**
 * Perform FILEINFO processing specific to an empty directory
 */
void handle_fileinfo_dir(struct group_list_t *group, int found_dir)
{
    if (!found_dir && !group->sync_preview) {
        glog2(group, "Creating directory");
        if (mkdir(group->fileinfo.filepath, 0755) == -1) {
            gsyserror(group, "Failed to create directory %s",
                             group->fileinfo.filepath);
            early_complete(group, COMP_STAT_REJECTED, 0);
            return;
        }
    }
    early_complete(group, found_dir ? COMP_STAT_SKIPPED : COMP_STAT_NORMAL, 0);
}
Beispiel #6
0
/**
 * Perform FILEINFO processing specific to a symbolic link
 */
void handle_fileinfo_link(struct group_list_t *group)
{
#ifndef WINDOWS
    if (!group->sync_preview) {
        if (symlink(group->fileinfo.linkname, group->fileinfo.filepath) == -1) {
            gsyserror(group, "Failed to create symlink %s",
                             group->fileinfo.filepath);
            early_complete(group, COMP_STAT_REJECTED, 0);
            return;
        }
    }
#endif
    early_complete(group, COMP_STAT_NORMAL, 0);
}
Beispiel #7
0
/**
 * Process an incoming FILEINFO message.
 * Expected in the middle of a group with no current file.
 */
void handle_fileinfo(struct group_list_t *group, const unsigned char *message,
                     unsigned meslen, struct timeval rxtime)
{
    stat_struct statbuf;
    int found_dir;

    if (!read_fileinfo(group, message, meslen, rxtime)) {
        return;
    }

    glog2(group, "Name of file to receive: %s", group->fileinfo.name);
    switch (group->fileinfo.ftype) {
    case FTYPE_REG:
        glog2(group, "Bytes: %s, Blocks: %d, Sections: %d",
                     printll(group->fileinfo.size),
                     group->fileinfo.blocks, group->fileinfo.sections);
        glog3(group, "small section size: %d, "
                     "big section size: %d, # big sections: %d",
                     group->fileinfo.secsize_small, group->fileinfo.secsize_big,
                     group->fileinfo.big_sections);
        break;
    case FTYPE_DIR:
        glog2(group, "Empty directory");
        break;
    case FTYPE_LINK:
        glog2(group, "Symbolic link to %s", group->fileinfo.linkname);
        break;
    case FTYPE_DELETE:
        glog2(group, "Deleting file/directory");
        break;
    case FTYPE_FREESPACE:
        glog2(group, "Get free space for path");
        break;
    default:
        glog1(group, "Invalid file type: %d", group->fileinfo.ftype);
        send_abort(group, "Invalid file type");
        return;
    }

    if (!setup_dest_file(group)) {
        // A rejected file is still a success because we responded with a
        // COMPLETE with status=rejected instead of with an ABORT
        return;
    }

    // Make sure the path to the destination file exists and
    // remove or back up any existing file
    if (!create_path_to_file(group, group->fileinfo.filepath)) {
        glog0(group, "Error creating path to data file");
        early_complete(group, COMP_STAT_REJECTED, 0);
        return;
    }
    found_dir = 0;
    if (tempfile && !group->sync_preview) {
        clear_path(group->fileinfo.temppath, group);
    }
    if ((group->fileinfo.ftype != FTYPE_DELETE) ||
            (group->fileinfo.ftype != FTYPE_FREESPACE)) {
        // Don't do path checks for metafile commands
    } else if (lstat_func(group->fileinfo.filepath, &statbuf) != -1) {
        glog3(group, "checking existing file");
        if ((group->fileinfo.ftype != FTYPE_DIR) || !S_ISDIR(statbuf.st_mode)) {
            if ((group->fileinfo.ftype != FTYPE_REG) ||
                    !S_ISREG(statbuf.st_mode) ||
                    ((!group->restart) && (!group->sync_mode))) {
                // Don't clear/backup if we're receiving a regular file
                // and we're in either restart mode or sync mode
                glog3(group, "calling move_to_backup");
                if (!tempfile) {
                    move_to_backup(group);
                }
            }
        } else {
            glog3(group, "found dir");
            found_dir = 1;
        }
    } else if (errno != ENOENT) {
        gsyserror(group, "Error checking file %s",group->fileinfo.filepath);
    }

    switch (group->fileinfo.ftype) {
    case FTYPE_REG:
        handle_fileinfo_regular(group);
        break;
    case FTYPE_DIR:
        handle_fileinfo_dir(group, found_dir);
        break;
    case FTYPE_LINK:
        handle_fileinfo_link(group);
        break;
    case FTYPE_DELETE:
        handle_fileinfo_delete(group);
        break;
    case FTYPE_FREESPACE:
        handle_fileinfo_freespace(group);
        break;
    default:
        glog0(group, "Error handling FILEINFO: shouldn't get here!");
    }
}
Beispiel #8
0
/**
 * Perform FILEINFO processing specific to a regular file
 */
void handle_fileinfo_regular(struct group_list_t *group)
{
    // First handle restart or sync mode,
    // then create/open the file.
    if (group->restartinfo) {
        if (handle_fileinfo_restart(group)) {
            return;
        }
    } else if (group->sync_mode) {
        if (handle_fileinfo_sync(group)) {
            return;
        }
    }
    if (group->fileinfo.restart) {
        group->fileinfo.fd = open(group->fileinfo.filepath, OPENWRITE);
    } else {
        const char *filename;
        if (tempfile) {
            filename = group->fileinfo.temppath;
        } else {
            filename = group->fileinfo.filepath;
        }
#ifdef WINDOWS
        SetFileAttributes(filename, FILE_ATTRIBUTE_NORMAL);
#else
        chmod(filename, 0644);
#endif
        group->fileinfo.fd = open(filename, OPENWRITE | O_CREAT | O_TRUNC,0644);
    }
    if (group->fileinfo.fd == -1) {
        gsyserror(group, "Error opening data file");
        early_complete(group, COMP_STAT_REJECTED, 0);
        return;
    }
    if (group->fileinfo.size > free_space(group->fileinfo.filepath)) {
        glog0(group, "Not enough disk space, aborting");
        send_abort(group, "Not enough disk space");
        return;
    }

    // Final preparations for receiving a file.
    if (group->fileinfo.restart) {
        group->fileinfo.naklist = group->restartinfo->naklist;
        group->fileinfo.section_done = group->restartinfo->section_done;
        group->restartinfo->naklist = NULL;
        group->restartinfo->section_done = NULL;
        free(group->restartinfo);
        group->restartinfo = NULL;
    } else {
        group->fileinfo.naklist = safe_calloc(group->fileinfo.blocks, 1);
        group->fileinfo.section_done = safe_calloc(group->fileinfo.sections, 1);
        memset(group->fileinfo.naklist, 1, group->fileinfo.blocks);
    }
    group->fileinfo.last_block = -1;
    group->fileinfo.last_section = 0;
    group->fileinfo.curr_offset = 0;
    group->fileinfo.cache_start = 0;
    group->fileinfo.cache_end = 0;
    group->fileinfo.cache_len = 0;
    group->fileinfo.cache = safe_calloc(cache_len, 1);
    group->fileinfo.cache_status = safe_calloc(cache_len / group->blocksize, 1);
    group->phase = PHASE_RECEIVING;
    send_fileinfo_ack(group, group->fileinfo.restart);
    set_timeout(group, 0);
}
Beispiel #9
0
/**
 * Move all files from temp to destination directory if at end of group
 */
void move_files(struct group_list_t *group)
{
    char temppath[MAXPATHNAME], destpath[MAXPATHNAME];
    char *filelist[10000];  // TODO: no magic number
    int len, filecount, i;

    if (!strcmp(tempdir, "") || (group->file_id != 0)) {
        return;
    }
    if (move_individual) {
        len = snprintf(temppath, sizeof(temppath), "%s%c_group_%08X",
                       tempdir, PATH_SEP, group->group_id);
        if ((len >= sizeof(temppath)) || (len == -1)) {
            glog0(group, "Max pathname length exceeded: %s%c_group_%08X",
                         tempdir, PATH_SEP, group->group_id);
        } else {
            move_files_individual(group, temppath, destdir[0]);
        }
        return;
    }

    {
#ifdef WINDOWS
        intptr_t ffhandle;
        struct _finddatai64_t finfo;
        char dirglob[MAXPATHNAME];

        snprintf(dirglob, sizeof(dirglob), "%s%c_group_%08X%c*", tempdir,
                 PATH_SEP, group->group_id, PATH_SEP);
        if ((ffhandle = _findfirsti64(dirglob, &finfo)) == -1) {
            gsyserror(group, "Failed to open directory %s", dirglob);
            return;
        }
        filecount = 0;
        do {
            len = snprintf(temppath, sizeof(temppath), "%s%c_group_%08X%c%s",
                           tempdir, PATH_SEP, group->group_id,
                           PATH_SEP, finfo.name);
            if ((len >= sizeof(temppath)) || (len == -1)) {
                glog0(group,"Max pathname length exceeded: %s%c_group_%08X%c%s",
                      tempdir, PATH_SEP, group->group_id, PATH_SEP, finfo.name);
                continue;
            }
            len = snprintf(destpath, sizeof(destpath), "%s%c%s",
                           destdir[0], PATH_SEP, finfo.name);
            if ((len >= sizeof(destpath)) || (len == -1)) {
                glog0(group, "Max pathname length exceeded: %s%c%s",
                             destdir[0], PATH_SEP, finfo.name);
                continue;
            }
            // do the move
            if (strcmp(finfo.name, ".") && strcmp(finfo.name, "..")) {
                clear_path(destpath, group);
                if (!MoveFile(temppath, destpath)) {
                    char errbuf[300];
                    FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL,
                            GetLastError(), 0, errbuf, sizeof(errbuf), NULL);
                    glog0(group, "error (%d): %s", GetLastError(), errbuf);
                }
                filelist[filecount] = strdup(destpath);
                if (filelist[filecount] == NULL) {
                    gsyserror(group, "strdup failed!");
                    exit(ERR_ALLOC);
                }
                filecount++;
            }
        } while (_findnexti64(ffhandle, &finfo) == 0);
        _findclose(ffhandle);
#else
        DIR *dir;
        struct dirent *de;
        char dirname[MAXPATHNAME];

        snprintf(dirname, sizeof(dirname), "%s%c_group_%08X", tempdir,
                 PATH_SEP, group->group_id);
        if ((dir = opendir(dirname)) == NULL) {
            gsyserror(group, "Failed to open directory %s", dirname);
            return;
        }
        filecount = 0;
        // errno needs to be set to 0 before calling readdir, otherwise
        // we'll report a false error when we exhaust the directory
        while ((errno = 0, de = readdir(dir)) != NULL) {
            len = snprintf(temppath, sizeof(temppath), "%s%c%s", dirname,
                           PATH_SEP, de->d_name);
            if ((len >= sizeof(temppath)) || (len == -1)) {
                glog0(group, "Max pathname length exceeded: %s%c%s", dirname,
                             PATH_SEP, de->d_name);
                continue;
            }
            len = snprintf(destpath, sizeof(destpath), "%s%c%s", destdir[0],
                           PATH_SEP, de->d_name);
            if ((len >= sizeof(destpath)) || (len == -1)) {
                glog0(group, "Max pathname length exceeded: %s%c%s", destdir[0],
                             PATH_SEP, de->d_name);
                continue;
            }
            if (strcmp(de->d_name, ".") && strcmp(de->d_name, "..")) {
                clear_path(destpath, group);
                if (rename(temppath, destpath) == -1) {
                    gsyserror(group, "Couldn't move file");
                }
                filelist[filecount] = strdup(destpath);
                if (filelist[filecount] == NULL) {
                    gsyserror(group, "strdup failed!");
                    exit(ERR_ALLOC);
                }
                filecount++;
            }
        }
        if (errno && (errno != ENOENT)) {
            gsyserror(group, "Failed to read directory %s", dirname);
        }
        closedir(dir);
#endif
    }
    run_postreceive_multi(group, filelist, filecount);
    for (i = 0; i < filecount; i++) {
        free(filelist[i]);
    }
    snprintf(temppath, sizeof(temppath), "%s%c_group_%08X", tempdir,
             PATH_SEP, group->group_id);
    if (rmdir(temppath) == -1) {
        gsyserror(group, "Failed remove temp directory %s", temppath);
    }
}
Beispiel #10
0
/**
 * Creates all directories in the given file's path, removing existing files.
 * Returns 1 on success, 0 on failure
 */
int create_path_to_file(struct group_list_t *group, const char *filename)
{
    char *dir, *base;
    stat_struct statbuf;
    int rval;

    split_path(filename, &dir, &base);
    if (!dir) {
        glog1(group, "Invalid path element %s", filename);
        rval = 0;
        goto end;
    }
#ifdef WINDOWS
    if ((base == NULL) || ((strlen(dir) == 2) && (dir[1] == ':'))) {
#else
    if ((!strcmp(dir, ".")) || (!strcmp(dir, "/"))) {
#endif
        // At top level directory, so stop recursion
        rval = 1;
        goto end;
    }

    if (lstat_func(dir, &statbuf) != -1) {
        if (!S_ISDIR(statbuf.st_mode)) {
            if (unlink(dir) == -1) {
                gsyserror(group, "Failed to delete path element %s", dir);
                rval = 0;
                goto end;
            }
            if (mkdir(dir, 0755) == -1) {
                gsyserror(group, "Failed to create path element %s", dir);
                rval = 0;
                goto end;
            }
        }
    } else {
        // If the file's directory does not exist, recurse first to make sure
        // all parent directories exist
        if (!create_path_to_file(group, dir)) {
            rval = 0;
            goto end;
        }
        if (mkdir(dir, 0755) == -1) {
            gsyserror(group, "Failed to create path element %s", dir);
            rval = 0;
            goto end;
        }
    }

    rval = 1;

end:
    free(dir);
    free(base);
    return rval;
}

void new_loss_event(struct group_list_t *group, uint16_t txseq)
{
    uint32_t seq_long;
    uint16_t count;
    int bytes, avgbytes, rate, grtt_usec;

    glog4(group, "Seq %d starts new loss event", txseq);
    // Found a new loss event
    if (txseq < group->max_txseq - MAXMISORDER) {
        glog5(group, "wrap check, i=%u, maxseq=%u", txseq, group->max_txseq);
        seq_long = ((group->seq_wrap - 1) << 16) | txseq;
    } else {
        seq_long = (group->seq_wrap << 16) | txseq;
    }
    if (group->slowstart) {
        group->slowstart = 0;
        // Initialize loss history 
        count = group->max_txseq;
        bytes = 0;
        grtt_usec = (int)(group->grtt * 1000000);
        while ((count != group->start_txseq) &&
                (diff_usec(group->loss_history[txseq].t,
                   group->loss_history[count].t) < grtt_usec)) {
            bytes += group->loss_history[count--].size;
        }
        rate = (int)(bytes / group->grtt);
        glog4(group, "End slowstart, calculated rate = %d", rate);
        avgbytes= bytes / ((int16_t)(group->max_txseq - count));
        group->loss_events[0].len = (int)(0 + pow(
                (rate * ((group->rtt != 0) ? group->rtt : group->grtt)) / 
                (sqrt(1.5) * 8 * avgbytes), 2));
        glog4(group, "Calculated prior event len = %d (rtt=%f, avgbytes=%d)",
                     group->loss_events[0].len, group->rtt,avgbytes);
    } else {
        group->loss_events[0].len = seq_long - group->loss_events[0].start_seq;
        glog4(group, "Prior event length = %d (i=%u, start=%u)",
                     group->loss_events[0].len,
                     seq_long, group->loss_events[0].start_seq);
    }
    memmove(&group->loss_events[1], &group->loss_events[0],
            sizeof(struct loss_event_t) * 8);
    group->loss_events[0].start_seq = seq_long;
    group->loss_events[0].len = 0;
    group->loss_events[0].t = group->loss_history[txseq].t;
}
Beispiel #11
0
/**
 * For the current file in a group, move the existing file to
 * the appropriate backup directory, if it exists.
 * In the event of a failure, delete the original file
 */
void move_to_backup(struct group_list_t *group)
{
    stat_struct statbuf;
    char backup_file[MAXBACKUPPATHNAME], *trim_name;
    int len;

    if (lstat_func(group->fileinfo.filepath, &statbuf) == -1) {
        return;
    }

    if (backupcnt == 0) {
        clear_path(group->fileinfo.filepath, group);
        return;
    }

#ifdef WINDOWS
    if ((group->fileinfo.filepath[1] == ':') &&
            (group->fileinfo.filepath[2] == '\\')) {
        trim_name = &group->fileinfo.filepath[3];
    } else {
        trim_name = group->fileinfo.filepath;
    }
#else
    trim_name = group->fileinfo.filepath;
#endif
    len = snprintf(backup_file, sizeof(backup_file), "%s%c%s%c%s%c%s",
                   backupdir[group->fileinfo.destdiridx], PATH_SEP,
                   group->start_date, PATH_SEP,
                   group->start_time, PATH_SEP, trim_name);
    if (len >= sizeof(backup_file)) {
        glog0(group, "Max pathname length exceeded for backup file, deleting",
                     group->fileinfo.filepath);
        clear_path(group->fileinfo.filepath, group);
        return;
    }
    clear_path(backup_file, group);
    if (!create_path_to_file(group, backup_file)) {
        glog0(group, "Error creating path to backup file");
        clear_path(group->fileinfo.filepath, group);
    }
#ifdef WINDOWS
    if (!MoveFile(group->fileinfo.filepath, backup_file)) {
        char errbuf[300];
        FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL,
                GetLastError(), 0, errbuf, sizeof(errbuf), NULL);
        glog0(group, "Couldn't rename from %s to %s, deleting: (%d): %s",
                group->fileinfo.filepath, backup_file, GetLastError(), errbuf);
        clear_path(group->fileinfo.filepath, group);
    } else {
        glog2(group, "Backed up existing file to %s", backup_file);
    }
#else
    if (rename(group->fileinfo.filepath, backup_file) == -1) {
        gsyserror(group, "Couldn't rename from %s to %s, deleting",
                         group->fileinfo.filepath, backup_file);
        clear_path(group->fileinfo.filepath, group);
    } else {
        glog2(group, "Backed up existing file to %s", backup_file);
    }
#endif
}
Beispiel #12
0
/**
 * Removes a full path from disk
 */
void clear_path(const char *path, struct group_list_t *group)
{
    stat_struct statbuf;
    char filename[MAXPATHNAME];
    int len;

    if (lstat_func(path, &statbuf) == -1) {
        if (errno != ENOENT) {
            gsyserror(group, "Error getting file status for %s", path);
        }
        return;
    }
    if (!S_ISDIR(statbuf.st_mode)) {
        unlink(path);
    } else {
#ifdef WINDOWS
        intptr_t ffhandle;
        struct _finddatai64_t finfo;
        char dirglob[MAXPATHNAME];

        snprintf(dirglob, sizeof(dirglob), "%s%c*", path,
                 PATH_SEP, group->group_id, PATH_SEP);
        if ((ffhandle = _findfirsti64(dirglob, &finfo)) == -1) {
            gsyserror(group, "Failed to open directory %s", path);
            return;
        }
        do {
            len = snprintf(filename, sizeof(filename), "%s%c%s", path,
                           PATH_SEP, finfo.name);
            if ((len >= sizeof(filename)) || (len == -1)) {
                glog0(group, "Max pathname length exceeded: %s%c%s",
                             filename, PATH_SEP, finfo.name);
                continue;
            }
            if (strcmp(finfo.name, ".") && strcmp(finfo.name, "..")) {
                clear_path(filename, group);
            }
        } while (_findnexti64(ffhandle, &finfo) == 0);
        _findclose(ffhandle);
#else
        DIR *dir;
        struct dirent *de;

        if ((dir = opendir(path)) == NULL) {
            gsyserror(group, "Failed to open directory %s", path);
            return;
        }
        // errno needs to be set to 0 before calling readdir, otherwise
        // we'll report a false error when we exhaust the directory
        while ((errno = 0, de = readdir(dir)) != NULL) {
            len = snprintf(filename, sizeof(filename), "%s%c%s", path, PATH_SEP,
                           de->d_name);
            if ((len >= sizeof(filename)) || (len == -1)) {
                glog0(group, "Max pathname length exceeded: %s%c%s",
                             path, PATH_SEP, de->d_name);
                continue;
            }
            if (strcmp(de->d_name, ".") && strcmp(de->d_name, "..")) {
                clear_path(filename, group);
            }
        }
        if (errno && (errno != ENOENT)) {
            gsyserror(group, "Failed to read directory %s", path);
        }
        closedir(dir);
#endif
        if (rmdir(path) == -1) {
            gsyserror(group, "Failed remove directory %s", path);
        }
    }
}
Beispiel #13
0
/**
 * Clean up a group list entry.  Close the file if open,
 * free malloc'ed structures, drop the multicast group
 * (if no one else is using it) and free the slot.
 */
void file_cleanup(struct group_list_t *group, int abort_session)
{
    if (group->fileinfo.fd >= 0) {
        glog2(group, "starting file close");
        close(group->fileinfo.fd);
        glog2(group, "done file close");
        group->fileinfo.fd = -1;
        if (abort_session && !strcmp(tempdir, "")) {
            if (tempfile) {
                unlink(group->fileinfo.temppath);
            } else {
                unlink(group->fileinfo.filepath);
            }
        } else {
            if (tempfile) {
                move_to_backup(group);
                if (rename(group->fileinfo.temppath,
                           group->fileinfo.filepath) == -1) {
                    gsyserror(group, "Couldn't rename from %s to %s",
                             group->fileinfo.temppath,group->fileinfo.filepath);
                }
            }
            if (group->fileinfo.tstamp) {
                utim_buf utbuf;
                utbuf.actime = group->fileinfo.tstamp;
                utbuf.modtime = group->fileinfo.tstamp;
                if (utime(group->fileinfo.filepath, &utbuf) == -1) {
                    gsyserror(group, "utime failed");
                }
            }
        }
    }

    if (abort_session || (group->file_id == 0)) {
        if (!addr_blank(&group->multi) && !other_mcast_users(group) &&
                group->multi_join) {
            if (server_count > 0) {
                multicast_leave(listener, group->group_id, &group->multi,
                        m_interface, interface_count, server_keys,server_count);
                if (has_proxy) {
                    multicast_leave(listener, group->group_id, &group->multi,
                            m_interface, interface_count, &proxy_info, 1);
                }
            } else {
                multicast_leave(listener, group->group_id, &group->multi,
                        m_interface, interface_count, NULL, 0);
            }
        }
        if (group->server_pubkey.key) {
            if (group->keyextype == KEYEX_ECDH_ECDSA) {
                free_EC_key(group->server_pubkey.ec);
            } else {
                free_RSA_key(group->server_pubkey.rsa);
            }
        }
        if (group->server_dhkey.key) {
            free_EC_key(group->server_dhkey.ec);
            free_EC_key(group->client_dhkey.ec);
        }
        if (group->restartinfo &&
                (strcmp(group->restartinfo->name, ""))) {
            // We have unused restart info from the last run.
            // Chalk this up as a loss and delete the data file
            char filepath[MAXPATHNAME];
            snprintf(filepath, sizeof(filepath), "%s%c_group_%08X%c%s", tempdir,
                     PATH_SEP, group->group_id, PATH_SEP,
                     group->restartinfo->name);
            unlink(filepath);
        }
        if (abort_session) {
            write_restart_file(group);
        }

        free(group->loss_history);
        free(group->fileinfo.naklist);
        free(group->fileinfo.section_done);
        free(group->fileinfo.cache);
        free(group->fileinfo.cache_status);
        if (group->restartinfo) {
            free(group->restartinfo->naklist);
            free(group->restartinfo->section_done);
            free(group->restartinfo);
        }
        memset(group, 0, sizeof(struct group_list_t));
    } else {
        // Don't clear the file_id in case we need to respond to late DONEs
        if (!strcmp(tempdir, "")) {
            run_postreceive(group, group->fileinfo.filepath);
        }
        group->phase = PHASE_MIDGROUP;
        set_timeout(group, 0);
        free(group->fileinfo.naklist);
        free(group->fileinfo.section_done);
        free(group->fileinfo.cache);
        free(group->fileinfo.cache_status);
        group->fileinfo.naklist = NULL;
        group->fileinfo.section_done = NULL;
        group->fileinfo.cache = NULL;
        group->fileinfo.cache_status = NULL;
    }
}
Beispiel #14
0
/**
 * Run the postreceive script on list of received files
 */
void run_postreceive_multi(struct group_list_t *group, char *const *files,
                           int count)
{
    char **params;
    char gid_str[10];
    char gid_param[] = "-I";
    int i;

    if (!strcmp(postreceive, "")) {
        return;
    }

    params = safe_calloc(count + 4, sizeof(char *));

    snprintf(gid_str, sizeof(gid_str), "%08X", group->group_id);

    params[0] = postreceive;
    params[1] = gid_param;
    params[2] = gid_str;
    for (i = 0; i < count; i++) {
        params[i+3] = files[i];
    }
    params[count+4-1] = NULL;

    if (log_level >= 2) {
        cglog2(group, "Running postreceive: %s", postreceive);
        for (i = 1; i < count + 3; i++) {
            sclog2(" %s", params[i]);
        }
        slog2("");
    }

#ifdef WINDOWS
    {
        char cmdline[0x8000];  // Windows max command line length
        char cmdexe[MAXPATHNAME];
        int too_long, rval, is_cmd;

        strcpy(cmdline, "");
        if ((!strncmp(&postreceive[strlen(postreceive)-4], ".cmd", 4)) ||
                (!strncmp(&postreceive[strlen(postreceive)-4], ".bat", 4))) {
            is_cmd = 1;
            if (!GetEnvironmentVariable("SystemRoot", cmdexe, sizeof(cmdexe))) {
                char errbuf[300];
                FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, GetLastError(),
                              0, errbuf, sizeof(errbuf), NULL);
                glog0(group, "Error getting sysroot: (%d) %s",
                             GetLastError(), errbuf);
                free(params);
                return;
            }
            strcat(cmdexe, "\\system32\\cmd.exe");
            strcat(cmdline, "/c \"");
        } else {
            is_cmd = 0;
        }
        for (too_long = 0, i = 0; i < count + 3; i++) {
            int size = 0x8000 - strlen(cmdline);
            if (size <= (int)strlen(params[i]) + 4) {
                too_long = 1;
                break;
            }
            // Quote everything except -I {group_id}
            if (i == 1 || i == 2) {
                strcat(cmdline, params[i]);
                strcat(cmdline," ");
            } else {
                strcat(cmdline, "\"");
                strcat(cmdline, params[i]);
                strcat(cmdline,"\" ");
            }
        }
        if (is_cmd) {
            strcat(cmdline, "\"");
        }

        if (!too_long) {
            STARTUPINFO startup_info;
            PROCESS_INFORMATION proc_info;

            GetStartupInfo(&startup_info);
            rval = CreateProcess(is_cmd ? cmdexe : postreceive, cmdline,
                NULL, NULL, 0, CREATE_NO_WINDOW, NULL, NULL,
                &startup_info, &proc_info);
            if (!rval) {
                char errbuf[300];
                FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, GetLastError(),
                              0, errbuf, sizeof(errbuf), NULL);
                glog0(group, "Error running script: (%d) %s",
                             GetLastError(), errbuf);
            }
        }
    }
#else
    {
        pid_t pid;
        if ((pid = fork()) == -1) {
            gsyserror(group, "fork failed");
        } else if (pid == 0) {
            close(listener);
            close(1);
            close(2);
            execv(postreceive, params);
            gsyserror(group, "exec failed");
            exit(1);
        }
    }
#endif

    free(params);
}
Beispiel #15
0
/**
 * Reads in the contents of the restart file.
 */
void read_restart_file(struct group_list_t *group)
{
    struct client_restart_t *restart;
    char restart_name[MAXPATHNAME];
    int fd, i, rval;

    // Don't bother if we're not using a temp directory.
    if (!strcmp(tempdir, "")) {
        return;
    }

    // First abort any prior session with the same group_id.
    // This creates the restart file.
    for (i = 0; i < MAXLIST; i++) {
        if ((group_list[i].group_id == group->group_id) &&
                (group_list[i].group_inst < group->group_inst)) {
            file_cleanup(&group_list[i], 1);
        }
    }

    glog2(group, "Reading restart file");
    snprintf(restart_name, sizeof(restart_name), "%s%c_group_%08X_restart",
             tempdir, PATH_SEP, group->group_id);
    if ((fd = open(restart_name, OPENREAD, 0644)) == -1) {
        gsyserror(group, "Failed to read restart file");
        return;
    }

    // Read header
    restart = safe_calloc(sizeof(struct client_restart_t), 1);
    if ((rval = file_read(fd, restart, sizeof(struct client_restart_t),
                          0)) == -1) {
        glog0(group, "Failed to read header for restart file");
        goto err1;
    }
    if (rval != sizeof(struct client_restart_t)) {
        glog0(group, "Failed to read header for restart file "
                "(read %d, expected %d)", rval,sizeof(struct client_restart_t));
        goto err1;
    }

    // Read NAK list
    if (restart->blocks) {
        restart->naklist = safe_calloc(restart->blocks, 1);
        if (file_read(fd, restart->naklist, restart->blocks, 0) == -1) {
            glog0(group, "Failed to read NAK list for restart file");
            goto err2;
        }
    }

    // Read section_done list
    if (restart->sections) {
        restart->section_done = safe_calloc(restart->sections, 1);
        if (file_read(fd, restart->section_done, restart->sections, 0) == -1) {
            glog0(group, "Failed to read section_done list for restart file");
            goto err3;
        }
    }
    close(fd);
    unlink(restart_name);
    group->restartinfo = restart;
    glog3(group, "Reading restart file done");
    return;

err3:
    free(restart->section_done);
err2:
    free(restart->naklist);
err1:
    free(restart);
    close(fd);
}