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); } } }
Folder* RAMFolder_local_find_folder(RAMFolder *self, const CharBuf *path) { Folder *local_folder = (Folder*)Hash_Fetch(self->entries, (Obj*)path); if (local_folder && Folder_Is_A(local_folder, FOLDER)) { return local_folder; } return NULL; }
Folder* FSFolder_Local_Find_Folder_IMP(FSFolder *self, String *name) { FSFolderIVARS *const ivars = FSFolder_IVARS(self); Folder *subfolder = NULL; if (!name || !Str_Get_Size(name)) { // No entity can be identified by NULL or empty string. return NULL; } else if (!S_is_local_entry(name)) { return NULL; } else if (Str_Starts_With_Utf8(name, ".", 1)) { // Don't allow access outside of the main dir. return NULL; } else if (NULL != (subfolder = (Folder*)Hash_Fetch(ivars->entries, (Obj*)name))) { if (Folder_Is_A(subfolder, FOLDER)) { return subfolder; } else { return NULL; } } String *fullpath = S_fullpath(self, name); if (S_dir_ok(fullpath)) { subfolder = (Folder*)FSFolder_new(fullpath); if (!subfolder) { DECREF(fullpath); THROW(ERR, "Failed to open FSFolder at '%o'", fullpath); } // Try to open a CompoundFileReader. On failure, just use the // existing folder. String *cfmeta_file = (String*)SSTR_WRAP_UTF8("cfmeta.json", 11); if (Folder_Local_Exists(subfolder, cfmeta_file)) { CompoundFileReader *cf_reader = CFReader_open(subfolder); if (cf_reader) { DECREF(subfolder); subfolder = (Folder*)cf_reader; } } Hash_Store(ivars->entries, (Obj*)name, (Obj*)subfolder); } DECREF(fullpath); return subfolder; }
static bool_t S_rename_or_hard_link(RAMFolder *self, const CharBuf* from, const CharBuf *to, Folder *from_folder, Folder *to_folder, ZombieCharBuf *from_name, ZombieCharBuf *to_name, int op) { Obj *elem = NULL; RAMFolder *inner_from_folder = NULL; RAMFolder *inner_to_folder = NULL; UNUSED_VAR(self); // Make sure the source and destination folders exist. if (!from_folder) { Err_set_error(Err_new(CB_newf("File not found: '%o'", from))); return false; } if (!to_folder) { Err_set_error(Err_new(CB_newf( "Invalid file path (can't find dir): '%o'", to))); return false; } // Extract RAMFolders from compound reader wrappers, if necessary. if (Folder_Is_A(from_folder, COMPOUNDFILEREADER)) { inner_from_folder = (RAMFolder*)CFReader_Get_Real_Folder( (CompoundFileReader*)from_folder); } else { inner_from_folder = (RAMFolder*)from_folder; } if (Folder_Is_A(to_folder, COMPOUNDFILEREADER)) { inner_to_folder = (RAMFolder*)CFReader_Get_Real_Folder( (CompoundFileReader*)to_folder); } else { inner_to_folder = (RAMFolder*)to_folder; } if (!RAMFolder_Is_A(inner_from_folder, RAMFOLDER)) { Err_set_error(Err_new(CB_newf("Not a RAMFolder, but a '%o'", Obj_Get_Class_Name((Obj*)inner_from_folder)))); return false; } if (!RAMFolder_Is_A(inner_to_folder, RAMFOLDER)) { Err_set_error(Err_new(CB_newf("Not a RAMFolder, but a '%o'", Obj_Get_Class_Name((Obj*)inner_to_folder)))); return false; } // Find the original element. elem = Hash_Fetch(inner_from_folder->entries, (Obj*)from_name); if (!elem) { if ( Folder_Is_A(from_folder, COMPOUNDFILEREADER) && Folder_Local_Exists(from_folder, (CharBuf*)from_name) ) { Err_set_error(Err_new(CB_newf("Source file '%o' is virtual", from))); } else { Err_set_error(Err_new(CB_newf("File not found: '%o'", from))); } return false; } // Execute the rename/hard-link. if (op == OP_RENAME) { Obj *existing = Hash_Fetch(inner_to_folder->entries, (Obj*)to_name); if (existing) { bool_t conflict = false; // Return success fast if file is copied on top of itself. if ( inner_from_folder == inner_to_folder && ZCB_Equals(from_name, (Obj*)to_name) ) { return true; } // Don't allow clobbering of different entry type. if (Obj_Is_A(elem, RAMFILE)) { if (!Obj_Is_A(existing, RAMFILE)) { conflict = true; } } else if (Obj_Is_A(elem, FOLDER)) { if (!Obj_Is_A(existing, FOLDER)) { conflict = true; } } if (conflict) { Err_set_error(Err_new(CB_newf("Can't clobber a %o with a %o", Obj_Get_Class_Name(existing), Obj_Get_Class_Name(elem)))); return false; } } // Perform the store first, then the delete. Inform Folder objects // about the relocation. Hash_Store(inner_to_folder->entries, (Obj*)to_name, INCREF(elem)); DECREF(Hash_Delete(inner_from_folder->entries, (Obj*)from_name)); if (Obj_Is_A(elem, FOLDER)) { CharBuf *newpath = S_fullpath(inner_to_folder, (CharBuf*)to_name); Folder_Set_Path((Folder*)elem, newpath); DECREF(newpath); } } else if (op == OP_HARD_LINK) { if (!Obj_Is_A(elem, RAMFILE)) { Err_set_error(Err_new(CB_newf("'%o' isn't a file, it's a %o", from, Obj_Get_Class_Name(elem)))); return false; } else { Obj *existing = Hash_Fetch(inner_to_folder->entries, (Obj*)to_name); if (existing) { Err_set_error(Err_new(CB_newf("'%o' already exists", to))); return false; } else { Hash_Store(inner_to_folder->entries, (Obj*)to_name, INCREF(elem)); } } } else { THROW(ERR, "Unexpected op: %i32", (int32_t)op); } return true; }
static void test_Enclosing_Folder_and_Find_Folder(TestBatch *batch) { Folder *folder = (Folder*)RAMFolder_new(NULL); FileHandle *fh; Folder_MkDir(folder, &foo); Folder_MkDir(folder, &foo_bar); Folder_MkDir(folder, &foo_bar_baz); fh = Folder_Open_FileHandle(folder, &foo_bar_baz_boffo, FH_CREATE | FH_WRITE_ONLY); { Folder *encloser = Folder_Enclosing_Folder(folder, (CharBuf*)&nope); Folder *found = Folder_Find_Folder(folder, (CharBuf*)&nope); TEST_TRUE(batch, encloser == folder, "Enclosing_Folder() - non-existent entry yields parent"); TEST_TRUE(batch, found == NULL, "Find_Folder() - non-existent entry yields NULL"); } { Folder *encloser = Folder_Enclosing_Folder(folder, &foo_bar); Folder *found = Folder_Find_Folder(folder, &foo_bar); TEST_TRUE(batch, encloser && Folder_Is_A(encloser, FOLDER) && CB_Ends_With(Folder_Get_Path(encloser), &foo), "Enclosing_Folder() - find one directory down"); TEST_TRUE(batch, found && Folder_Is_A(found, FOLDER) && CB_Ends_With(Folder_Get_Path(found), &bar), "Find_Folder() - 'foo/bar'"); } { Folder *encloser = Folder_Enclosing_Folder(folder, &foo_bar_baz); Folder *found = Folder_Find_Folder(folder, &foo_bar_baz); TEST_TRUE(batch, encloser && Folder_Is_A(encloser, FOLDER) && CB_Ends_With(Folder_Get_Path(encloser), &bar), "Find two directories down"); TEST_TRUE(batch, found && Folder_Is_A(found, FOLDER) && CB_Ends_With(Folder_Get_Path(found), &baz), "Find_Folder() - 'foo/bar/baz'"); } { Folder *encloser = Folder_Enclosing_Folder(folder, &foo_bar_baz_boffo); Folder *found = Folder_Find_Folder(folder, &foo_bar_baz_boffo); TEST_TRUE(batch, encloser && Folder_Is_A(encloser, FOLDER) && CB_Ends_With(Folder_Get_Path(encloser), &baz), "Recurse to find a directory containing a real file"); TEST_TRUE(batch, found == NULL, "Find_Folder() - file instead of folder yields NULL"); } DECREF(fh); DECREF(folder); }