void DCOPY_do_cleanup(DCOPY_operation_t* op, \ CIRCLE_handle* handle) { char* newop; /* * Truncate file on last chunk (synchronous mode can write past end of file) */ int64_t bytes_written = (int64_t)(op->chunk + 1) * (int64_t)DCOPY_user_opts.chunk_size; if(bytes_written >= op->file_size) { /* truncate file to appropriate size, to do this before * setting permissions in case file does not have write permission */ DCOPY_truncate_file(op, handle); /* since we still may access the file in the compare step, * delay setting permissions and timestamps until final phase */ } /* * Add work item to compare source and destination if user requested it. */ if(DCOPY_user_opts.compare) { newop = DCOPY_encode_operation(COMPARE, op->chunk, op->operand, \ op->source_base_offset, \ op->dest_base_appendix, op->file_size); handle->enqueue(newop); free(newop); } return; }
void DCOPY_retry_failed_operation(DCOPY_operation_code_t target, \ CIRCLE_handle* handle, \ DCOPY_operation_t* op) { char* new_op; if(DCOPY_user_opts.reliable_filesystem) { MFU_LOG(MFU_LOG_ERR, "Not retrying failed operation. " \ "Reliable filesystem is specified. (op=%d chunk=%ld src=%s dst=%s)", target, op->chunk, op->operand, op->dest_full_path); DCOPY_abort(EXIT_FAILURE); } else { MFU_LOG(MFU_LOG_INFO, "Attempting to retry operation."); new_op = DCOPY_encode_operation(target, op->chunk, op->operand, \ op->source_base_offset, \ op->dest_base_appendix, op->file_size); handle->enqueue(new_op); mfu_free(&new_op); } return; }
/* * Encode and enqueue the cleanup stage for this chunk so the file is * truncated and (if specified via getopt) permissions are preserved. */ void DCOPY_enqueue_cleanup_stage(DCOPY_operation_t* op, \ CIRCLE_handle* handle) { char* newop; newop = DCOPY_encode_operation(CLEANUP, op->chunk, op->operand, \ op->source_base_offset, \ op->dest_base_appendix, op->file_size); handle->enqueue(newop); free(newop); }
void DCOPY_do_cleanup(DCOPY_operation_t* op, \ CIRCLE_handle* handle) { char* newop; bool ownership_preserved; /* * Only bother truncating and setting permissions on the first chunk of * the file. */ if(op->chunk == 0) { if(DCOPY_user_opts.preserve) { /* build destination object name */ char dest_path_recursive[PATH_MAX]; char dest_path_file_to_file[PATH_MAX]; if(op->dest_base_appendix == NULL) { sprintf(dest_path_recursive, "%s/%s", \ DCOPY_user_opts.dest_path, \ op->operand + op->source_base_offset + 1); strncpy(dest_path_file_to_file, DCOPY_user_opts.dest_path, PATH_MAX); } else { sprintf(dest_path_recursive, "%s/%s/%s", \ DCOPY_user_opts.dest_path, \ op->dest_base_appendix, \ op->operand + op->source_base_offset + 1); sprintf(dest_path_file_to_file, "%s/%s", \ DCOPY_user_opts.dest_path, \ op->dest_base_appendix); } /* get stat of source object */ struct stat64 statbuf; if(lstat64(op->operand, &statbuf) == 0) { ownership_preserved = DCOPY_set_preserve_ownership(op, handle, &statbuf, dest_path_recursive); DCOPY_set_preserve_permissions(op, handle, ownership_preserved, &statbuf, dest_path_recursive); DCOPY_set_preserve_timestamps(op, handle, &statbuf, dest_path_recursive); } else { /* LOG(DCOPY_LOG_ERR, "Could not determine if `%s' is a directory. %s", path, strerror(errno)); */ } } DCOPY_truncate_file(op, handle); } /* * If the user is feeling brave, this is where we let them skip the * comparison stage. */ if(!DCOPY_user_opts.skip_compare) { newop = DCOPY_encode_operation(COMPARE, op->chunk, op->operand, \ op->source_base_offset, \ op->dest_base_appendix, op->file_size); handle->enqueue(newop); free(newop); } return; }
/** * Analyze all file path inputs and place on the work queue. * * We start off with all of the following potential options in mind and prune * them until we figure out what situation we have. * * Libcircle only calls this function from rank 0, so there's no need to check * the current rank here. * * Source must overwrite destination. * - Single file to single file * * Must return an error. Impossible condition. * - Single directory to single file * - Many file to single file * - Many directory to single file * - Many directory and many file to single file * * All Sources must be placed inside destination. * - Single file to single directory * - Single directory to single directory * - Many file to single directory * - Many directory to single directory * - Many file and many directory to single directory * * @param handle the libcircle primary queue handle. */ void DCOPY_enqueue_work_objects(CIRCLE_handle* handle) { bool dest_is_dir = DCOPY_dest_is_dir(); bool dest_is_file = !dest_is_dir; char* opts_dest_path_dirname; char* src_path_dirname; uint32_t number_of_source_files = DCOPY_source_file_count(); if(number_of_source_files < 1) { LOG(DCOPY_LOG_ERR, "At least one valid source file must be specified."); DCOPY_abort(EXIT_FAILURE); } if(dest_is_file) { LOG(DCOPY_LOG_DBG, "Infered that the destination is a file."); /* * If the destination is a file, there must be only one source object, and it * must be a file. */ if(number_of_source_files == 1 && DCOPY_is_regular_file(DCOPY_user_opts.src_path[0])) { /* Make a copy of the dest path so we can run dirname on it. */ size_t dest_size = sizeof(char) * PATH_MAX; opts_dest_path_dirname = (char*) malloc(dest_size); if(opts_dest_path_dirname == NULL) { LOG(DCOPY_LOG_DBG, "Failed to allocate %llu bytes for dest path.", (long long unsigned) dest_size); DCOPY_abort(EXIT_FAILURE); } int dest_written = snprintf(opts_dest_path_dirname, dest_size, "%s", DCOPY_user_opts.dest_path); if(dest_written < 0 || (size_t)(dest_written) > dest_size - 1) { LOG(DCOPY_LOG_DBG, "Destination path too long."); DCOPY_abort(EXIT_FAILURE); } opts_dest_path_dirname = dirname(opts_dest_path_dirname); /* Make a copy of the src path so we can run dirname on it. */ size_t src_size = sizeof(char) * PATH_MAX; src_path_dirname = (char*) malloc(sizeof(char) * PATH_MAX); if(src_path_dirname == NULL) { LOG(DCOPY_LOG_DBG, "Failed to allocate %llu bytes for dest path.", (long long unsigned) src_size); DCOPY_abort(EXIT_FAILURE); } int src_written = snprintf(src_path_dirname, src_size, "%s", DCOPY_user_opts.src_path[0]); if(src_written < 0 || (size_t)(src_written) > src_size - 1) { LOG(DCOPY_LOG_DBG, "Source path too long."); DCOPY_abort(EXIT_FAILURE); } src_path_dirname = dirname(src_path_dirname); /* LOG(DCOPY_LOG_DBG, "Enqueueing only a single source path `%s'.", DCOPY_user_opts.src_path[0]); */ char* op = DCOPY_encode_operation(TREEWALK, 0, DCOPY_user_opts.src_path[0], \ (uint16_t)strlen(src_path_dirname), NULL, 0); handle->enqueue(op); free(op); free(opts_dest_path_dirname); free(src_path_dirname); } else { /* * Determine if we're trying to copy one or more directories into * a file. */ int i; for(i = 0; i < DCOPY_user_opts.num_src_paths; i++) { char* src_path = DCOPY_user_opts.src_path[i]; if(DCOPY_is_directory(src_path)) { LOG(DCOPY_LOG_ERR, "Copying a directory into a file is not supported."); DCOPY_abort(EXIT_FAILURE); } } /* * The only remaining possible condition is that the user wants to * copy multiple files into a single file (hopefully). */ LOG(DCOPY_LOG_ERR, "Copying several files into a single file is not supported."); DCOPY_abort(EXIT_FAILURE); } } else if(dest_is_dir) { LOG(DCOPY_LOG_DBG, "Infered that the destination is a directory."); bool dest_already_exists = DCOPY_is_directory(DCOPY_user_opts.dest_path); int i; for(i = 0; i < DCOPY_user_opts.num_src_paths; i++) { char* src_path = DCOPY_user_opts.src_path[i]; LOG(DCOPY_LOG_DBG, "Enqueueing source path `%s'.", src_path); char* src_path_basename = NULL; size_t src_len = strlen(src_path) + 1; char* src_path_basename_tmp = (char*) malloc(src_len); if(src_path_basename_tmp == NULL) { LOG(DCOPY_LOG_ERR, "Failed to allocate tmp for src_path_basename."); DCOPY_abort(EXIT_FAILURE); } /* * If the destination directory already exists, we want to place * new files inside it. To do this, we send a path fragment along * with the source path message and append it to the options dest * path whenever the options dest path is used. */ if(dest_already_exists && !DCOPY_user_opts.conditional) { /* Make a copy of the src path so we can run basename on it. */ strncpy(src_path_basename_tmp, src_path, src_len); src_path_basename = basename(src_path_basename_tmp); } char* op = DCOPY_encode_operation(TREEWALK, 0, src_path, \ (uint16_t)(src_len - 1), \ src_path_basename, 0); handle->enqueue(op); free(src_path_basename_tmp); } } else { /* * This is the catch-all for all of the object types we haven't * implemented yet. */ LOG(DCOPY_LOG_ERR, "We've encountered an unsupported filetype."); DCOPY_abort(EXIT_FAILURE); } /* TODO: print mode we're using to DBG. */ }