Lock* Lock_init(Lock *self, Folder *folder, const CharBuf *name, const CharBuf *host, int32_t timeout, int32_t interval) { // Validate. if (interval <= 0) { DECREF(self); THROW(ERR, "Invalid value for 'interval': %i32", interval); } ZombieCharBuf *scratch = ZCB_WRAP(name); uint32_t code_point; while (0 != (code_point = ZCB_Nip_One(scratch))) { if (isalnum(code_point) || code_point == '.' || code_point == '-' || code_point == '_' ) { continue; } DECREF(self); THROW(ERR, "Lock name contains disallowed characters: '%o'", name); } // Assign. self->folder = (Folder*)INCREF(folder); self->timeout = timeout; self->name = CB_Clone(name); self->host = CB_Clone(host); self->interval = interval; // Derive. self->lock_path = CB_newf("locks/%o.lock", name); return self; }
bool_t LFLock_maybe_delete_file(LockFileLock *self, const CharBuf *path, bool_t delete_mine, bool_t delete_other) { Folder *folder = self->folder; bool_t success = false; ZombieCharBuf *scratch = ZCB_WRAP(path); // Only delete locks that start with our lock name. CharBuf *lock_dir_name = (CharBuf*)ZCB_WRAP_STR("locks", 5); if (!ZCB_Starts_With(scratch, lock_dir_name)) { return false; } ZCB_Nip(scratch, CB_Get_Size(lock_dir_name) + 1); if (!ZCB_Starts_With(scratch, self->name)) { return false; } // Attempt to delete dead lock file. if (Folder_Exists(folder, path)) { Hash *hash = (Hash*)Json_slurp_json(folder, path); if (hash != NULL && Obj_Is_A((Obj*)hash, HASH)) { CharBuf *pid_buf = (CharBuf*)Hash_Fetch_Str(hash, "pid", 3); CharBuf *host = (CharBuf*)Hash_Fetch_Str(hash, "host", 4); CharBuf *name = (CharBuf*)Hash_Fetch_Str(hash, "name", 4); // Match hostname and lock name. if (host != NULL && CB_Equals(host, (Obj*)self->host) && name != NULL && CB_Equals(name, (Obj*)self->name) && pid_buf != NULL ) { // Verify that pid is either mine or dead. int pid = (int)CB_To_I64(pid_buf); if ((delete_mine && pid == PID_getpid()) // This process. || (delete_other && !PID_active(pid)) // Dead pid. ) { if (Folder_Delete(folder, path)) { success = true; } else { CharBuf *mess = MAKE_MESS("Can't delete '%o'", path); DECREF(hash); Err_throw_mess(ERR, mess); } } } } DECREF(hash); } return success; }
static Folder* S_enclosing_folder(Folder *self, ZombieCharBuf *path) { size_t path_component_len = 0; uint32_t code_point; // Strip trailing slash. if (ZCB_Code_Point_From(path, 0) == '/') { ZCB_Chop(path, 1); } // Find first component of the file path. ZombieCharBuf *scratch = ZCB_WRAP((CharBuf*)path); ZombieCharBuf *path_component = ZCB_WRAP((CharBuf*)path); while (0 != (code_point = ZCB_Nip_One(scratch))) { if (code_point == '/') { ZCB_Truncate(path_component, path_component_len); ZCB_Nip(path, path_component_len + 1); break; } path_component_len++; } // If we've eaten up the entire filepath, self is enclosing folder. if (ZCB_Get_Size(scratch) == 0) { return self; } Folder *local_folder = Folder_Local_Find_Folder(self, (CharBuf*)path_component); if (!local_folder) { /* This element of the filepath doesn't exist, or it's not a * directory. However, there are filepath characters left over, * implying that this component ought to be a directory -- so the * original file path is invalid. */ return NULL; } // This file path component is a folder. Recurse into it. return S_enclosing_folder(local_folder, path); }
bool_t Seg_valid_seg_name(const CharBuf *name) { if (CB_Starts_With_Str(name, "seg_", 4)) { ZombieCharBuf *scratch = ZCB_WRAP(name); ZCB_Nip(scratch, 4); uint32_t code_point; while (0 != (code_point = ZCB_Nip_One(scratch))) { if (!isalnum(code_point)) { return false; } } if (ZCB_Get_Size(scratch) == 0) { return true; } // Success! } return false; }
int32_t CB_hash_sum(CharBuf *self) { uint32_t hashvalue = 5381; ZombieCharBuf *iterator = ZCB_WRAP(self); const CB_Nip_One_t nip_one = METHOD_PTR(iterator->vtable, Lucy_CB_Nip_One); while (iterator->size) { uint32_t code_point = (uint32_t)nip_one((CharBuf*)iterator); hashvalue = ((hashvalue << 5) + hashvalue) ^ code_point; } return (int32_t) hashvalue; }
static void test_To_String(TestBatch *batch) { Obj *testobj = S_new_testobj(); CharBuf *string = Obj_To_String(testobj); ZombieCharBuf *temp = ZCB_WRAP(string); while (ZCB_Get_Size(temp)) { if (ZCB_Starts_With_Str(temp, "TestObj", 7)) { break; } ZCB_Nip_One(temp); } TEST_TRUE(batch, ZCB_Starts_With_Str(temp, "TestObj", 7), "To_String"); DECREF(string); DECREF(testobj); }
Folder* Folder_find_folder(Folder *self, const CharBuf *path) { if (!path || !CB_Get_Size(path)) { return self; } else { ZombieCharBuf *scratch = ZCB_WRAP(path); Folder *enclosing_folder = S_enclosing_folder(self, scratch); if (!enclosing_folder) { return NULL; } else { return Folder_Local_Find_Folder(enclosing_folder, (CharBuf*)scratch); } } }
Lock* IxManager_make_snapshot_read_lock(IndexManager *self, const CharBuf *filename) { ZombieCharBuf *lock_name = ZCB_WRAP(filename); LockFactory *lock_factory = S_obtain_lock_factory(self); if ( !CB_Starts_With_Str(filename, "snapshot_", 9) || !CB_Ends_With_Str(filename, ".json", 5) ) { THROW(ERR, "Not a snapshot filename: %o", filename); } // Truncate ".json" from end of snapshot file name. ZCB_Chop(lock_name, sizeof(".json") - 1); return LockFact_Make_Shared_Lock(lock_factory, (CharBuf*)lock_name, 1000, 100); }
Folder* Folder_enclosing_folder(Folder *self, const CharBuf *path) { ZombieCharBuf *scratch = ZCB_WRAP(path); return S_enclosing_folder(self, scratch); }
static void S_append_json_string(Obj *dump, CharBuf *json) { // Append opening quote. CB_Cat_Trusted_Str(json, "\"", 1); // Process string data. ZombieCharBuf *iterator = ZCB_WRAP((CharBuf*)dump); while (ZCB_Get_Size(iterator)) { uint32_t code_point = ZCB_Nip_One(iterator); if (code_point > 127) { // There is no need to escape any high characters, including those // above the BMP, as we assume that the destination channel can // handle arbitrary UTF-8 data. CB_Cat_Char(json, code_point); } else { char buffer[7]; size_t len; switch (code_point & 127) { // Perform all mandatory escapes enumerated in the JSON spec. // Note that the spec makes escaping forward slash optional; // we choose not to. case 0x00: case 0x01: case 0x02: case 0x03: case 0x04: case 0x05: case 0x06: case 0x07: case 0x0b: case 0x0e: case 0x0f: case 0x10: case 0x11: case 0x12: case 0x13: case 0x14: case 0x15: case 0x16: case 0x17: case 0x18: case 0x19: case 0x1a: case 0x1b: case 0x1c: case 0x1d: case 0x1e: case 0x1f: { sprintf(buffer, "\\u%04x", (unsigned)code_point); len = 6; break; } case '\b': memcpy(buffer, "\\b", 2); len = 2; break; case '\t': memcpy(buffer, "\\t", 2); len = 2; break; case '\n': memcpy(buffer, "\\n", 2); len = 2; break; case '\f': memcpy(buffer, "\\f", 2); len = 2; break; case '\r': memcpy(buffer, "\\r", 2); len = 2; break; case '\\': memcpy(buffer, "\\\\", 2); len = 2; break; case '\"': memcpy(buffer, "\\\"", 2); len = 2; break; // Ordinary printable ASCII. default: buffer[0] = (char)code_point; len = 1; } CB_Cat_Trusted_Str(json, buffer, len); } } // Append closing quote. CB_Cat_Trusted_Str(json, "\"", 1); }