Example #1
0
/* TODO: condionally set setuid and setgid bits? */
void DCOPY_copy_permissions(
    const struct stat64* statbuf,
    const char* dest_path)
{
    /* change mode */
    if(! S_ISLNK(statbuf->st_mode)) {
        if(mfu_chmod(dest_path, statbuf->st_mode) != 0) {
            MFU_LOG(MFU_LOG_ERR, "Failed to change permissions on %s chmod() errno=%d %s",
                dest_path, errno, strerror(errno)
               );
        }
    }

    return;
}
Example #2
0
/** Callback given to process the dataset. */
static void walk_stat_process(CIRCLE_handle* handle)
{
    /* get path from queue */
    char path[CIRCLE_MAX_STRING_LEN];
    handle->dequeue(path);

    /* stat item */
    struct stat st;
    int status = mfu_lstat(path, &st);
    if (status != 0) {
        /* print error */
        return;
    }

    /* increment our item count */
    reduce_items++;

    /* TODO: filter items by stat info */

    if (REMOVE_FILES && !S_ISDIR(st.st_mode)) {
        mfu_unlink(path);
    } else {
        /* record info for item in list */
        mfu_flist_insert_stat(CURRENT_LIST, path, st.st_mode, &st);
    }

    /* recurse into directory */
    if (S_ISDIR(st.st_mode)) {
        /* before more processing check if SET_DIR_PERMS is set,
         * and set usr read and execute bits if need be */
        if (SET_DIR_PERMS) {
            /* use masks to check if usr_r and usr_x are already on */
            long usr_r_mask = 1 << 8;
            long usr_x_mask = 1 << 6;
            /* turn on the usr read & execute bits if they are not already on*/
            if (!((usr_r_mask & st.st_mode) && (usr_x_mask & st.st_mode))) {
                st.st_mode |= S_IRUSR;
                st.st_mode |= S_IXUSR;
                mfu_chmod(path, st.st_mode);
            }
        }
        /* TODO: check that we can recurse into directory */
        walk_stat_process_dir(path, handle);
    }

    return;
}
Example #3
0
/* TODO: condionally set setuid and setgid bits? */
void DCOPY_copy_permissions(
    mfu_flist flist,
    uint64_t idx,
    const char* dest_path)
{
    /* get mode and type */
    mfu_filetype type = mfu_flist_file_get_type(flist, idx);
    mode_t mode = (mode_t) mfu_flist_file_get_mode(flist, idx);

    /* change mode */
    if(type != MFU_TYPE_LINK) {
        if(mfu_chmod(dest_path, mode) != 0) {
            MFU_LOG(MFU_LOG_ERR, "Failed to change permissions on %s chmod() errno=%d %s",
                dest_path, errno, strerror(errno)
               );
        }
    }

    return;
}
Example #4
0
static void walk_readdir_process_dir(const char* dir, CIRCLE_handle* handle)
{
    /* TODO: may need to try these functions multiple times */
    DIR* dirp = mfu_opendir(dir);

    /* if there is a permissions error and the usr read & execute are being turned
     * on when walk_stat=0 then catch the permissions error and turn the bits on */
    if (dirp == NULL) {
        if (errno == EACCES && SET_DIR_PERMS) {
            struct stat st;
            mfu_lstat(dir, &st);
            // turn on the usr read & execute bits
            st.st_mode |= S_IRUSR;
            st.st_mode |= S_IXUSR;
            mfu_chmod(dir, st.st_mode);
            dirp = mfu_opendir(dir);
            if (dirp == NULL) {
                if (errno == EACCES) {
                    MFU_LOG(MFU_LOG_ERR, "Failed to open directory with opendir: `%s' (errno=%d %s)", dir, errno, strerror(errno));
                }
            }
        }
    }

    if (! dirp) {
        /* TODO: print error */
    }
    else {
        /* Read all directory entries */
        while (1) {
            /* read next directory entry */
            struct dirent* entry = mfu_readdir(dirp);
            if (entry == NULL) {
                break;
            }

            /* process component, unless it's "." or ".." */
            char* name = entry->d_name;
            if ((strncmp(name, ".", 2)) && (strncmp(name, "..", 3))) {
                /* <dir> + '/' + <name> + '/0' */
                char newpath[CIRCLE_MAX_STRING_LEN];
                size_t len = strlen(dir) + 1 + strlen(name) + 1;
                if (len < sizeof(newpath)) {
                    /* build full path to item */
                    strcpy(newpath, dir);
                    strcat(newpath, "/");
                    strcat(newpath, name);

#ifdef _DIRENT_HAVE_D_TYPE
                    /* record info for item */
                    mode_t mode;
                    int have_mode = 0;
                    if (entry->d_type != DT_UNKNOWN) {
                        /* unlink files here if remove option is on,
                         * and dtype is known without a stat */
                        if (REMOVE_FILES && (entry->d_type != DT_DIR)) {
                            mfu_unlink(newpath);
                        } else {
                            /* we can read object type from directory entry */
                            have_mode = 1;
                            mode = DTTOIF(entry->d_type);
                            mfu_flist_insert_stat(CURRENT_LIST, newpath, mode, NULL);
                        }
                    }
                    else {
                        /* type is unknown, we need to stat it */
                        struct stat st;
                        int status = mfu_lstat(newpath, &st);
                        if (status == 0) {
                            have_mode = 1;
                            mode = st.st_mode;
                            /* unlink files here if remove option is on,
                             * and stat was necessary to get type */
                            if (REMOVE_FILES && !S_ISDIR(st.st_mode)) {
                                mfu_unlink(newpath);
                            } else {
                                mfu_flist_insert_stat(CURRENT_LIST, newpath, mode, &st);
                            }
                        }
                        else {
                            /* error */
                        }
                    }

                    /* increment our item count */
                    reduce_items++;

                    /* recurse into directories */
                    if (have_mode && S_ISDIR(mode)) {
                        handle->enqueue(newpath);
                    }
#endif
                }
                else {
                    /* TODO: print error in correct format */
                    /* name is too long */
                    MFU_LOG(MFU_LOG_ERR, "Path name is too long: %lu chars exceeds limit %lu", len, sizeof(newpath));
                }
            }
        }
    }

    mfu_closedir(dirp);

    return;
}
Example #5
0
int main(int argc, char* argv[])
{
    MPI_Init(&argc, &argv);
    mfu_init();

    /* get our rank and number of ranks in the job */
    int rank, ranks;
    MPI_Comm_rank(MPI_COMM_WORLD, &rank);
    MPI_Comm_size(MPI_COMM_WORLD, &ranks);

    /* pointer to mfu_walk_opts */
    mfu_walk_opts_t* walk_opts = mfu_walk_opts_new();

    uint64_t idx;
    int option_index = 0;
    int usage = 0;
    int report = 0;
    unsigned int numpaths = 0;
    mfu_param_path* paths = NULL;
    unsigned long long bytes;

    /* verbose by default */
    mfu_debug_level = MFU_LOG_VERBOSE;

    /* default to 1MB stripe size, stripe across all OSTs, and all files are candidates */
    int stripes = -1;
    uint64_t stripe_size = 1048576;
    uint64_t min_size = 0;

    static struct option long_options[] = {
        {"count",    1, 0, 'c'},
        {"size",     1, 0, 's'},
        {"minsize",  1, 0, 'm'},
        {"report",   0, 0, 'r'},
        {"progress", 1, 0, 'P'},
        {"verbose",  0, 0, 'v'},
        {"quiet",    0, 0, 'q'},
        {"help",     0, 0, 'h'},
        {0, 0, 0, 0}
    };

    while (1) {
        int c = getopt_long(argc, argv, "c:s:m:rvqh",
                    long_options, &option_index);

        if (c == -1) {
            break;
        }

        switch (c) {
            case 'c':
                /* stripe count */
                stripes = atoi(optarg);
                break;
            case 's':
                /* stripe size in bytes */
                if (mfu_abtoull(optarg, &bytes) != MFU_SUCCESS) {
                    if (rank == 0) {
                        MFU_LOG(MFU_LOG_ERR, "Failed to parse stripe size: %s", optarg);
                    }
                    MPI_Abort(MPI_COMM_WORLD, 1);
                }
                stripe_size = (uint64_t)bytes;
                break;
            case 'm':
                /* min file size in bytes */
                if (mfu_abtoull(optarg, &bytes) != MFU_SUCCESS) {
                    if (rank == 0) {
                        MFU_LOG(MFU_LOG_ERR, "Failed to parse minimum file size: %s", optarg);
                    }
                    MPI_Abort(MPI_COMM_WORLD, 1);
                }
                min_size = (uint64_t)bytes;
                break;
            case 'r':
                /* report striping info */
		report = 1;
                break;
            case 'P':
                mfu_progress_timeout = atoi(optarg);
                break;
            case 'v':
                mfu_debug_level = MFU_LOG_VERBOSE;
                break;
            case 'q':
                mfu_debug_level = MFU_LOG_NONE;
                break;
            case 'h':
                /* display usage */
                usage = 1;
                break;
            case '?':
                /* display usage */
                usage = 1;
                break;
            default:
                if (rank == 0) {
                    printf("?? getopt returned character code 0%o ??\n", c);
                }
        }
    }

    /* check that we got a valid progress value */
    if (mfu_progress_timeout < 0) {
        if (rank == 0) {
            MFU_LOG(MFU_LOG_ERR, "Seconds in --progress must be non-negative: %d invalid", mfu_progress_timeout);
        }
        usage = 1;
    }

    /* paths to walk come after the options */
    if (optind < argc) {
        /* determine number of paths specified by user */
        numpaths = argc - optind;

        /* allocate space for each path */
        paths = (mfu_param_path*) MFU_MALLOC((size_t)numpaths * sizeof(mfu_param_path));

        /* process each path */
        char** p = &argv[optind];
        mfu_param_path_set_all((uint64_t)numpaths, (const char**)p, paths);
        optind += numpaths;
    } else {
        usage = 1;
    }

    /* if we need to print usage, print it and exit */
    if (usage) {
        if (rank == 0) {
            print_usage();
        }

        mfu_finalize();
        MPI_Finalize();
        return 1;
    }

    /* nothing to do if lustre support is disabled */
#ifndef LUSTRE_SUPPORT
    if (rank == 0) {
        MFU_LOG(MFU_LOG_ERR, "Lustre support is disabled.");
    }
    MPI_Abort(MPI_COMM_WORLD, 1);
#endif

    /* stripe count must be -1 for all available or greater than 0 */
    if (stripes < -1) {
        if (rank == 0) {
            MFU_LOG(MFU_LOG_ERR, "Stripe count must be -1 for all servers, 0 for lustre file system default, or a positive value");
        }
        MPI_Abort(MPI_COMM_WORLD, 1);
    }

    /* lustre requires stripe sizes to be aligned */
    if (stripe_size > 0 && stripe_size % 65536 != 0) {
        if (rank == 0) {
            MFU_LOG(MFU_LOG_ERR, "Stripe size must be a multiple of 65536");
        }
        MPI_Abort(MPI_COMM_WORLD, 1);
    }

    /* TODO: verify that source / target are on Lustre */

    /* walk list of input paths and stat as we walk */
    mfu_flist flist = mfu_flist_new();
    mfu_flist_walk_param_paths(numpaths, paths, walk_opts, flist);

    /* filter down our list to files which don't meet our striping requirements */
    mfu_flist filtered = filter_list(flist, stripes, stripe_size, min_size, &create_prog_count_total, &stripe_prog_bytes_total);
    mfu_flist_free(&flist);

    MPI_Barrier(MPI_COMM_WORLD);

    /* report the file size and stripe count of all files we found */
    if (report) {
        /* report the files in our filtered list */
        stripe_info_report(filtered);

        /* free the paths and our list */
        mfu_flist_free(&filtered);
        mfu_param_path_free_all(numpaths, paths);
        mfu_free(&paths);

        /* finalize */
        mfu_finalize();
        MPI_Finalize();
        return 0;
    }

    /* generate a global suffix for our temp files and have each node check it's list */
    char suffix[8];
    uint64_t retry;

    /* seed our random number generator */
    srand(time(NULL));

    /* keep trying to make a valid random suffix...*/
    do {
        uint64_t attempt = 0;

        /* make rank 0 responsible for generating a random suffix */
        if (rank == 0) {
            generate_suffix(suffix, sizeof(suffix));
        }

        /* broadcast the random suffix to all ranks */
        MPI_Bcast(suffix, sizeof(suffix), MPI_CHAR, 0, MPI_COMM_WORLD);

        /* check that the file doesn't already exist */
        uint64_t size = mfu_flist_size(filtered);
        for (idx = 0; idx < size; idx++) {
            char temp_path[PATH_MAX];
            strcpy(temp_path, mfu_flist_file_get_name(filtered, idx));
            strcat(temp_path, suffix);
            if(!mfu_access(temp_path, F_OK)) {
                /* the file already exists */
                attempt = 1;
                break;
            }
        }

        /* do a reduce to figure out if a rank has a file collision */
        MPI_Allreduce(&attempt, &retry, 1, MPI_UINT64_T, MPI_MAX, MPI_COMM_WORLD);
    } while(retry != 0);

    /* initialize progress messages while creating files */
    create_prog_count = 0;
    create_prog = mfu_progress_start(mfu_progress_timeout, 1, MPI_COMM_WORLD, create_progress_fn);

    /* create new files so we can restripe */
    uint64_t size = mfu_flist_size(filtered);
    for (idx = 0; idx < size; idx++) {
        char temp_path[PATH_MAX];
        strcpy(temp_path, mfu_flist_file_get_name(filtered, idx));
        strcat(temp_path, suffix);

        /* create a striped file at the temp file path */
        mfu_stripe_set(temp_path, stripe_size, stripes);

        /* update our status for file create progress */
        create_prog_count++;
        mfu_progress_update(&create_prog_count, create_prog);
    }

    /* finalize file create progress messages */
    mfu_progress_complete(&create_prog_count, &create_prog);

    MPI_Barrier(MPI_COMM_WORLD);

    /* initialize progress messages while copying data */
    stripe_prog_bytes = 0;
    stripe_prog = mfu_progress_start(mfu_progress_timeout, 1, MPI_COMM_WORLD, stripe_progress_fn);

    /* found a suffix, now we need to break our files into chunks based on stripe size */
    mfu_file_chunk* file_chunks = mfu_file_chunk_list_alloc(filtered, stripe_size);
    mfu_file_chunk* p = file_chunks;
    while (p != NULL) {
        /* build path to temp file */
        char temp_path[PATH_MAX];
        strcpy(temp_path, p->name);
        strcat(temp_path, suffix);

        /* write each chunk in our list */
        write_file_chunk(p, temp_path);

        /* move on to next file chunk */
        p = p->next;
    }
    mfu_file_chunk_list_free(&file_chunks);

    /* finalize progress messages */
    mfu_progress_complete(&stripe_prog_bytes, &stripe_prog);

    MPI_Barrier(MPI_COMM_WORLD);

    /* remove input file and rename temp file */
    for (idx = 0; idx < size; idx++) {
        /* build path to temp file */
        const char *in_path = mfu_flist_file_get_name(filtered, idx);
        char out_path[PATH_MAX];
        strcpy(out_path, in_path);
        strcat(out_path, suffix);

        /* change the mode of the newly restriped file to be the same as the old one */
        mode_t mode = (mode_t) mfu_flist_file_get_mode(filtered, idx);
        if (mfu_chmod(out_path, mode) != 0) {
            MFU_LOG(MFU_LOG_ERR, "Failed to chmod file %s (%s)", out_path, strerror(errno));
            MPI_Abort(MPI_COMM_WORLD, 1);
        }

        /* rename the new, restriped file to the old name */
        if (rename(out_path, in_path) != 0) {
            MFU_LOG(MFU_LOG_ERR, "Failed to rename file %s to %s", out_path, in_path);
            MPI_Abort(MPI_COMM_WORLD, 1);
        }
    }

    /* wait for everyone to finish */
    MPI_Barrier(MPI_COMM_WORLD);

    /* free the walk options */
    mfu_walk_opts_delete(&walk_opts);

    /* free filtered list, path parameters */
    mfu_flist_free(&filtered);
    mfu_param_path_free_all(numpaths, paths);
    mfu_free(&paths);

    mfu_finalize();
    MPI_Finalize();

    return 0;
}