qioerr chpl_fs_get_gid(int* ret, const char* name) { struct stat buf; int exitStatus = stat(name, &buf); if (exitStatus) return qio_mkerror_errno(); *ret = buf.st_gid; return 0; }
/* creates a symlink named linkName to the file orig */ qioerr chpl_fs_symlink(const char* orig, const char* linkName) { qioerr err = 0; int exitStatus = symlink(orig, linkName); if (exitStatus) err = qio_mkerror_errno(); return err; }
/* Renames the file from oldname to newname, returning a qioerr if one occurred. */ qioerr chpl_fs_rename(const char* oldname, const char* newname) { qioerr err = 0; int exitStatus = rename(oldname, newname); // utilizes the C library function rename. if (exitStatus) err = qio_mkerror_errno(); return err; }
qioerr _chpl_fs_check_mode(int* ret, const char* name, int mode_flag) { struct stat buf; int exitStatus = stat(name, &buf); if (exitStatus) return qio_mkerror_errno(); *ret = (buf.st_mode&mode_flag) != 0; return 0; }
// Send a signal to the specified pid qioerr qio_send_signal(int64_t pid, int sig) { qioerr err = 0; int rc = kill(pid, sig); if (rc == -1) err = qio_mkerror_errno(); return err; }
qioerr chpl_fs_realpath(const char* path, const char **shortened) { qioerr err = 0; *shortened = realpath(path, NULL); if (*shortened == NULL) { // If an error occurred, shortened will be NULL. Otherwise, it will // contain the cleaned up path. err = qio_mkerror_errno(); } return err; }
qioerr chpl_fs_copy_metadata(const char* source, const char* dest) { qioerr err = 0; struct stat oldTimes; struct utimbuf times; int exitStatus = stat(source, &oldTimes); if (exitStatus == -1) { // Hopefully an error will not occur (as we have checked that the // file exists when we perform the other operations on it). But just in // case, check it here. err = qio_mkerror_errno(); return err; } times.actime = oldTimes.st_atime; // The access time times.modtime = oldTimes.st_mtime; // The modification time exitStatus = utime(dest, ×); // Set the times for dest. if (exitStatus == -1) { err = qio_mkerror_errno(); } return err; }
// This routine returns a malloc'd string (through the working_dir pointer) // that must be deallocated by the caller. qioerr chpl_fs_cwd(const char** working_dir) { qioerr err = 0; size_t bufsize = MAXPATHLEN*sizeof(char); char* bufptr; char* pathbuf = (char *)qio_malloc(bufsize); bufptr = getcwd(pathbuf, bufsize); if (bufptr == NULL) err = qio_mkerror_errno(); else *working_dir = pathbuf; return err; }
/* Returns the current permissions on a file specified by name */ qioerr chpl_fs_viewmode(int* ret, const char* name) { struct stat buf; int exitStatus = stat(name, &buf); if (exitStatus) return qio_mkerror_errno(); *ret = (int)(buf.st_mode&(S_IRWXU | S_IRWXG | S_IRWXO | S_ISUID | S_ISGID | S_ISVTX)); // Stylistic decision: while we have the capacity to make sure all we're // getting are the permissions bits in module code, sending that extra // information strikes me as unnecessary, since we don't intend to use it at // the module level in other circumstances. return 0; }
qioerr hdfs_fsync(void* fl, void* fs) { int got; qioerr err_out = 0; STARTING_SLOW_SYSCALL; got = hdfsFlush(to_hdfs_fs(fs)->hfs, to_hdfs_file(fl)->file); if(got == -1) err_out = qio_mkerror_errno(); DONE_SLOW_SYSCALL; return err_out; }
qioerr hdfs_close(void* fl, void* fs) { int got = 0; qioerr err_out = 0; STARTING_SLOW_SYSCALL; got = hdfsCloseFile(to_hdfs_fs(fs)->hfs, to_hdfs_file(fl)->file); if(got == -1) err_out = qio_mkerror_errno(); DONE_SLOW_SYSCALL; DO_RELEASE((to_hdfs_fs(fs)), hdfs_disconnect_and_free); return err_out; }
qioerr chpl_fs_is_link(int* ret, const char* name) { // Note: Cannot use _chpl_fs_check_mode in this case because stat follows // symbolic links instead of evaluating the link itself. The similar // comparison is also not valid when an unlinked file is provided. struct stat buf; int exitStatus = lstat(name, &buf); if (exitStatus == -1 && errno == ENOENT) { // The link examined does not exist, return false *ret = 0; return 0; } else if (exitStatus) { return qio_mkerror_errno(); } *ret = S_ISLNK(buf.st_mode); return 0; }
qioerr chpl_fs_realpath(const char* path, const char **shortened) { qioerr err = 0; size_t bufsize = MAXPATHLEN*sizeof(char); char* bufptr; char* pathbuf = (char *)qio_malloc(bufsize); bufptr = realpath(path, pathbuf); if (bufptr == NULL) { // If an error occurred, bufptr will be NULL. Otherwise, it will // point to pathbuf anyways err = qio_mkerror_errno(); qio_free(pathbuf); } else { *shortened = pathbuf; } return err; }
qioerr chpl_fs_exists(int* ret, const char* name) { qioerr err = 0; struct stat buf; // Stat will attempt to follow all symbolic links. If the link is broken, // this means we will detect it and return false. int exitStatus = stat(name, &buf); if (exitStatus == -1 && errno == ENOENT) { // File or directory does not exist, return false *ret = 0; } else if (exitStatus) { // Another error occurred. Return it. err = qio_mkerror_errno(); } else { // The file or directory exists, return true *ret = 1; } return err; }
static qioerr hdfs_disconnect_and_free(void* fs) { qioerr err = 0; int ret= 0; STARTING_SLOW_SYSCALL; errno = 0; ret = hdfsDisconnect(((hdfs_fs*)fs)->hfs); if ((ret == -2) || (ret == -1)) { err = qio_mkerror_errno(); } else errno = 0; DONE_SLOW_SYSCALL; qio_free(fs); return err; }
qioerr hdfs_open(void** fd, const char* path, int* flags, mode_t mode, qio_hint_t iohints, void* fs) { qioerr err_out = 0; int rc; hdfs_file* fl = (hdfs_file*)qio_calloc(sizeof(hdfs_file), 1); STARTING_SLOW_SYSCALL; DO_RETAIN(((hdfs_fs*)fs)); // assert that we connected CREATE_ERROR((to_hdfs_fs(fs)->hfs == NULL), err_out, ECONNREFUSED,"Unable to open HDFS file", error); fl->file = hdfsOpenFile(to_hdfs_fs(fs)->hfs, path, *flags, 0, 0, 0); // Assert that we opened the file if (fl->file == NULL) { err_out = qio_mkerror_errno(); goto error; } DONE_SLOW_SYSCALL; fl->pathnm = path; rc = *flags | ~O_ACCMODE; rc &= O_ACCMODE; if( rc == O_RDONLY ) { *flags |= QIO_FDFLAG_READABLE; } else if( rc == O_WRONLY ) { *flags |= QIO_FDFLAG_WRITEABLE; } else if( rc == O_RDWR ) { *flags |= QIO_FDFLAG_READABLE; *flags |= QIO_FDFLAG_WRITEABLE; } *fd = fl; // Set fd to fl and return return err_out; error: qio_free(fl); return err_out; }
static qioerr curl_writev(void* fl, const struct iovec* iov, int iovcnt, ssize_t* num_written_out, void* fs) { CURLcode ret; qioerr err_out = 0; struct curl_iovec_t write_vec; write_vec.total_read = 0; write_vec.count = iovcnt; write_vec.vec = (struct iovec*)iov; write_vec.amt_read = 0; write_vec.offset = 0; write_vec.curr = 0; STARTING_SLOW_SYSCALL; /*tell it to "upload" to the URL*/ curl_easy_setopt(to_curl_handle(fl)->curl, CURLOPT_UPLOAD, 1L); // set it up to write over curl curl_easy_setopt(to_curl_handle(fl)->curl, CURLOPT_READFUNCTION, read_data); // Tell curl how much data to expect curl_easy_setopt(to_curl_handle(fl)->curl, CURLOPT_INFILESIZE_LARGE, (curl_off_t)sys_iov_total_bytes(iov, iovcnt)); curl_easy_setopt(to_curl_handle(fl)->curl, CURLOPT_READDATA, &write_vec); ret = curl_easy_perform(to_curl_handle(fl)->curl); *num_written_out = write_vec.total_read; if (ret != CURLE_OK) err_out = qio_mkerror_errno(); curl_easy_setopt(to_curl_handle(fl)->curl, CURLOPT_UPLOAD, 0L); curl_easy_setopt(to_curl_handle(fl)->curl, CURLOPT_INFILESIZE_LARGE, 0L); curl_easy_setopt(to_curl_handle(fl)->curl, CURLOPT_READFUNCTION, NULL); curl_easy_setopt(to_curl_handle(fl)->curl, CURLOPT_READDATA, NULL); DONE_SLOW_SYSCALL; return err_out; }
qioerr chpl_fs_is_mount(int* ret, const char* name) { qioerr err = 0; struct stat nBuf, parentBuf; int exitStatus = 0; size_t nameLen = strlen(name); char* parent = (char* ) chpl_mem_allocMany(nameLen + 4, sizeof(char), CHPL_RT_MD_OS_LAYER_TMP_DATA, 0, 0); char* safeNameCopy = (char* ) chpl_mem_allocMany(nameLen + 1, sizeof(char), CHPL_RT_MD_OS_LAYER_TMP_DATA, 0, 0); strncpy(safeNameCopy, name, nameLen + 1); // Need to copy name so that we can use it in the case of links err = chpl_fs_is_link(&exitStatus, name); if (err) { // The stat call in is_link returned an error, which we would encounter too, // so return immediately. chpl_mem_free(parent, 0, 0); chpl_mem_free(safeNameCopy, 0, 0); return err; } else if (exitStatus) { // We are dealing with a link. Using /.. will refer to the parent of the // linked location, rather than the parent of the link itself. We need to // perform some string token action. // Lydia note (03/17/2015): when the Path library is more fleshed out, this // operation could be done in module code and this function would instead // take the name of the parent and child instead of creating the parent name // itself. char* curTok = strtok(safeNameCopy, "/"); char* nextTok = strtok(NULL, "/"); // We need the next token to determine if the path is longer than a single // link name. assert(curTok != NULL); // curTok should never be null. The only string which would return null is // "/", but that directory is not a link, so won't be here in the first // place. if (nextTok != NULL) { // name includes a path longer than just the current symlink. // Thus, we should copy up to (but not including) the basename of the // path. strncpy(parent, curTok, strlen(curTok) + 1); curTok = nextTok; nextTok = strtok(NULL, "/"); while (nextTok != NULL) { // While we haven't found the end of the path (in nextTok) strncat(parent, "/", 1); // Restore the lost path separator. strncat(parent, curTok, strlen(curTok)); // Add the current token to the parent list curTok = nextTok; // And prepare to check if the next token is the last in the path nextTok = strtok(NULL, "/"); } } else { // name was merely the current symlink rather than a longer path. // That means its parent is "." or the current directory. strncpy(parent, ".", 2); } } else { // We are not referring to a link, so concatenating "/.." is fine. strncpy(parent, name, nameLen + 1); strncat(parent, "/..", 3); // TODO: Using "/" is not necessarily portable, look into this } exitStatus = lstat(name, &nBuf); if (exitStatus) { err = qio_mkerror_errno(); chpl_mem_free(parent, 0, 0); chpl_mem_free(safeNameCopy, 0, 0); return err; } exitStatus = lstat(parent, &parentBuf); if (exitStatus) { err = qio_mkerror_errno(); } else { if (nBuf.st_dev != parentBuf.st_dev) { *ret = 1; // Check if the st_dev matches that of its parent directory. // If they don't match, it is a mount point. } else { err = chpl_fs_samefile_string(ret, name, parent); // If the parent directory is the same as the current directory, we've // reached the root. If they don't, we know it isn't a mount point // because we already know their st_dev matches. } } chpl_mem_free(parent, 0, 0); chpl_mem_free(safeNameCopy, 0, 0); return err; }
qioerr hdfs_preadv (void* file, const struct iovec *vector, int count, off_t offset, ssize_t* num_read_out, void* fs) { ssize_t got; ssize_t got_total; qioerr err_out = 0; int i; STARTING_SLOW_SYSCALL; #ifdef HDFS3 const hdfs_file orig_hfl = *to_hdfs_file(file); const hdfs_fs orig_hfs = *to_hdfs_fs(fs); hdfsFS hfs = hdfsConnect(orig_hfs.fs_name, orig_hfs.fs_port); hdfsFile hfl = hdfsOpenFile(hfs, orig_hfl.pathnm, O_RDONLY, 0, 0, 0); //assert connection CREATE_ERROR((hfs == NULL), err_out, ECONNREFUSED, "Unable to read HDFS file", error); if(hfl == NULL) { err_out = qio_mkerror_errno(); goto error; } #endif err_out = 0; got_total = 0; for(i = 0; i < count; i++) { #ifdef HDFS3 hdfsSeek(hfs, hfl, offset+got_total); got = hdfsRead(hfs, hfl, (void*)vector[i].iov_base, vector[i].iov_len); #else got = hdfsPread(to_hdfs_fs(fs)->hfs, to_hdfs_file(file)->file, offset + got_total, (void*)vector[i].iov_base, vector[i].iov_len); #endif if( got != -1 ) { got_total += got; } else { err_out = qio_mkerror_errno(); break; } if(got != (ssize_t)vector[i].iov_len ) { break; } } if( err_out == 0 && got_total == 0 && sys_iov_total_bytes(vector, count) != 0 ) err_out = qio_int_to_err(EEOF); *num_read_out = got_total; #ifdef HDFS3 got = hdfsCloseFile(hfs, hfl); if(got == -1) { err_out = qio_mkerror_errno(); } got = hdfsDisconnect(hfs); if(got == -1) { err_out = qio_mkerror_errno(); } #endif DONE_SLOW_SYSCALL; #ifdef HDFS3 error: #endif return err_out; }
/* Creates a directory with the given name and settings if possible, returning a qioerr if not. If parents != 0, then the callee wishes to create all interim directories necessary as well. */ qioerr chpl_fs_mkdir(const char* name, int mode, int parents) { qioerr err = 0; int exitStatus; if (!parents) { // Simple, easy. Callee didn't specify recursive creation, so // if something fails, they get to deal with it. exitStatus = mkdir(name, mode); } else { int len = strlen(name); char tmp[len+1]; int index; struct stat statRes; // We don't actually care about the full result of the stat calls, merely // the existence and state of the directory being accessed. while (name[len-1] == '/') { // In case the caller, in their infinite wisdom, decides to send // a directory name of the form "foo///////". len--; // Note: not being able to mix declarations and code means that // tmp must be created larger than might be necessary. } // Copy each step of the directory path into a temporary string, // creating the parent directories as needed. In the case of name // being "foo/bar/baz", this means that tmp will be "foo/" and then // "foo/bar" for each inner call of mkdir. for (index = 0; name[index] != '\0' && index < len; index++) { tmp[index] = name[index]; if(tmp[index] == '/') { tmp[index+1] = '\0'; exitStatus = stat(tmp, &statRes); if (exitStatus == -1 && errno == ENOENT) { // This error means we could not find the parent directory, so need // to create it. exitStatus = mkdir(tmp, mode); } // EEXIST could occur from the mkdir call above if the directory came // into existence between when we checked and when we tried to create // it. There's really nothing to be done about it, so skip it and // continue on. if (exitStatus && errno != EEXIST) { // We encountered an error making a parent directory or during the // stat call to determine if we need to make a directory. We will // encounter errors for every step after this, so return this one // as it will be more informative. err = qio_mkerror_errno(); return err; } } } tmp[len] = '\0'; exitStatus = mkdir(tmp, mode); if (exitStatus && errno == EEXIST) { // If we encountered EEXIST when creating the last directory, ignore it. // This behavior is consistent with the command line mkdir -p behavior. exitStatus = 0; } } if (exitStatus) { err = qio_mkerror_errno(); } return err; }