예제 #1
0
파일: Folder.c 프로젝트: pavansondur/lucy
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);
        }
    }
}
예제 #2
0
static void
test_Local_MkDir_and_Find_Folder(TestBatchRunner *runner) {
    Folder *real_folder = S_folder_with_contents();
    CompoundFileReader *cf_reader = CFReader_open(real_folder);

    TEST_FALSE(runner,
               CFReader_Local_Is_Directory(cf_reader, stuff),
               "Local_Is_Directory returns false for non-existent entry");

    TEST_TRUE(runner, CFReader_MkDir(cf_reader, stuff),
              "MkDir returns true");
    TEST_TRUE(runner,
              Folder_Find_Folder(real_folder, stuff) != NULL,
              "Local_MkDir pass-through");
    TEST_TRUE(runner,
              Folder_Find_Folder(real_folder, stuff)
              == CFReader_Find_Folder(cf_reader, stuff),
              "Local_Find_Folder pass-through");
    TEST_TRUE(runner,
              CFReader_Local_Is_Directory(cf_reader, stuff),
              "Local_Is_Directory pass through");

    Err_set_error(NULL);
    TEST_FALSE(runner, CFReader_MkDir(cf_reader, stuff),
               "MkDir returns false when dir already exists");
    TEST_TRUE(runner, Err_get_error() != NULL,
              "MkDir sets global error when dir already exists");

    Err_set_error(NULL);
    TEST_FALSE(runner, CFReader_MkDir(cf_reader, foo),
               "MkDir returns false when virtual file exists");
    TEST_TRUE(runner, Err_get_error() != NULL,
              "MkDir sets global error when virtual file exists");

    TEST_TRUE(runner,
              CFReader_Find_Folder(cf_reader, foo) == NULL,
              "Virtual file not reported as directory");
    TEST_FALSE(runner, CFReader_Local_Is_Directory(cf_reader, foo),
               "Local_Is_Directory returns false for virtual file");

    DECREF(real_folder);
    DECREF(cf_reader);
}
예제 #3
0
파일: Folder.c 프로젝트: theory/lucy
DirHandle*
Folder_open_dir(Folder *self, const CharBuf *path) {
    DirHandle *dh = NULL;
    Folder *folder;
    if (path) {
        folder = Folder_Find_Folder(self, path);
    }
    else {
        ZombieCharBuf *empty = ZCB_BLANK();
        folder = Folder_Find_Folder(self, (CharBuf*)empty);
    }
    if (!folder) {
        Err_set_error(Err_new(CB_newf("Invalid path: '%o'", path)));
    }
    else {
        dh = Folder_Local_Open_Dir(folder);
        if (!dh) {
            ERR_ADD_FRAME(Err_get_error());
        }
    }
    return dh;
}
예제 #4
0
파일: Folder.c 프로젝트: theory/lucy
VArray*
Folder_list_r(Folder *self, const CharBuf *path) {
    Folder *local_folder = Folder_Find_Folder(self, path);
    VArray *list =  VA_new(0);
    if (local_folder) {
        CharBuf *dir    = CB_new(20);
        CharBuf *prefix = CB_new(20);
        if (path && CB_Get_Size(path)) {
            CB_setf(prefix, "%o/", path);
        }
        S_add_to_file_list(local_folder, list, dir, prefix);
        DECREF(prefix);
        DECREF(dir);
    }
    return list;
}
예제 #5
0
파일: Folder.c 프로젝트: theory/lucy
VArray*
Folder_list(Folder *self, const CharBuf *path) {
    Folder *local_folder = Folder_Find_Folder(self, path);
    VArray *list = NULL;
    DirHandle *dh = Folder_Local_Open_Dir(local_folder);
    if (dh) {
        CharBuf *entry = DH_Get_Entry(dh);
        list = VA_new(32);
        while (DH_Next(dh)) { VA_Push(list, (Obj*)CB_Clone(entry)); }
        DECREF(dh);
    }
    else {
        ERR_ADD_FRAME(Err_get_error());
    }
    return list;
}
예제 #6
0
파일: Lock.c 프로젝트: apache/lucy
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;
}
예제 #7
0
파일: Lock.c 프로젝트: pavansondur/lucy
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;
}
예제 #8
0
파일: Lock.c 프로젝트: carriercomm/lucy
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;
}
예제 #9
0
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);
}