#include #include #include #include #include "common.h" #include "debug.h" #include "string.h" #include "filepath.h" #include "utils.h" enum { DEBUG_FILE = true, FILE_COPY_BUFFER_SIZE = (8 * 1024) }; static int fileFdCount = 0; bool file_copy(int self, int copy) { int readsize; int writtensize; char buffer[FILE_COPY_BUFFER_SIZE]; assert(fd_isopen(self)); assert(fd_isopen(copy)); while(true) { readsize = read(self, buffer, FILE_COPY_BUFFER_SIZE); if(readsize == 0) { return true; } if(readsize < 0) { ERROR(DEBUG_FILE, "file_copy_fd error reading"); return false; } writtensize = write(copy, buffer, readsize); if(writtensize != readsize) { ERROR(DEBUG_FILE, "file_copy_fd error writing file"); return false; } } assert(false); /* impossible to get here */ return false; } int file_create(char *self, int omode, ulong perm) { int result; assert_valid(self); result = create(self, omode, perm); if(DEBUG_FILE && fd_isopen(result)) { ++fileFdCount; NOISE(DEBUG_FILE, "file_create active open: %d path: %s omode: %d perm: %uo fd: %d", fileFdCount, self, omode, perm, result); } return result; } int file_open(char *self, int omode) { int result; assert_valid(self); result = open(self, omode); if(DEBUG_FILE && fd_isopen(result)) { ++fileFdCount; NOISE(DEBUG_FILE, "file_open active open: %d path: %s omode: %d fd: %d", fileFdCount, self, omode, result); } return result; } void file_close(int self) { if(DEBUG_FILE && fd_isopen(self)) { --fileFdCount; NOISE(DEBUG_FILE, "file_close active open: %d fd: %d", fileFdCount, self); } close(self); } bool file_access(char *self, int mode) { assert_valid(self); return access(self, mode) != -1; } bool file_exists(char *self) { return file_access(self, AEXIST); } bool file_mkdir(char *self) { int fd; assert_valid(self); fd = file_create(self, OREAD, DMDIR | 0777L); if(!fd_isopen(fd)) { return false; } file_close(fd); return true; } /** * create any parent directory in order to create the whole restpath directory. * restpath is being modified to null out each slash while currentpath is kept * being appended. */ bool file_recursive_mkdir(String *currentpath, char *restpath) { char *slash; assert_valid(currentpath); assert_valid(restpath); NOISE(DEBUG_FILE, "entering file_recursive_mkdir with current: %s rest: %s", s_to_c(currentpath), restpath); if(*restpath == '\0') { NOISE(DEBUG_FILE, "file_recursive_mkdir done"); return true; } slash = string_nullify_if_found(restpath, '/'); filepath_append(¤tpath, restpath); if(!file_exists(s_to_c(currentpath)) && !file_mkdir(s_to_c(currentpath))) { ERROR(DEBUG_FILE, "file_recursive_mkdir failed to mkdir %s", s_to_c(currentpath)); return false; } restpath += strlen(restpath); restpath += (slash != nil) ? 1 : 0; return file_recursive_mkdir(currentpath, restpath); } bool file_relative_recursive_mkdir(char *path) { bool result; String *current = s_copy("."); assert_valid(path); result = file_recursive_mkdir(current, path); s_free(current); return result; } bool file_on_demand_mkdir(char *path) { bool result; char *restpath = estrdup_fs(path); assert_valid(path); if(restpath[0] == '/') { String *root = s_copy("/"); result = file_recursive_mkdir(root, restpath + 1); s_free(root); } else { result = file_relative_recursive_mkdir(restpath); } free(restpath); return result; } bool file_remove(char *self) { assert_valid(self); return remove(self) != -1; } bool file_dirwstat(char *self, Dir *d) { assert_valid(self); assert_valid(d); return dirwstat(self, d) != -1; } bool file_isdir(char *self) { Dir *d; assert_valid(self); d = dirstat(self); if(d != nil) { bool result = qid_isdir(&d->qid); free(d); return result; } return false; } long file_dir_file_count(char *self) { int fd; Dir *d; long result; assert_valid(self); fd = file_open(self, OREAD); if(!fd_isopen(fd)) { return -1; } result = dirreadall(fd, &d); free(d); close(fd); return result; } bool file_dir_notempty(char *self) { assert_valid(self); return file_isdir(self) && file_dir_file_count(self) > 0; } bool file_isdir_empty(char *self) { assert_valid(self); return !file_dir_notempty(self); }