bool_t RAMFolder_hard_link(RAMFolder *self, const CharBuf *from, const CharBuf *to) { Folder *from_folder = RAMFolder_Enclosing_Folder(self, from); Folder *to_folder = RAMFolder_Enclosing_Folder(self, to); ZombieCharBuf *from_name = IxFileNames_local_part(from, ZCB_BLANK()); ZombieCharBuf *to_name = IxFileNames_local_part(to, ZCB_BLANK()); bool_t result = S_rename_or_hard_link(self, from, to, from_folder, to_folder, from_name, to_name, OP_HARD_LINK); if (!result) { ERR_ADD_FRAME(Err_get_error()); } return result; }
void Folder_consolidate(Folder *self, const CharBuf *path) { Folder *folder = Folder_Find_Folder(self, path); Folder *enclosing_folder = Folder_Enclosing_Folder(self, path); if (!folder) { THROW(ERR, "Can't consolidate %o", path); } else if (Folder_Is_A(folder, COMPOUNDFILEREADER)) { THROW(ERR, "Can't consolidate %o twice", path); } else { CompoundFileWriter *cf_writer = CFWriter_new(folder); CFWriter_Consolidate(cf_writer); DECREF(cf_writer); if (CB_Get_Size(path)) { ZombieCharBuf *name = IxFileNames_local_part(path, ZCB_BLANK()); CompoundFileReader *cf_reader = CFReader_open(folder); if (!cf_reader) { RETHROW(INCREF(Err_get_error())); } Hash_Store(enclosing_folder->entries, (Obj*)name, (Obj*)cf_reader); } } }
static void S_test_local_part(TestBatchRunner *runner, const char *source, const char *wanted, const char *test_name) { StackString *source_str = SSTR_WRAP_UTF8(source, strlen(source)); String *got = IxFileNames_local_part((String*)source_str); TEST_TRUE(runner, Str_Equals_Utf8(got, wanted, strlen(wanted)), test_name); DECREF(got); }
bool Folder_is_directory(Folder *self, const CharBuf *path) { Folder *enclosing_folder = Folder_Enclosing_Folder(self, path); bool retval = false; if (enclosing_folder) { ZombieCharBuf *name = IxFileNames_local_part(path, ZCB_BLANK()); if (Folder_Local_Is_Directory(enclosing_folder, (CharBuf*)name)) { retval = true; } } return retval; }
bool Folder_delete(Folder *self, const CharBuf *path) { Folder *enclosing_folder = Folder_Enclosing_Folder(self, path); if (enclosing_folder) { ZombieCharBuf *name = IxFileNames_local_part(path, ZCB_BLANK()); bool result = Folder_Local_Delete(enclosing_folder, (CharBuf*)name); return result; } else { return false; } }
bool_t Folder_exists(Folder *self, const CharBuf *path) { Folder *enclosing_folder = Folder_Enclosing_Folder(self, path); bool_t retval = false; if (enclosing_folder) { ZombieCharBuf *name = IxFileNames_local_part(path, ZCB_BLANK()); if (Folder_Local_Exists(enclosing_folder, (CharBuf*)name)) { retval = true; } } return retval; }
bool_t Folder_delete_tree(Folder *self, const CharBuf *path) { Folder *enclosing_folder = Folder_Enclosing_Folder(self, path); // Don't allow Folder to delete itself. if (!path || !CB_Get_Size(path)) { return false; } if (enclosing_folder) { ZombieCharBuf *local = IxFileNames_local_part(path, ZCB_BLANK()); if (Folder_Local_Is_Directory(enclosing_folder, (CharBuf*)local)) { Folder *inner_folder = Folder_Local_Find_Folder(enclosing_folder, (CharBuf*)local); DirHandle *dh = Folder_Local_Open_Dir(inner_folder); if (dh) { VArray *files = VA_new(20); VArray *dirs = VA_new(20); CharBuf *entry = DH_Get_Entry(dh); while (DH_Next(dh)) { VA_Push(files, (Obj*)CB_Clone(entry)); if (DH_Entry_Is_Dir(dh) && !DH_Entry_Is_Symlink(dh)) { VA_Push(dirs, (Obj*)CB_Clone(entry)); } } for (uint32_t i = 0, max = VA_Get_Size(dirs); i < max; i++) { CharBuf *name = (CharBuf*)VA_Fetch(files, i); bool_t success = Folder_Delete_Tree(inner_folder, name); if (!success && Folder_Local_Exists(inner_folder, name)) { break; } } for (uint32_t i = 0, max = VA_Get_Size(files); i < max; i++) { CharBuf *name = (CharBuf*)VA_Fetch(files, i); bool_t success = Folder_Local_Delete(inner_folder, name); if (!success && Folder_Local_Exists(inner_folder, name)) { break; } } DECREF(dirs); DECREF(files); DECREF(dh); } } return Folder_Local_Delete(enclosing_folder, (CharBuf*)local); } else { // Return failure if the entry wasn't there in the first place. return false; } }
InStream* Folder_open_in(Folder *self, const CharBuf *path) { Folder *enclosing_folder = Folder_Enclosing_Folder(self, path); InStream *instream = NULL; if (enclosing_folder) { ZombieCharBuf *name = IxFileNames_local_part(path, ZCB_BLANK()); instream = Folder_Local_Open_In(enclosing_folder, (CharBuf*)name); if (!instream) { ERR_ADD_FRAME(Err_get_error()); } } else { Err_set_error(Err_new(CB_newf("Invalid path: '%o'", path))); } return instream; }
FileHandle* Folder_open_filehandle(Folder *self, const CharBuf *path, uint32_t flags) { Folder *enclosing_folder = Folder_Enclosing_Folder(self, path); FileHandle *fh = NULL; if (enclosing_folder) { ZombieCharBuf *name = IxFileNames_local_part(path, ZCB_BLANK()); fh = Folder_Local_Open_FileHandle(enclosing_folder, (CharBuf*)name, flags); if (!fh) { ERR_ADD_FRAME(Err_get_error()); } } else { Err_set_error(Err_new(CB_newf("Invalid path: '%o'", path))); } return fh; }
bool Folder_mkdir(Folder *self, const CharBuf *path) { Folder *enclosing_folder = Folder_Enclosing_Folder(self, path); bool result = false; if (!CB_Get_Size(path)) { Err_set_error(Err_new(CB_newf("Invalid path: '%o'", path))); } else if (!enclosing_folder) { Err_set_error(Err_new(CB_newf("Can't recursively create dir %o", path))); } else { ZombieCharBuf *name = IxFileNames_local_part(path, ZCB_BLANK()); result = Folder_Local_MkDir(enclosing_folder, (CharBuf*)name); if (!result) { ERR_ADD_FRAME(Err_get_error()); } } return result; }
CompoundFileReader* CFReader_do_open(CompoundFileReader *self, Folder *folder) { CompoundFileReaderIVARS *const ivars = CFReader_IVARS(self); String *cfmeta_file = (String*)SSTR_WRAP_UTF8("cfmeta.json", 11); Hash *metadata = (Hash*)Json_slurp_json((Folder*)folder, cfmeta_file); Err *error = NULL; Folder_init((Folder*)self, Folder_Get_Path(folder)); // Parse metadata file. if (!metadata || !Hash_Is_A(metadata, HASH)) { error = Err_new(Str_newf("Can't read '%o' in '%o'", cfmeta_file, Folder_Get_Path(folder))); } else { Obj *format = Hash_Fetch_Utf8(metadata, "format", 6); ivars->format = format ? (int32_t)Obj_To_I64(format) : 0; ivars->records = (Hash*)INCREF(Hash_Fetch_Utf8(metadata, "files", 5)); if (ivars->format < 1) { error = Err_new(Str_newf("Corrupt %o file: Missing or invalid 'format'", cfmeta_file)); } else if (ivars->format > CFWriter_current_file_format) { error = Err_new(Str_newf("Unsupported compound file format: %i32 " "(current = %i32", ivars->format, CFWriter_current_file_format)); } else if (!ivars->records) { error = Err_new(Str_newf("Corrupt %o file: missing 'files' key", cfmeta_file)); } } DECREF(metadata); if (error) { Err_set_error(error); DECREF(self); return NULL; } // Open an instream which we'll clone over and over. String *cf_file = (String*)SSTR_WRAP_UTF8("cf.dat", 6); ivars->instream = Folder_Open_In(folder, cf_file); if (!ivars->instream) { ERR_ADD_FRAME(Err_get_error()); DECREF(self); return NULL; } // Assign. ivars->real_folder = (Folder*)INCREF(folder); // Strip directory name from filepaths for old format. if (ivars->format == 1) { Vector *files = Hash_Keys(ivars->records); String *folder_name = IxFileNames_local_part(Folder_Get_Path(folder)); size_t folder_name_len = Str_Length(folder_name); for (uint32_t i = 0, max = Vec_Get_Size(files); i < max; i++) { String *orig = (String*)Vec_Fetch(files, i); if (Str_Starts_With(orig, folder_name)) { Obj *record = Hash_Delete(ivars->records, orig); size_t offset = folder_name_len + sizeof(CHY_DIR_SEP) - 1; size_t len = Str_Length(orig) - offset; String *filename = Str_SubString(orig, offset, len); Hash_Store(ivars->records, filename, (Obj*)record); DECREF(filename); } } DECREF(folder_name); DECREF(files); } return self; }
CompoundFileReader* CFReader_do_open(CompoundFileReader *self, Folder *folder) { CharBuf *cfmeta_file = (CharBuf*)ZCB_WRAP_STR("cfmeta.json", 11); Hash *metadata = (Hash*)Json_slurp_json((Folder*)folder, cfmeta_file); Err *error = NULL; Folder_init((Folder*)self, Folder_Get_Path(folder)); // Parse metadata file. if (!metadata || !Hash_Is_A(metadata, HASH)) { error = Err_new(CB_newf("Can't read '%o' in '%o'", cfmeta_file, Folder_Get_Path(folder))); } else { Obj *format = Hash_Fetch_Str(metadata, "format", 6); self->format = format ? (int32_t)Obj_To_I64(format) : 0; self->records = (Hash*)INCREF(Hash_Fetch_Str(metadata, "files", 5)); if (self->format < 1) { error = Err_new(CB_newf("Corrupt %o file: Missing or invalid 'format'", cfmeta_file)); } else if (self->format > CFWriter_current_file_format) { error = Err_new(CB_newf("Unsupported compound file format: %i32 " "(current = %i32", self->format, CFWriter_current_file_format)); } else if (!self->records) { error = Err_new(CB_newf("Corrupt %o file: missing 'files' key", cfmeta_file)); } } DECREF(metadata); if (error) { Err_set_error(error); DECREF(self); return NULL; } // Open an instream which we'll clone over and over. CharBuf *cf_file = (CharBuf*)ZCB_WRAP_STR("cf.dat", 6); self->instream = Folder_Open_In(folder, cf_file); if (!self->instream) { ERR_ADD_FRAME(Err_get_error()); DECREF(self); return NULL; } // Assign. self->real_folder = (Folder*)INCREF(folder); // Strip directory name from filepaths for old format. if (self->format == 1) { VArray *files = Hash_Keys(self->records); ZombieCharBuf *filename = ZCB_BLANK(); ZombieCharBuf *folder_name = IxFileNames_local_part(Folder_Get_Path(folder), ZCB_BLANK()); size_t folder_name_len = ZCB_Length(folder_name); for (uint32_t i = 0, max = VA_Get_Size(files); i < max; i++) { CharBuf *orig = (CharBuf*)VA_Fetch(files, i); if (CB_Starts_With(orig, (CharBuf*)folder_name)) { Obj *record = Hash_Delete(self->records, (Obj*)orig); ZCB_Assign(filename, orig); ZCB_Nip(filename, folder_name_len + sizeof(DIR_SEP) - 1); Hash_Store(self->records, (Obj*)filename, (Obj*)record); } } DECREF(files); } return self; }