int DCOPY_open_file(const char* file, int read_flag, DCOPY_file_cache_t* cache) { int newfd = -1; /* see if we have a cached file descriptor */ char* name = cache->name; if (name != NULL) { /* we have a cached file descriptor */ int fd = cache->fd; if (strcmp(name, file) == 0 && cache->read == read_flag) { /* the file we're trying to open matches name and read/write mode, * so just return the cached descriptor */ return fd; } else { /* the file we're trying to open is different, * close the old file and delete the name */ mfu_close(name, fd); mfu_free(&cache->name); } } /* open the new file */ if (read_flag) { int flags = O_RDONLY; if (DCOPY_user_opts.synchronous) { flags |= O_DIRECT; } newfd = mfu_open(file, flags); } else { int flags = O_WRONLY | O_CREAT; if (DCOPY_user_opts.synchronous) { flags |= O_DIRECT; } newfd = mfu_open(file, flags, DCOPY_DEF_PERMS_FILE); } /* cache the file descriptor */ if (newfd != -1) { cache->name = MFU_STRDUP(file); cache->fd = newfd; cache->read = read_flag; } return newfd; }
static void walk_getdents_process_dir(const char* dir, CIRCLE_handle* handle) { char buf[BUF_SIZE]; /* TODO: may need to try these functions multiple times */ int fd = mfu_open(dir, O_RDONLY | O_DIRECTORY); if (fd == -1) { /* print error */ MFU_LOG(MFU_LOG_ERR, "Failed to open directory for reading: `%s' (errno=%d %s)", dir, errno, strerror(errno)); return; } /* Read all directory entries */ while (1) { /* execute system call to get block of directory entries */ int nread = syscall(SYS_getdents, fd, buf, (int) BUF_SIZE); if (nread == -1) { MFU_LOG(MFU_LOG_ERR, "syscall to getdents failed when reading `%s' (errno=%d %s)", dir, errno, strerror(errno)); break; } /* bail out if we're done */ if (nread == 0) { break; } /* otherwise, we read some bytes, so process each record */ int bpos = 0; while (bpos < nread) { /* get pointer to current record */ struct linux_dirent* d = (struct linux_dirent*)(buf + bpos); /* get name of directory item, skip d_ino== 0, ".", and ".." entries */ char* name = d->d_name; if (d->d_ino != 0 && (strncmp(name, ".", 2)) && (strncmp(name, "..", 3))) { /* check whether we can define path to item: * <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); /* get type of item */ char d_type = *(buf + bpos + d->d_reclen - 1); #if 0 printf("%-10s ", (d_type == DT_REG) ? "regular" : (d_type == DT_DIR) ? "directory" : (d_type == DT_FIFO) ? "FIFO" : (d_type == DT_SOCK) ? "socket" : (d_type == DT_LNK) ? "symlink" : (d_type == DT_BLK) ? "block dev" : (d_type == DT_CHR) ? "char dev" : "???"); printf("%4d %10lld %s\n", d->d_reclen, (long long) d->d_off, (char*) d->d_name); #endif /* TODO: this is hacky, would be better to create list elem directly */ /* determine type of item (just need to set bits in mode * that get_mfu_filetype checks for) */ mode_t mode = 0; if (d_type == DT_REG) { mode |= S_IFREG; } else if (d_type == DT_DIR) { mode |= S_IFDIR; } else if (d_type == DT_LNK) { mode |= S_IFLNK; } /* insert a record for this item into our list */ mfu_flist_insert_stat(CURRENT_LIST, newpath, mode, NULL); /* increment our item count */ reduce_items++; /* recurse on directory if we have one */ if (d_type == DT_DIR) { handle->enqueue(newpath); } } else { MFU_LOG(MFU_LOG_ERR, "Path name is too long: %lu chars exceeds limit %lu", len, sizeof(newpath)); } } /* advance to next record */ bpos += d->d_reclen; } } mfu_close(dir, fd); return; }
/* write a chunk of the file */ static void write_file_chunk(mfu_file_chunk* p, const char* out_path) { size_t chunk_size = 1024*1024; uint64_t base = (off_t)p->offset; uint64_t file_size = (off_t)p->file_size; const char *in_path = p->name; uint64_t stripe_size = (off_t)p->length; /* if the file size is 0, there's no data to restripe */ /* if the stripe size is 0, then there's no work to be done */ if (file_size == 0 || stripe_size == 0) { return; } /* allocate buffer */ void* buf = MFU_MALLOC(chunk_size); /* open input file for reading */ int in_fd = mfu_open(in_path, O_RDONLY); if (in_fd < 0) { MFU_LOG(MFU_LOG_ERR, "Failed to open input file %s (%s)", in_path, strerror(errno)); MPI_Abort(MPI_COMM_WORLD, 1); } /* open output file for writing */ int out_fd = mfu_open(out_path, O_WRONLY); if (out_fd < 0) { MFU_LOG(MFU_LOG_ERR, "Failed to open output file %s (%s)", out_path, strerror(errno)); MPI_Abort(MPI_COMM_WORLD, 1); } /* write data */ uint64_t chunk_id = 0; uint64_t stripe_read = 0; while (stripe_read < stripe_size) { /* determine number of bytes to read */ /* try to read a full chunk's worth of bytes */ size_t read_size = chunk_size; /* if the stripe doesn't have that much left */ uint64_t remainder = stripe_size - stripe_read; if (remainder < (uint64_t) read_size) { read_size = (size_t) remainder; } /* get byte offset to read from */ uint64_t offset = base + (chunk_id * chunk_size); if (offset < file_size) { /* the first byte falls within the file size, * now check the last byte */ uint64_t last = offset + (uint64_t) read_size; if (last > file_size) { /* the last byte is beyond the end, set read size * to the most we can read */ read_size = (size_t) (file_size - offset); } } else { /* the first byte we need to read is past the end of * the file, so don't read anything */ read_size = 0; } /* bail if we don't have anything to read */ if (read_size == 0) { break; } /* seek to correct spot in input file */ off_t pos = (off_t) offset; off_t seek_rc = mfu_lseek(in_path, in_fd, pos, SEEK_SET); if (seek_rc == (off_t)-1) { MFU_LOG(MFU_LOG_ERR, "Failed to seek in input file %s (%s)", in_path, strerror(errno)); MPI_Abort(MPI_COMM_WORLD, 1); } /* read chunk from input */ ssize_t nread = mfu_read(in_path, in_fd, buf, read_size); /* check for errors */ if (nread < 0) { MFU_LOG(MFU_LOG_ERR, "Failed to read data from input file %s (%s)", in_path, strerror(errno)); MPI_Abort(MPI_COMM_WORLD, 1); } /* check for short reads */ if (nread != read_size) { MFU_LOG(MFU_LOG_ERR, "Got a short read from input file %s", in_path); MPI_Abort(MPI_COMM_WORLD, 1); } /* seek to correct spot in output file */ seek_rc = mfu_lseek(out_path, out_fd, pos, SEEK_SET); if (seek_rc == (off_t)-1) { MFU_LOG(MFU_LOG_ERR, "Failed to seek in output file %s (%s)", out_path, strerror(errno)); MPI_Abort(MPI_COMM_WORLD, 1); } /* write chunk to output */ ssize_t nwrite = mfu_write(out_path, out_fd, buf, read_size); /* check for errors */ if (nwrite < 0) { MFU_LOG(MFU_LOG_ERR, "Failed to write data to output file %s (%s)", out_path, strerror(errno)); MPI_Abort(MPI_COMM_WORLD, 1); } /* check for short reads */ if (nwrite != read_size) { MFU_LOG(MFU_LOG_ERR, "Got a short write to output file %s", out_path); MPI_Abort(MPI_COMM_WORLD, 1); } /* update our byte count for progress messages */ stripe_prog_bytes += read_size; mfu_progress_update(&stripe_prog_bytes, stripe_prog); /* go on to the next chunk in this stripe, we assume we * read the whole chunk size, if we didn't it's because * the stripe is smaller or we're at the end of the file, * but in either case we're done so it doesn't hurt to * over estimate in this calculation */ stripe_read += (uint64_t) chunk_size; chunk_id++; } /* close files */ mfu_fsync(out_path, out_fd); mfu_close(out_path, out_fd); mfu_close(in_path, in_fd); /* free buffer */ mfu_free(&buf); }
/* open the specified file, read specified chunk, and close file, * returns -1 on any read error */ static int read_data(const char* fname, char* chunk_buf, uint64_t chunk_id, uint64_t chunk_size, uint64_t file_size, uint64_t* data_size) { int status = 0; assert(chunk_id > 0); /* compute byte offset to read from in file */ uint64_t offset = (chunk_id - 1) * chunk_size; /* zero out our buffer */ memset(chunk_buf, 0, chunk_size); /* open the file */ int fd = mfu_open(fname, O_RDONLY); if (fd < 0) { return -1; } /* seek to the correct offset */ if (mfu_lseek(fname, fd, (off_t)offset, SEEK_SET) == (off_t) - 1) { status = -1; goto out; } /* read data from file */ ssize_t read_size = mfu_read(fname, fd, chunk_buf, chunk_size); if (read_size < 0) { /* read failed */ status = -1; goto out; } /* compute number of bytes we expect to read */ ssize_t expect_size = (ssize_t) chunk_size; if (chunk_id * chunk_size > file_size) { if (offset >= file_size) { /* have gone past the end of the file, expect to read 0 */ expect_size = 0; } else { /* read partial chunk */ expect_size = (ssize_t) (file_size - offset); } } /* check that we read all bytes we expected */ if (read_size != expect_size) { /* File size has been changed */ status = -1; goto out; } /* return number of bytes read */ *data_size = (uint64_t)read_size; out: /* close our file and return */ mfu_close(fname, fd); return status; }
int DCOPY_open_file(const char* file, int read_flag, DCOPY_file_cache_t* cache) { int newfd = -1; /* see if we have a cached file descriptor */ char* name = cache->name; if (name != NULL) { /* we have a cached file descriptor */ int fd = cache->fd; if (strcmp(name, file) == 0 && cache->read == read_flag) { /* the file we're trying to open matches name and read/write mode, * so just return the cached descriptor */ return fd; } else { /* the file we're trying to open is different, * close the old file and delete the name */ mfu_close(name, fd); mfu_free(&cache->name); } } /* open the new file */ if (read_flag) { int flags = O_RDONLY; if (DCOPY_user_opts.synchronous) { flags |= O_DIRECT; } newfd = mfu_open(file, flags); } else { int flags = O_WRONLY | O_CREAT; if (DCOPY_user_opts.synchronous) { flags |= O_DIRECT; } newfd = mfu_open(file, flags, DCOPY_DEF_PERMS_FILE); } /* cache the file descriptor */ if (newfd != -1) { cache->name = MFU_STRDUP(file); cache->fd = newfd; cache->read = read_flag; #ifdef LUSTRE_SUPPORT /* Zero is an invalid ID for grouplock. */ if (DCOPY_user_opts.grouplock_id != 0) { int rc; rc = ioctl(newfd, LL_IOC_GROUP_LOCK, DCOPY_user_opts.grouplock_id); if (rc) { MFU_LOG(MFU_LOG_ERR, "Failed to obtain grouplock with ID %d " "on file `%s', ignoring this error: %s", DCOPY_user_opts.grouplock_id, file, strerror(errno)); } else { MFU_LOG(MFU_LOG_INFO, "Obtained grouplock with ID %d " "on file `%s', fd %d", DCOPY_user_opts.grouplock_id, file, newfd); } } #endif } return newfd; }