int SLNSessionGetFileInfo(SLNSessionRef const session, strarg_t const URI, SLNFileInfo *const info) { DB_env *db = NULL; int rc = SLNSessionDBOpen(session, SLN_RDONLY, &db); if(rc < 0) return rc; DB_txn *txn = NULL; rc = db_txn_begin(db, NULL, DB_RDONLY, &txn); if(rc < 0) { SLNSessionDBClose(session, &db); return rc; } DB_cursor *cursor; rc = db_txn_cursor(txn, &cursor); assert(!rc); DB_range fileIDs[1]; SLNURIAndFileIDRange1(fileIDs, txn, URI); DB_val URIAndFileID_key[1]; rc = db_cursor_firstr(cursor, fileIDs, URIAndFileID_key, NULL, +1); DB_val file_val[1]; if(rc >= 0) { strarg_t URI2; uint64_t fileID; SLNURIAndFileIDKeyUnpack(URIAndFileID_key, txn, &URI2, &fileID); assert(0 == strcmp(URI, URI2)); if(info) { DB_val fileID_key[1]; SLNFileByIDKeyPack(fileID_key, txn, fileID); rc = db_get(txn, fileID_key, file_val); } } if(rc < 0) { db_txn_abort(txn); txn = NULL; SLNSessionDBClose(session, &db); return rc; } if(info) { // Clear padding for later assert_zeroed. memset(info, 0, sizeof(*info)); strarg_t const internalHash = db_read_string(file_val, txn); strarg_t const type = db_read_string(file_val, txn); uint64_t const size = db_read_uint64(file_val); info->hash = strdup(internalHash); info->path = SLNRepoCopyInternalPath(SLNSessionGetRepo(session), internalHash); info->type = strdup(type); info->size = size; if(!info->hash || !info->path || !info->type) { SLNFileInfoCleanup(info); db_txn_abort(txn); txn = NULL; SLNSessionDBClose(session, &db); return DB_ENOMEM; } } db_txn_abort(txn); txn = NULL; SLNSessionDBClose(session, &db); return 0; }
int SLNSubmissionEnd(SLNSubmissionRef const sub) { if(!sub) return 0; if(sub->size <= 0) return UV_EINVAL; assert(sub->tmppath); assert(sub->tmpfile >= 0); assert(sub->type); sub->URIs = SLNHasherEnd(sub->hasher); sub->internalHash = strdup(SLNHasherGetInternalHash(sub->hasher)); SLNHasherFree(&sub->hasher); if(!sub->URIs || !sub->internalHash) return UV_ENOMEM; SLNRepoRef const repo = SLNSubmissionGetRepo(sub); str_t *internalPath = NULL; bool worker = false; int rc = 0; rc = verify(sub); if(rc < 0) goto cleanup; internalPath = SLNRepoCopyInternalPath(repo, sub->internalHash); if(!internalPath) rc = UV_ENOMEM; if(rc < 0) goto cleanup; async_pool_enter(NULL); worker = true; rc = async_fs_fdatasync(sub->tmpfile); if(rc < 0) goto cleanup; // We use link(2) rather than rename(2) because link gives an error // if there's a name collision, rather than overwriting. We want to // keep the oldest file for any given hash, rather than the newest. rc = async_fs_link_mkdirp(sub->tmppath, internalPath); if(UV_EEXIST == rc) { rc = 0; goto cleanup; } if(rc < 0) { alogf("SLNSubmission couldn't move '%s' to '%s' (%s)\n", sub->tmppath, internalPath, sln_strerror(rc)); goto cleanup; } rc = async_fs_sync_dirname(internalPath); cleanup: if(worker) { async_pool_leave(NULL); worker = false; } FREE(&internalPath); async_fs_unlink(sub->tmppath); FREE(&sub->tmppath); return rc; }
int SLNSubmissionGetFileInfo(SLNSubmissionRef const sub, SLNFileInfo *const info) { if(!sub) return UV_EINVAL; if(!sub->internalHash) return UV_EINVAL; SLNRepoRef const repo = SLNSessionGetRepo(sub->session); info->hash = strdup(sub->internalHash); info->path = SLNRepoCopyInternalPath(repo, sub->internalHash); info->type = strdup(sub->type); info->size = sub->size; if(!info->hash || !info->path || !info->type) { SLNFileInfoCleanup(info); return UV_ENOMEM; } return 0; }