bool CFReader_Local_Delete_IMP(CompoundFileReader *self, String *name) { CompoundFileReaderIVARS *const ivars = CFReader_IVARS(self); Hash *record = (Hash*)Hash_Delete(ivars->records, name); DECREF(record); if (record == NULL) { return Folder_Local_Delete(ivars->real_folder, name); } else { // Once the number of virtual files falls to 0, remove the compound // files. if (Hash_Get_Size(ivars->records) == 0) { String *cf_file = (String*)SSTR_WRAP_UTF8("cf.dat", 6); if (!Folder_Delete(ivars->real_folder, cf_file)) { return false; } String *cfmeta_file = (String*)SSTR_WRAP_UTF8("cfmeta.json", 11); if (!Folder_Delete(ivars->real_folder, cfmeta_file)) { return false; } } return true; } }
static void Layer_Remove(int victim) { LayerPtr layer = (LayerPtr)Hash_Delete(layer_hash, victim); int index; Widget temp; int i; for ( index = 0 ; layer_list_map[index] != victim ; index++ ); free(layer->instances); free(layer->name); free(layer); temp = layer_toggles[index]; XtUnmanageChild(temp); for ( i = index + 1; i < num_layers ; i++ ) { layer_name_list[i-1] = layer_name_list[i]; layer_list_map[i-1] = layer_list_map[i]; layer_toggles[i-1] = layer_toggles[i]; } num_layers--; layer_toggles[num_layers] = temp; XawListChange(layer_list_widget, layer_name_list, num_layers, 0, TRUE); }
bool_t CFReader_local_delete(CompoundFileReader *self, const CharBuf *name) { Hash *record = (Hash*)Hash_Delete(self->records, (Obj*)name); DECREF(record); if (record == NULL) { return Folder_Local_Delete(self->real_folder, name); } else { // Once the number of virtual files falls to 0, remove the compound // files. if (Hash_Get_Size(self->records) == 0) { CharBuf *cf_file = (CharBuf*)ZCB_WRAP_STR("cf.dat", 6); if (!Folder_Delete(self->real_folder, cf_file)) { return false; } CharBuf *cfmeta_file = (CharBuf*)ZCB_WRAP_STR("cfmeta.json", 11); if (!Folder_Delete(self->real_folder, cfmeta_file)) { return false; } } return true; } }
bool_t RAMFolder_local_delete(RAMFolder *self, const CharBuf *name) { Obj *entry = Hash_Fetch(self->entries, (Obj*)name); if (entry) { if (Obj_Is_A(entry, RAMFILE)) { ; } else if (Obj_Is_A(entry, FOLDER)) { RAMFolder *inner_folder; if (Obj_Is_A(entry, COMPOUNDFILEREADER)) { inner_folder = (RAMFolder*)CERTIFY( CFReader_Get_Real_Folder((CompoundFileReader*)entry), RAMFOLDER); } else { inner_folder = (RAMFolder*)CERTIFY(entry, RAMFOLDER); } if (Hash_Get_Size(inner_folder->entries)) { // Can't delete non-empty dir. return false; } } else { return false; } DECREF(Hash_Delete(self->entries, (Obj*)name)); return true; } else { return false; } }
bool_t RAMFolder_delete(RAMFolder *self, const CharBuf *filepath) { RAMFileDes *file_des = (RAMFileDes*)Hash_Delete(self->elems, filepath); if (file_des) { RAMFileDes_Dec_RefCount(file_des); } return !!file_des; }
/* Gets the best node from OpenList * returns the best node, or NULL of none is found * Also it deletes the node from the OpenList */ static OpenListNode *AyStarMain_OpenList_Pop(AyStar *aystar) { /* Return the item the Queue returns.. the best next OpenList item. */ OpenListNode *res = (OpenListNode*)aystar->OpenListQueue.pop(&aystar->OpenListQueue); if (res != NULL) { Hash_Delete(&aystar->OpenListHash, res->path.node.tile, res->path.node.direction); } return res; }
bool_t Snapshot_delete_entry(Snapshot *self, const CharBuf *entry) { Obj *val = Hash_Delete(self->entries, entry); if (val) { Obj_Dec_RefCount(val); return true; } else { return false; } }
bool Snapshot_Delete_Entry_IMP(Snapshot *self, String *entry) { SnapshotIVARS *const ivars = Snapshot_IVARS(self); Obj *val = Hash_Delete(ivars->entries, entry); if (val) { DECREF(val); return true; } else { return false; } }
void RAMFolder_rename(RAMFolder *self, const CharBuf* from, const CharBuf *to) { RAMFileDes *file_des = (RAMFileDes*)Hash_Delete(self->elems, from); if (file_des == NULL) { THROW("File '%o' not loaded into RAM", from); } Hash_Store(self->elems, to, (Obj*)file_des); FileDes_Set_Path(file_des, to); }
bool FSFolder_Local_Delete_IMP(FSFolder *self, String *name) { FSFolderIVARS *const ivars = FSFolder_IVARS(self); char *path_ptr = S_fullpath_ptr(self, name); #ifdef CHY_REMOVE_ZAPS_DIRS bool result = !remove(path_ptr); #else bool result = !rmdir(path_ptr) || !remove(path_ptr); #endif DECREF(Hash_Delete(ivars->entries, (Obj*)name)); FREEMEM(path_ptr); return result; }
void* thread_code(void *arg) { struct hash_job_desc *jd = (struct hash_job_desc *) arg; int numOfOps = NUM_OPS_PER_THREAD; int i = 0; int *addlist = malloc(sizeof(int) * numOfOps); if (addlist == NULL) { printf(" cannot allocate more ..., reduce space \n"); exit(-1); } while (i < numOfOps) { // addlist[i] = rand() % (numOfOps * num_threads); // since key is unique... addlist[i] = i + (numOfOps * jd->tid); Hash_Insert(&h, addlist + i, addlist[i]); (jd->ic)++; i++; } i = 0; while (i < numOfOps) { if (i % 3 == 0) { Hash_Delete(&h, addlist[i]); (jd->dc)++; } i++; } i = 0; while (i < numOfOps) { if (Hash_Lookup(&h, addlist[i]) != NULL) (jd->lc)++; i++; } // printf(" END Thread-%04d with %6d ic, %6d dc, %6d lc\n", // jd->tid, jd->ic, jd->dc, jd->lc); free(addlist); return NULL; }
int main () { FILE* the_table = fopen ("the_table.csv", "w"); FILE* the_text = fopen ("the_text.txt", "r"); assert (the_log); assert (the_table); assert (the_text); hash* the_hash = Hash_NEW(); assert (the_hash); char word[MAXLEN] = {}; int nWords = 0; typedef unsigned int (*hash_funcs) (const char* my_key); hash_funcs hf[5] = {hf0, hf1, hf2, hf3, hf4}; int func_num = 0; char text_description[2 * MAXLEN] = {}; strcpy (text_description, "Bradbury's novel \"Fahrenheit 451\""); OUT printf ("# This program allows to use hash-functions for sorting\n" "# words in %s\n" "# The developer: Yura Gorishniy <*****@*****.**>\n" "# Version 1.00\n" "# The file: %s\n" "# The compilation time: %s, %s\n\n", text_description, strrchr (__FILE__, '\\'), __DATE__, __TIME__); printf ("# You can use 5 hash-functions to analyse the novel:\n" "# Function [1] hash = 0\n" "# Function [2] hash = the ASCII code of the first letter of the word\n" "# Function [3] hash = the sum of ASCII codes of all letters of the word\n" "# Function [4] hash = the average ASCII code of all letters of the word\n" "# Function [5] hash = the number, which we get after right cyclic shift\n" "# P.S. All the hashes you get will be counted by module %d\n\n", HASH_SIZE); printf ("# Please, enter number of the function you want to use\n"); if (!scanf ("%d", &func_num)) { printf ("Incorrect input, try again\n"); abort (); } if (!(1 <= func_num && func_num <= 5)) { printf ("Incorrect input, try again\n"); abort (); } the_hash -> func = hf[func_num - 1]; while (1) { if (get_word (the_text, word) == 0) break; nWords++; int hash = the_hash -> func (word) % the_hash -> size; elem* new_elem = NULL; List_Elem_Find_Key (the_hash -> table[hash], word, &new_elem); if (!new_elem) List_Elem_Add (the_hash -> table[hash], word, 1); } for (int i = 0; i < HASH_SIZE; ++i) fprintf (the_table, "%d\n", the_hash -> table[i] -> length); Hash_Dump (the_hash); Hash_Delete (the_hash); fclose (the_text); fclose (the_table); fclose (the_log); printf ("\nThe job is done! \nYou can use the_table.csv in Microsoft Excel to get a nice diagram\nGoodbye!\n\n"); return 0; }
static void test_Store_and_Fetch(TestBatch *batch) { Hash *hash = Hash_new(100); Hash *dupe = Hash_new(100); const uint32_t starting_cap = Hash_Get_Capacity(hash); VArray *expected = VA_new(100); VArray *got = VA_new(100); ZombieCharBuf *twenty = ZCB_WRAP_STR("20", 2); ZombieCharBuf *forty = ZCB_WRAP_STR("40", 2); ZombieCharBuf *foo = ZCB_WRAP_STR("foo", 3); for (int32_t i = 0; i < 100; i++) { CharBuf *cb = CB_newf("%i32", i); Hash_Store(hash, (Obj*)cb, (Obj*)cb); Hash_Store(dupe, (Obj*)cb, INCREF(cb)); VA_Push(expected, INCREF(cb)); } TEST_TRUE(batch, Hash_Equals(hash, (Obj*)dupe), "Equals"); TEST_INT_EQ(batch, Hash_Get_Capacity(hash), starting_cap, "Initial capacity sufficient (no rebuilds)"); for (int32_t i = 0; i < 100; i++) { Obj *key = VA_Fetch(expected, i); Obj *elem = Hash_Fetch(hash, key); VA_Push(got, (Obj*)INCREF(elem)); } TEST_TRUE(batch, VA_Equals(got, (Obj*)expected), "basic Store and Fetch"); TEST_INT_EQ(batch, Hash_Get_Size(hash), 100, "size incremented properly by Hash_Store"); TEST_TRUE(batch, Hash_Fetch(hash, (Obj*)foo) == NULL, "Fetch against non-existent key returns NULL"); Hash_Store(hash, (Obj*)forty, INCREF(foo)); TEST_TRUE(batch, ZCB_Equals(foo, Hash_Fetch(hash, (Obj*)forty)), "Hash_Store replaces existing value"); TEST_FALSE(batch, Hash_Equals(hash, (Obj*)dupe), "replacement value spoils equals"); TEST_INT_EQ(batch, Hash_Get_Size(hash), 100, "size unaffected after value replaced"); TEST_TRUE(batch, Hash_Delete(hash, (Obj*)forty) == (Obj*)foo, "Delete returns value"); DECREF(foo); TEST_INT_EQ(batch, Hash_Get_Size(hash), 99, "size decremented by successful Delete"); TEST_TRUE(batch, Hash_Delete(hash, (Obj*)forty) == NULL, "Delete returns NULL when key not found"); TEST_INT_EQ(batch, Hash_Get_Size(hash), 99, "size not decremented by unsuccessful Delete"); DECREF(Hash_Delete(dupe, (Obj*)forty)); TEST_TRUE(batch, VA_Equals(got, (Obj*)expected), "Equals after Delete"); Hash_Clear(hash); TEST_TRUE(batch, Hash_Fetch(hash, (Obj*)twenty) == NULL, "Clear"); TEST_TRUE(batch, Hash_Get_Size(hash) == 0, "size is 0 after Clear"); DECREF(hash); DECREF(dupe); DECREF(got); DECREF(expected); }
int main() { pthread_t thread[3]; counter_t counter; printf("Testing Counter...\n"); printf("Begin single thread test\n"); printf("Counter Init\n"); Counter_Init(&counter, 0); printf("Counter_GetValue\n"); int counter_val = Counter_GetValue(&counter); printf("expected 0 got %d\n", counter_val); printf("Counter_Increment\n"); Counter_Increment(&counter); counter_val = counter_val = Counter_GetValue(&counter); printf("expected 1 got %d\n", counter_val); printf("Counter_Decrement\n"); Counter_Decrement(&counter); counter_val = Counter_GetValue(&counter); printf("expected 0 got %d\n", counter_val); printf("Begin multithreaded test\n"); printf("Counter Init\n"); Counter_Init(&counter, 0); pthread_create(&thread[0], NULL, Counter_Increment, (void*)&counter); printf("Counter is at %d after 1 increment call\n", Counter_GetValue(&counter)); pthread_create(&thread[1], NULL, Counter_Increment, (void*)&counter); printf("Counter is at %d after 2 increment calls\n", Counter_GetValue(&counter)); pthread_create(&thread[2], NULL, Counter_Increment, (void*)&counter); printf("Counter is at %d after 3 increment calls\n", Counter_GetValue(&counter)); pthread_join(thread[0], NULL); pthread_join(thread[1], NULL); pthread_join(thread[2], NULL); printf("Count after 3 threads = %d\n", Counter_GetValue(&counter)); printf("Done Testing Counter\n\n"); list_insert_arg insert_arg[3]; list_lookup_arg lookup_arg[3]; list_t list; printf("Testing list...\n"); printf("Begin single-thread test\n"); printf("List_Init()\n"); List_Init(&list); printf("List_Insert()\n"); List_Insert(&list, (void *)0x1, 1); List_Insert(&list, (void *)0x2, 2); List_Insert(&list, (void *)0x3, 3); printf("Expected %p got %p\n", (void *)0x1, List_Lookup(&list, 1)); printf("Expected %p got %p\n", (void *)0x3, List_Lookup(&list, 3)); printf("Expected %p got %p\n", (void *)0x2, List_Lookup(&list, 2)); printf("List_Delete()\n"); List_Delete(&list, 1); printf("Expected %p got %p\n", (void *)0x2, List_Lookup(&list, 2)); printf("Expected %p got %p\n", (void *)0x3, List_Lookup(&list, 3)); printf("Expected %p got %p\n", NULL, List_Lookup(&list, 1)); printf("Single-thread test completed\n"); printf("Begin multi-thread test\n"); printf("List_Init()\n"); List_Init(&list); printf("Parallel List_Insert()\n"); insert_arg[0].list = &list; insert_arg[0].element = (void *)0x1; insert_arg[0].key = 1; pthread_create(&thread[0], NULL, pthread_list_insert, &insert_arg[0]); insert_arg[1].list = &list; insert_arg[1].element = (void *)0x2; insert_arg[1].key = 2; pthread_create(&thread[1], NULL, pthread_list_insert, &insert_arg[1]); insert_arg[2].list = &list; insert_arg[2].element = (void *)0x3; insert_arg[2].key = 3; pthread_create(&thread[2], NULL, pthread_list_insert, &insert_arg[2]); pthread_join(thread[0], NULL); pthread_join(thread[1], NULL); pthread_join(thread[2], NULL); printf("Parallel List_Insert() completed\n"); printf("Parallel List_Lookup()\n"); lookup_arg[0].list = &list; lookup_arg[0].key = 1; pthread_create(&thread[0], NULL, pthread_list_lookup, &lookup_arg[0]); lookup_arg[1].list = &list; lookup_arg[1].key = 2; pthread_create(&thread[1], NULL, pthread_list_lookup, &lookup_arg[1]); lookup_arg[2].list = &list; lookup_arg[2].key = 3; pthread_create(&thread[2], NULL, pthread_list_lookup, &lookup_arg[2]); pthread_join(thread[0], NULL); pthread_join(thread[1], NULL); pthread_join(thread[2], NULL); printf("Parallel List_Lookup() completed\n"); printf("List_Delete()\n"); List_Delete(&list, 1); printf("Expected %p got %p\n", (void *)0x2, List_Lookup(&list, 2)); printf("Expected %p got %p\n", (void *)0x3, List_Lookup(&list, 3)); printf("Expected %p got %p\n", NULL, List_Lookup(&list, 1)); printf("Multi-thread test completed\n"); printf("Done testing list\n\n"); hash_t hash; printf("Testing hash...\n"); printf("Begin single-thread test\n"); printf("Hash_Init()\n"); Hash_Init(&hash, 2); printf("Hash_Insert()\n"); Hash_Insert(&hash, (void *)0x1, 1); Hash_Insert(&hash, (void *)0x2, 2); Hash_Insert(&hash, (void *)0x3, 3); printf("Hash_Lookup()\n"); printf("Expected %p got %p\n", (void *)0x2, Hash_Lookup(&hash, 2)); printf("Expected %p got %p\n", (void *)0x3, Hash_Lookup(&hash, 3)); printf("Expected %p got %p\n", (void *)0x1, Hash_Lookup(&hash, 1)); printf("Hash_Delete()\n"); Hash_Delete(&hash, 1); printf("Hash_Lookup()\n"); printf("Expected %p got %p\n", (void *)0x2, Hash_Lookup(&hash, 2)); printf("Expected %p got %p\n", (void *)0x3, Hash_Lookup(&hash, 3)); printf("Expected %p got %p\n", NULL, Hash_Lookup(&hash, 1)); printf("Single-thread test completed\n"); printf("Done testing hash...\n"); return 0; }
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; }
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; }
static void S_discover_unused(FilePurger *self, VArray **purgables_ptr, VArray **snapshots_ptr) { Folder *folder = self->folder; DirHandle *dh = Folder_Open_Dir(folder, NULL); if (!dh) { RETHROW(INCREF(Err_get_error())); } VArray *spared = VA_new(1); VArray *snapshots = VA_new(1); CharBuf *snapfile = NULL; // Start off with the list of files in the current snapshot. if (self->snapshot) { VArray *entries = Snapshot_List(self->snapshot); VArray *referenced = S_find_all_referenced(folder, entries); VA_Push_VArray(spared, referenced); DECREF(entries); DECREF(referenced); snapfile = Snapshot_Get_Path(self->snapshot); if (snapfile) { VA_Push(spared, INCREF(snapfile)); } } CharBuf *entry = DH_Get_Entry(dh); Hash *candidates = Hash_new(64); while (DH_Next(dh)) { if (!CB_Starts_With_Str(entry, "snapshot_", 9)) { continue; } else if (!CB_Ends_With_Str(entry, ".json", 5)) { continue; } else if (snapfile && CB_Equals(entry, (Obj*)snapfile)) { continue; } else { Snapshot *snapshot = Snapshot_Read_File(Snapshot_new(), folder, entry); Lock *lock = IxManager_Make_Snapshot_Read_Lock(self->manager, entry); VArray *snap_list = Snapshot_List(snapshot); VArray *referenced = S_find_all_referenced(folder, snap_list); // DON'T obtain the lock -- only see whether another // entity holds a lock on the snapshot file. if (lock) { Lock_Clear_Stale(lock); } if (lock && Lock_Is_Locked(lock)) { // The snapshot file is locked, which means someone's using // that version of the index -- protect all of its entries. uint32_t new_size = VA_Get_Size(spared) + VA_Get_Size(referenced) + 1; VA_Grow(spared, new_size); VA_Push(spared, (Obj*)CB_Clone(entry)); VA_Push_VArray(spared, referenced); } else { // No one's using this snapshot, so all of its entries are // candidates for deletion. for (uint32_t i = 0, max = VA_Get_Size(referenced); i < max; i++) { CharBuf *file = (CharBuf*)VA_Fetch(referenced, i); Hash_Store(candidates, (Obj*)file, INCREF(&EMPTY)); } VA_Push(snapshots, INCREF(snapshot)); } DECREF(referenced); DECREF(snap_list); DECREF(snapshot); DECREF(lock); } } DECREF(dh); // Clean up after a dead segment consolidation. S_zap_dead_merge(self, candidates); // Eliminate any current files from the list of files to be purged. for (uint32_t i = 0, max = VA_Get_Size(spared); i < max; i++) { CharBuf *filename = (CharBuf*)VA_Fetch(spared, i); DECREF(Hash_Delete(candidates, (Obj*)filename)); } // Pass back purgables and Snapshots. *purgables_ptr = Hash_Keys(candidates); *snapshots_ptr = snapshots; DECREF(candidates); DECREF(spared); }
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; }