static void test_Exists(TestBatch *batch) { Folder *folder = (Folder*)RAMFolder_new(NULL); FileHandle *fh; Folder_MkDir(folder, &foo); Folder_MkDir(folder, &foo_bar); fh = Folder_Open_FileHandle(folder, &boffo, FH_CREATE | FH_WRITE_ONLY); DECREF(fh); fh = Folder_Open_FileHandle(folder, &foo_boffo, FH_CREATE | FH_WRITE_ONLY); DECREF(fh); TEST_TRUE(batch, Folder_Exists(folder, &foo), "Dir exists"); TEST_TRUE(batch, Folder_Exists(folder, &boffo), "File exists"); TEST_TRUE(batch, Folder_Exists(folder, &foo_bar), "Nested dir exists"); TEST_TRUE(batch, Folder_Exists(folder, &foo_boffo), "Nested file exists"); TEST_FALSE(batch, Folder_Exists(folder, &banana), "Non-existent entry"); TEST_FALSE(batch, Folder_Exists(folder, &foo_foo), "Non-existent nested entry"); DECREF(folder); }
static void test_Open_Dir(TestBatch *batch) { Folder *folder = (Folder*)RAMFolder_new(NULL); DirHandle *dh; Folder_MkDir(folder, &foo); Folder_MkDir(folder, &foo_bar); dh = Folder_Open_Dir(folder, &foo); TEST_TRUE(batch, dh && DH_Is_A(dh, DIRHANDLE), "Open_Dir"); DECREF(dh); dh = Folder_Open_Dir(folder, &foo_bar); TEST_TRUE(batch, dh && DH_Is_A(dh, DIRHANDLE), "Open_Dir nested dir"); DECREF(dh); Err_set_error(NULL); dh = Folder_Open_Dir(folder, &bar); TEST_TRUE(batch, dh == NULL, "Open_Dir on non-existent entry fails"); TEST_TRUE(batch, Err_get_error() != NULL, "Open_Dir on non-existent entry sets Err_error"); Err_set_error(NULL); dh = Folder_Open_Dir(folder, &foo_foo); TEST_TRUE(batch, dh == NULL, "Open_Dir on non-existent nested entry fails"); TEST_TRUE(batch, Err_get_error() != NULL, "Open_Dir on non-existent nested entry sets Err_error"); DECREF(folder); }
static void test_Open_FileHandle(TestBatch *batch) { Folder *folder = (Folder*)RAMFolder_new(NULL); FileHandle *fh; Folder_MkDir(folder, &foo); fh = Folder_Open_FileHandle(folder, &boffo, FH_CREATE | FH_WRITE_ONLY); TEST_TRUE(batch, fh && FH_Is_A(fh, FILEHANDLE), "Open_FileHandle"); DECREF(fh); fh = Folder_Open_FileHandle(folder, &foo_boffo, FH_CREATE | FH_WRITE_ONLY); TEST_TRUE(batch, fh && FH_Is_A(fh, FILEHANDLE), "Open_FileHandle for nested file"); DECREF(fh); Err_set_error(NULL); fh = Folder_Open_FileHandle(folder, &foo, FH_CREATE | FH_WRITE_ONLY); TEST_TRUE(batch, fh == NULL, "Open_FileHandle on existing dir path fails"); TEST_TRUE(batch, Err_get_error() != NULL, "Open_FileHandle on existing dir name sets Err_error"); Err_set_error(NULL); fh = Folder_Open_FileHandle(folder, &foo_bar_baz_boffo, FH_CREATE | FH_WRITE_ONLY); TEST_TRUE(batch, fh == NULL, "Open_FileHandle for entry within non-existent dir fails"); TEST_TRUE(batch, Err_get_error() != NULL, "Open_FileHandle for entry within non-existent dir sets Err_error"); DECREF(folder); }
static void test_MkDir_and_Is_Directory(TestBatch *batch) { Folder *folder = (Folder*)RAMFolder_new(NULL); FileHandle *fh; TEST_FALSE(batch, Folder_Is_Directory(folder, &foo), "Is_Directory() false for non-existent entry"); TEST_TRUE(batch, Folder_MkDir(folder, &foo), "MkDir returns true on success"); TEST_TRUE(batch, Folder_Is_Directory(folder, &foo), "Is_Directory() true for local folder"); TEST_FALSE(batch, Folder_Is_Directory(folder, &foo_bar_baz), "Is_Directory() false for non-existent deeply nested dir"); Err_set_error(NULL); TEST_FALSE(batch, Folder_MkDir(folder, &foo_bar_baz), "MkDir for deeply nested dir fails"); TEST_TRUE(batch, Err_get_error() != NULL, "MkDir for deeply nested dir sets Err_error"); TEST_TRUE(batch, Folder_MkDir(folder, &foo_bar), "MkDir for nested dir"); TEST_TRUE(batch, Folder_Is_Directory(folder, &foo_bar), "Is_Directory() true for nested dir"); Err_set_error(NULL); TEST_FALSE(batch, Folder_MkDir(folder, &foo_bar), "Overwrite dir with MkDir fails"); TEST_TRUE(batch, Err_get_error() != NULL, "Overwrite dir with MkDir sets Err_error"); fh = Folder_Open_FileHandle(folder, &foo_boffo, FH_CREATE | FH_WRITE_ONLY); DECREF(fh); Err_set_error(NULL); TEST_FALSE(batch, Folder_MkDir(folder, &foo_boffo), "Overwrite file with MkDir fails"); TEST_TRUE(batch, Err_get_error() != NULL, "Overwrite file with MkDir sets Err_error"); TEST_FALSE(batch, Folder_Is_Directory(folder, &foo_boffo), "Is_Directory() false for nested file"); DECREF(folder); }
static void test_Open_In(TestBatch *batch) { Folder *folder = (Folder*)RAMFolder_new(NULL); FileHandle *fh; InStream *instream; Folder_MkDir(folder, &foo); Folder_MkDir(folder, &foo_bar); fh = Folder_Open_FileHandle(folder, &boffo, FH_CREATE | FH_WRITE_ONLY); DECREF(fh); fh = Folder_Open_FileHandle(folder, &foo_boffo, FH_CREATE | FH_WRITE_ONLY); DECREF(fh); instream = Folder_Open_In(folder, &boffo); TEST_TRUE(batch, instream && InStream_Is_A(instream, INSTREAM), "Open_In"); DECREF(instream); instream = Folder_Open_In(folder, &foo_boffo); TEST_TRUE(batch, instream && InStream_Is_A(instream, INSTREAM), "Open_In for nested file"); DECREF(instream); Err_set_error(NULL); instream = Folder_Open_In(folder, &foo); TEST_TRUE(batch, instream == NULL, "Open_InStream on existing dir path fails"); TEST_TRUE(batch, Err_get_error() != NULL, "Open_In on existing dir name sets Err_error"); Err_set_error(NULL); instream = Folder_Open_In(folder, &foo_bar_baz_boffo); TEST_TRUE(batch, instream == NULL, "Open_In for entry within non-existent dir fails"); TEST_TRUE(batch, Err_get_error() != NULL, "Open_In for entry within non-existent dir sets Err_error"); DECREF(folder); }
static void test_Delete_Tree(TestBatch *batch) { Folder *folder = (Folder*)RAMFolder_new(NULL); FileHandle *fh; bool_t result; // Create tree to be deleted. 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); DECREF(fh); // Create bystanders. Folder_MkDir(folder, &bar); fh = Folder_Open_FileHandle(folder, &baz, FH_CREATE | FH_WRITE_ONLY); DECREF(fh); result = Folder_Delete_Tree(folder, &foo); TEST_TRUE(batch, result, "Delete_Tree() succeeded"); TEST_FALSE(batch, Folder_Exists(folder, &foo), "Tree really gone"); TEST_TRUE(batch, Folder_Exists(folder, &bar), "local dir with same name as nested dir left intact"); TEST_TRUE(batch, Folder_Exists(folder, &baz), "local file with same name as nested dir left intact"); // Kill off the bystanders. result = Folder_Delete_Tree(folder, &bar); TEST_TRUE(batch, result, "Delete_Tree() on empty dir"); result = Folder_Delete_Tree(folder, &baz); TEST_TRUE(batch, result, "Delete_Tree() on file"); // Create new tree to be deleted. 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); DECREF(fh); // Remove tree in subdir. result = Folder_Delete_Tree(folder, &foo_bar); TEST_TRUE(batch, result, "Delete_Tree() of subdir succeeded"); TEST_FALSE(batch, Folder_Exists(folder, &foo_bar), "subdir really gone"); TEST_TRUE(batch, Folder_Exists(folder, &foo), "enclosing dir left intact"); DECREF(folder); }
static void test_List(TestBatch *batch) { Folder *folder = (Folder*)RAMFolder_new(NULL); FileHandle *fh; VArray *list; CharBuf *elem; Folder_MkDir(folder, &foo); Folder_MkDir(folder, &foo_bar); Folder_MkDir(folder, &foo_bar_baz); fh = Folder_Open_FileHandle(folder, &boffo, FH_CREATE | FH_WRITE_ONLY); DECREF(fh); fh = Folder_Open_FileHandle(folder, &banana, FH_CREATE | FH_WRITE_ONLY); DECREF(fh); list = Folder_List(folder, NULL); VA_Sort(list, NULL, NULL); TEST_INT_EQ(batch, VA_Get_Size(list), 3, "List"); elem = (CharBuf*)DOWNCAST(VA_Fetch(list, 0), CHARBUF); TEST_TRUE(batch, elem && CB_Equals(elem, (Obj*)&banana), "List first file"); elem = (CharBuf*)DOWNCAST(VA_Fetch(list, 1), CHARBUF); TEST_TRUE(batch, elem && CB_Equals(elem, (Obj*)&boffo), "List second file"); elem = (CharBuf*)DOWNCAST(VA_Fetch(list, 2), CHARBUF); TEST_TRUE(batch, elem && CB_Equals(elem, (Obj*)&foo), "List dir"); DECREF(list); list = Folder_List(folder, &foo_bar); TEST_INT_EQ(batch, VA_Get_Size(list), 1, "List subdirectory contents"); elem = (CharBuf*)DOWNCAST(VA_Fetch(list, 0), CHARBUF); TEST_TRUE(batch, elem && CB_Equals(elem, (Obj*)&baz), "Just the filename"); DECREF(list); DECREF(folder); }
static void test_Delete(TestBatch *batch) { Folder *folder = (Folder*)RAMFolder_new(NULL); FileHandle *fh; bool_t result; Folder_MkDir(folder, &foo); Folder_MkDir(folder, &foo_bar); fh = Folder_Open_FileHandle(folder, &boffo, FH_CREATE | FH_WRITE_ONLY); DECREF(fh); fh = Folder_Open_FileHandle(folder, &foo_boffo, FH_CREATE | FH_WRITE_ONLY); DECREF(fh); Err_set_error(NULL); result = Folder_Delete(folder, &banana); TEST_FALSE(batch, result, "Delete on non-existent entry returns false"); Err_set_error(NULL); result = Folder_Delete(folder, &foo); TEST_FALSE(batch, result, "Delete on non-empty dir returns false"); TEST_TRUE(batch, Folder_Delete(folder, &foo_boffo), "Delete nested file"); TEST_FALSE(batch, Folder_Exists(folder, &foo_boffo), "File is really gone"); TEST_TRUE(batch, Folder_Delete(folder, &foo_bar), "Delete nested dir"); TEST_FALSE(batch, Folder_Exists(folder, &foo_bar), "Dir is really gone"); TEST_TRUE(batch, Folder_Delete(folder, &foo), "Delete empty dir"); TEST_FALSE(batch, Folder_Exists(folder, &foo), "Dir is really gone"); DECREF(folder); }
void SegWriter_Prep_Seg_Dir_IMP(SegWriter *self) { SegWriterIVARS *const ivars = SegWriter_IVARS(self); Folder *folder = SegWriter_Get_Folder(self); String *seg_name = Seg_Get_Name(ivars->segment); // Clear stale segment files from crashed indexing sessions. if (Folder_Exists(folder, seg_name)) { bool result = Folder_Delete_Tree(folder, seg_name); if (!result) { THROW(ERR, "Couldn't completely remove '%o'", seg_name); } } // Create the segment directory. bool result = Folder_MkDir(folder, seg_name); if (!result) { RETHROW(INCREF(Err_get_error())); } }
bool Lock_make_lock_dir(Folder *folder) { String *lock_dir_name = SSTR_WRAP_C("locks"); if (!Folder_MkDir(folder, lock_dir_name)) { Err *err = (Err*)INCREF(Err_get_error()); // Maybe our attempt failed because another process succeeded. if (Folder_Find_Folder(folder, lock_dir_name)) { DECREF(err); } else { // Nope, everything failed, so bail out. Err_set_error(err); return false; } } return true; }
static void test_Open_Out(TestBatch *batch) { Folder *folder = (Folder*)RAMFolder_new(NULL); OutStream *outstream; Folder_MkDir(folder, &foo); outstream = Folder_Open_Out(folder, &boffo); TEST_TRUE(batch, outstream && OutStream_Is_A(outstream, OUTSTREAM), "Open_Out"); DECREF(outstream); outstream = Folder_Open_Out(folder, &foo_boffo); TEST_TRUE(batch, outstream && OutStream_Is_A(outstream, OUTSTREAM), "Open_Out for nested file"); DECREF(outstream); Err_set_error(NULL); outstream = Folder_Open_Out(folder, &boffo); TEST_TRUE(batch, outstream == NULL, "Open_OutStream on existing file fails"); TEST_TRUE(batch, Err_get_error() != NULL, "Open_Out on existing file sets Err_error"); Err_set_error(NULL); outstream = Folder_Open_Out(folder, &foo); TEST_TRUE(batch, outstream == NULL, "Open_OutStream on existing dir path fails"); TEST_TRUE(batch, Err_get_error() != NULL, "Open_Out on existing dir name sets Err_error"); Err_set_error(NULL); outstream = Folder_Open_Out(folder, &foo_bar_baz_boffo); TEST_TRUE(batch, outstream == NULL, "Open_Out for entry within non-existent dir fails"); TEST_TRUE(batch, Err_get_error() != NULL, "Open_Out for entry within non-existent dir sets Err_error"); DECREF(folder); }
bool_t LFLock_request(LockFileLock *self) { Hash *file_data; bool_t wrote_json; bool_t success = false; bool_t deletion_failed = false; if (Folder_Exists(self->folder, self->lock_path)) { Err_set_error((Err*)LockErr_new(CB_newf("Can't obtain lock: '%o' exists", self->lock_path))); return false; } // Create the "locks" subdirectory if necessary. CharBuf *lock_dir_name = (CharBuf*)ZCB_WRAP_STR("locks", 5); if (!Folder_Exists(self->folder, lock_dir_name)) { if (!Folder_MkDir(self->folder, lock_dir_name)) { Err *mkdir_err = (Err*)CERTIFY(Err_get_error(), ERR); LockErr *err = LockErr_new(CB_newf("Can't create 'locks' directory: %o", Err_Get_Mess(mkdir_err))); // Maybe our attempt failed because another process succeeded. if (Folder_Find_Folder(self->folder, lock_dir_name)) { DECREF(err); } else { // Nope, everything failed, so bail out. Err_set_error((Err*)err); return false; } } } // Prepare to write pid, lock name, and host to the lock file as JSON. file_data = Hash_new(3); Hash_Store_Str(file_data, "pid", 3, (Obj*)CB_newf("%i32", (int32_t)PID_getpid())); Hash_Store_Str(file_data, "host", 4, INCREF(self->host)); Hash_Store_Str(file_data, "name", 4, INCREF(self->name)); // Write to a temporary file, then use the creation of a hard link to // ensure atomic but non-destructive creation of the lockfile with its // complete contents. wrote_json = Json_spew_json((Obj*)file_data, self->folder, self->link_path); if (wrote_json) { success = Folder_Hard_Link(self->folder, self->link_path, self->lock_path); if (!success) { Err *hard_link_err = (Err*)CERTIFY(Err_get_error(), ERR); Err_set_error((Err*)LockErr_new(CB_newf("Failed to obtain lock at '%o': %o", self->lock_path, Err_Get_Mess(hard_link_err)))); } deletion_failed = !Folder_Delete(self->folder, self->link_path); } else { Err *spew_json_err = (Err*)CERTIFY(Err_get_error(), ERR); Err_set_error((Err*)LockErr_new(CB_newf("Failed to obtain lock at '%o': %o", self->lock_path, Err_Get_Mess(spew_json_err)))); } DECREF(file_data); // Verify that our temporary file got zapped. if (wrote_json && deletion_failed) { CharBuf *mess = MAKE_MESS("Failed to delete '%o'", self->link_path); Err_throw_mess(ERR, mess); } return success; }
bool LFLock_Request_IMP(LockFileLock *self) { LockFileLockIVARS *const ivars = LFLock_IVARS(self); bool success = false; if (Folder_Exists(ivars->folder, ivars->lock_path)) { Err_set_error((Err*)LockErr_new(Str_newf("Can't obtain lock: '%o' exists", ivars->lock_path))); return false; } // Create the "locks" subdirectory if necessary. String *lock_dir_name = (String*)SSTR_WRAP_UTF8("locks", 5); if (!Folder_Exists(ivars->folder, lock_dir_name)) { if (!Folder_MkDir(ivars->folder, lock_dir_name)) { Err *mkdir_err = (Err*)CERTIFY(Err_get_error(), ERR); LockErr *err = LockErr_new(Str_newf("Can't create 'locks' directory: %o", Err_Get_Mess(mkdir_err))); // Maybe our attempt failed because another process succeeded. if (Folder_Find_Folder(ivars->folder, lock_dir_name)) { DECREF(err); } else { // Nope, everything failed, so bail out. Err_set_error((Err*)err); return false; } } } // Prepare to write pid, lock name, and host to the lock file as JSON. Hash *file_data = Hash_new(3); Hash_Store_Utf8(file_data, "pid", 3, (Obj*)Str_newf("%i32", (int32_t)PID_getpid())); Hash_Store_Utf8(file_data, "host", 4, INCREF(ivars->host)); Hash_Store_Utf8(file_data, "name", 4, INCREF(ivars->name)); String *json = Json_to_json((Obj*)file_data); DECREF(file_data); // Write to a temporary file, then use the creation of a hard link to // ensure atomic but non-destructive creation of the lockfile with its // complete contents. OutStream *outstream = Folder_Open_Out(ivars->folder, ivars->link_path); if (!outstream) { ERR_ADD_FRAME(Err_get_error()); DECREF(json); return false; } struct lockfile_context context; context.outstream = outstream; context.json = json; Err *json_error = Err_trap(S_write_lockfile_json, &context); bool wrote_json = !json_error; DECREF(outstream); DECREF(json); if (wrote_json) { success = Folder_Hard_Link(ivars->folder, ivars->link_path, ivars->lock_path); if (!success) { Err *hard_link_err = (Err*)CERTIFY(Err_get_error(), ERR); Err_set_error((Err*)LockErr_new(Str_newf("Failed to obtain lock at '%o': %o", ivars->lock_path, Err_Get_Mess(hard_link_err)))); } } else { Err_set_error((Err*)LockErr_new(Str_newf("Failed to obtain lock at '%o': %o", ivars->lock_path, Err_Get_Mess(json_error)))); DECREF(json_error); } // Verify that our temporary file got zapped. bool deletion_failed = !Folder_Delete(ivars->folder, ivars->link_path); if (deletion_failed) { String *mess = MAKE_MESS("Failed to delete '%o'", ivars->link_path); Err_throw_mess(ERR, mess); } return success; }
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); }