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; } }
bool CFReader_Local_Exists_IMP(CompoundFileReader *self, String *name) { CompoundFileReaderIVARS *const ivars = CFReader_IVARS(self); if (Hash_Fetch(ivars->records, name)) { return true; } if (Folder_Local_Exists(ivars->real_folder, name)) { return true; } return false; }
bool Folder_exists(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_Exists(enclosing_folder, (CharBuf*)name)) { retval = true; } } return retval; }
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; }
bool_t CFReader_local_exists(CompoundFileReader *self, const CharBuf *name) { if (Hash_Fetch(self->records, (Obj*)name)) { return true; } if (Folder_Local_Exists(self->real_folder, name)) { return true; } return false; }