static void _sg_workingdir__get_dir(SG_context* pCtx, SG_repo* pRepo, const SG_pathname* pPathLocal, const char* pszidHidTreeNode, SG_vhash * pvhTimestamps) { SG_uint32 count; SG_uint32 i; SG_pathname* pPathSub = NULL; SG_treenode* pTreenode = NULL; SG_ERR_CHECK( SG_treenode__load_from_repo(pCtx, pRepo, pszidHidTreeNode, &pTreenode) ); SG_ERR_CHECK( SG_treenode__count(pCtx, pTreenode, &count) ); for (i=0; i<count; i++) { const char * pszGid; const SG_treenode_entry* pEntry; const char* pszName; SG_ERR_CHECK( SG_treenode__get_nth_treenode_entry__ref(pCtx, pTreenode, i, &pszGid, &pEntry) ); SG_ERR_CHECK( SG_treenode_entry__get_entry_name(pCtx, pEntry, &pszName) ); SG_ERR_CHECK( SG_PATHNAME__ALLOC__PATHNAME_SZ(pCtx, &pPathSub, pPathLocal, pszName) ); SG_ERR_CHECK( _sg_workingdir__get_entry(pCtx, pRepo, pPathSub, pszGid, pEntry, pvhTimestamps) ); SG_PATHNAME_NULLFREE(pCtx, pPathSub); } fail: SG_TREENODE_NULLFREE(pCtx, pTreenode); SG_PATHNAME_NULLFREE(pCtx, pPathSub); }
/** * INSERT or UPDATE this TreeNodeEntry and if a directory, * dive into it and INSERT/UPDATE the contents of the directory. */ void sg_wc_db__tne__insert_recursive(SG_context * pCtx, sg_wc_db * pDb, const sg_wc_db__cset_row * pCSetRow, sqlite3_stmt * pStmt, SG_uint64 uiAliasGidParent, SG_uint64 uiAliasGid, const SG_treenode_entry * pTreenodeEntry) { SG_treenode * pTreenode = NULL; SG_uint32 nrEntries, k; SG_treenode_entry_type tneType; SG_ERR_CHECK( sg_wc_db__tne__bind_insert_and_step(pCtx, pStmt, uiAliasGid, uiAliasGidParent, pTreenodeEntry) ); SG_ERR_CHECK( SG_treenode_entry__get_entry_type(pCtx, pTreenodeEntry, &tneType) ); if (tneType == SG_TREENODEENTRY_TYPE_DIRECTORY) { const char * pszHid = NULL; // we do not own this // dive into the contents of the directory and load them. SG_ERR_CHECK( SG_treenode_entry__get_hid_blob(pCtx, pTreenodeEntry, &pszHid) ); SG_ERR_CHECK( SG_treenode__load_from_repo(pCtx, pDb->pRepo, pszHid, &pTreenode) ); SG_ERR_CHECK( SG_treenode__count(pCtx, pTreenode, &nrEntries) ); for (k=0; k<nrEntries; k++) { const char * pszGid_k = NULL; // we do not own this const SG_treenode_entry * pTreenodeEntry_k = NULL; // we do not own this SG_uint64 uiAliasGid_k = 0; SG_ERR_CHECK( SG_treenode__get_nth_treenode_entry__ref(pCtx, pTreenode, k, &pszGid_k, &pTreenodeEntry_k) ); SG_ERR_CHECK( sg_wc_db__gid__insert(pCtx, pDb, pszGid_k) ); SG_ERR_CHECK( sg_wc_db__gid__get_alias_from_gid(pCtx, pDb, pszGid_k, &uiAliasGid_k) ); SG_ERR_CHECK( sg_wc_db__tne__insert_recursive(pCtx, pDb, pCSetRow, pStmt, uiAliasGid, uiAliasGid_k, pTreenodeEntry_k) ); } } fail: SG_TREENODE_NULLFREE(pCtx, pTreenode); }
void sg_pack__get_dir(SG_context* pCtx, SG_repo* pRepo, SG_int32 gen, const char* pszidHidTreeNode, SG_rbtree* prb_blobs, SG_rbtree* prb_new) { SG_uint32 count; SG_uint32 i; SG_treenode* pTreenode = NULL; const char* psz_gid = NULL; SG_treenode_entry_type type; const char* psz_hid = NULL; SG_ERR_CHECK( SG_treenode__load_from_repo(pCtx, pRepo, pszidHidTreeNode, &pTreenode) ); SG_ERR_CHECK( SG_treenode__count(pCtx, pTreenode, &count) ); for (i=0; i<count; i++) { const SG_treenode_entry* pEntry = NULL; const char* pszName = NULL; SG_ERR_CHECK( SG_treenode__get_nth_treenode_entry__ref(pCtx, pTreenode, i, &psz_gid, &pEntry) ); SG_ERR_CHECK( SG_treenode_entry__get_entry_name(pCtx, pEntry, &pszName) ); SG_ERR_CHECK( SG_treenode_entry__get_entry_type(pCtx, pEntry, &type) ); SG_ERR_CHECK( SG_treenode_entry__get_hid_blob(pCtx, pEntry, &psz_hid) ); if (SG_TREENODEENTRY_TYPE_DIRECTORY == type) { SG_ERR_CHECK( sg_pack__do_blob(pCtx, psz_gid, psz_hid, gen, prb_blobs, prb_new) ); SG_ERR_CHECK( sg_pack__get_dir(pCtx, pRepo, gen, psz_hid, prb_blobs, prb_new) ); } else if (SG_TREENODEENTRY_TYPE_REGULAR_FILE == type) { /* TODO use pszName file extension to decide whether to bother? */ SG_ERR_CHECK( sg_pack__do_blob(pCtx, psz_gid, psz_hid, gen, prb_blobs, prb_new) ); } else if (SG_TREENODEENTRY_TYPE_SYMLINK == type) { /* ignore symlinks */ } else { SG_ERR_THROW( SG_ERR_NOTIMPLEMENTED ); } } SG_TREENODE_NULLFREE(pCtx, pTreenode); pTreenode = NULL; return; fail: SG_TREENODE_NULLFREE(pCtx, pTreenode); }
/** * This function is used to get a new tree. It must be called with the HID of * the top-level user root directory. Not the super-root. The directory which * corresponds to @. */ static void sg_pack__do_get_dir__top(SG_context* pCtx, SG_repo* pRepo, SG_int32 gen, const char* pszidHidTreeNode, SG_rbtree* prb_blobs, SG_rbtree* prb_new) { SG_treenode* pTreenode = NULL; SG_byte* pBytes = NULL; const SG_treenode_entry* pEntry = NULL; const char* pszidHidContent = NULL; /* Load the treenode. It should have exactly one entry, a subdirectory, * named @ */ SG_ERR_CHECK( SG_treenode__load_from_repo(pCtx, pRepo, pszidHidTreeNode, &pTreenode) ); SG_ERR_CHECK( SG_treenode__get_nth_treenode_entry__ref(pCtx, pTreenode, 0, NULL, &pEntry) ); SG_ERR_CHECK( SG_treenode_entry__get_hid_blob(pCtx, pEntry, &pszidHidContent) ); #ifdef DEBUG { SG_uint32 count; SG_treenode_entry_type type; const char* pszName = NULL; SG_ERR_CHECK( SG_treenode__count(pCtx, pTreenode, &count) ); SG_ASSERT(1 == count); SG_ERR_CHECK( SG_treenode_entry__get_entry_type(pCtx, pEntry, &type) ); SG_ASSERT (SG_TREENODEENTRY_TYPE_DIRECTORY == type); SG_ERR_CHECK( SG_treenode_entry__get_entry_name(pCtx, pEntry, &pszName) ); SG_ASSERT(0 == strcmp(pszName, "@")); } #endif /* create the directory and then dive into it */ SG_ERR_CHECK( sg_pack__get_dir(pCtx, pRepo, gen, pszidHidContent, prb_blobs, prb_new) ); SG_TREENODE_NULLFREE(pCtx, pTreenode); return; fail: /* TODO free stuff */ SG_NULLFREE(pCtx, pBytes); }
/** * Load the SuperRoot TreeNode from the Repo and completely * populate the tbl_L[k] table. * * WE DO NOT DROP/RECREATE THE TABLE BEFORE STARTING. * The caller should have prep'd the table if they want that. * * We DO NOT put the super-root in the tne_L0 table; we * start the tne_L0 table with the actual root "@/" (aka "@b/"). * (Info on the super-root can be found in the tbl_csets.) * */ void sg_wc_db__tne__process_super_root(SG_context * pCtx, sg_wc_db * pDb, const sg_wc_db__cset_row * pCSetRow, sqlite3_stmt * pStmt, const char * pszHidSuperRoot) { SG_treenode * pTreenodeSuperRoot = NULL; const char * pszGidRoot = NULL; // we don't own this const SG_treenode_entry * pTreenodeEntryRoot = NULL; // we don't own this SG_uint64 uiAliasGidNull = 0; SG_uint64 uiAliasGidRoot = 0; SG_ERR_CHECK( SG_treenode__load_from_repo(pCtx, pDb->pRepo, pszHidSuperRoot, &pTreenodeSuperRoot) ); #if defined(DEBUG) { // verify we have a well-formed super-root. that is, the super-root treenode // should have exactly 1 treenode-entry -- the "@" (aka "@b/") directory. SG_uint32 nrEntries; SG_ERR_CHECK( SG_treenode__count(pCtx, pTreenodeSuperRoot, &nrEntries) ); if (nrEntries != 1) SG_ERR_THROW( SG_ERR_MALFORMED_SUPERROOT_TREENODE ); } #endif SG_ERR_CHECK( SG_treenode__get_nth_treenode_entry__ref(pCtx, pTreenodeSuperRoot,0, &pszGidRoot, &pTreenodeEntryRoot) ); #if defined(DEBUG) { const char * pszEntrynameRoot = NULL; // we don't own this SG_treenode_entry_type tneTypeRoot; SG_ERR_CHECK( SG_treenode_entry__get_entry_name(pCtx, pTreenodeEntryRoot, &pszEntrynameRoot) ); SG_ERR_CHECK( SG_treenode_entry__get_entry_type(pCtx, pTreenodeEntryRoot, &tneTypeRoot) ); // we set the root's entryname to "@" (not "@b") for // historical reasons and because that is what is in // the treenode. (We don't want it to look like // a rename if/when the corresponding row is created // in the tbl_PC table (where it should have "@").) if ( (strcmp(pszEntrynameRoot,"@") != 0) || (tneTypeRoot != SG_TREENODEENTRY_TYPE_DIRECTORY) ) SG_ERR_THROW( SG_ERR_MALFORMED_SUPERROOT_TREENODE ); } #endif // alias for null-root has already been added. SG_ERR_CHECK( sg_wc_db__gid__insert(pCtx, pDb, pszGidRoot) ); SG_ERR_CHECK( sg_wc_db__gid__get_alias_from_gid(pCtx, pDb, SG_WC_DB__GID__NULL_ROOT, &uiAliasGidNull) ); SG_ERR_CHECK( sg_wc_db__gid__get_alias_from_gid(pCtx, pDb, pszGidRoot, &uiAliasGidRoot) ); SG_ERR_CHECK( sg_wc_db__tne__insert_recursive(pCtx, pDb, pCSetRow, pStmt, uiAliasGidNull, uiAliasGidRoot, pTreenodeEntryRoot) ); fail: SG_TREENODE_NULLFREE(pCtx, pTreenodeSuperRoot); }
/** * This function is used to get a new tree. It must be called with the HID of * the top-level user root directory. Not the super-root. The directory which * corresponds to @. * * Record the file timestamp of each file we fetch in the pvhTimestamps; this * provides the basis for the timestamp check in scan-dir. */ static void sg_workingdir__do_get_dir__top(SG_context* pCtx, SG_repo* pRepo, const SG_pathname* pPathLocal, const char* pszidHidTreeNode, SG_vhash * pvhTimestamps) { SG_pathname* pPathSub = NULL; SG_treenode* pTreenode = NULL; SG_string* pstrLink = NULL; SG_byte* pBytes = NULL; SG_vhash* pvhAttributes = NULL; SG_int64 iAttributeBits = 0; const SG_treenode_entry* pEntry = NULL; const char* pszidHidContent = NULL; #ifdef SG_BUILD_FLAG_FEATURE_XATTR const char* pszidHidXattrs = NULL; #endif SG_bool bExists = SG_FALSE; /* Load the treenode. It should have exactly one entry, a subdirectory, * named @ */ SG_ERR_CHECK( SG_treenode__load_from_repo(pCtx, pRepo, pszidHidTreeNode, &pTreenode) ); SG_ERR_CHECK( SG_treenode__get_nth_treenode_entry__ref(pCtx, pTreenode, 0, NULL, &pEntry) ); SG_ERR_CHECK( SG_treenode_entry__get_hid_blob(pCtx, pEntry, &pszidHidContent) ); #ifdef DEBUG { SG_uint32 count; SG_treenode_entry_type type; const char* pszName = NULL; SG_ERR_CHECK( SG_treenode__count(pCtx, pTreenode, &count) ); SG_ASSERT(1 == count); SG_ERR_CHECK( SG_treenode_entry__get_entry_type(pCtx, pEntry, &type) ); SG_ASSERT (SG_TREENODEENTRY_TYPE_DIRECTORY == type); SG_ERR_CHECK( SG_treenode_entry__get_entry_name(pCtx, pEntry, &pszName) ); SG_ASSERT(0 == strcmp(pszName, "@")); } #endif /* create the directory and then dive into it */ SG_ERR_CHECK( SG_PATHNAME__ALLOC__COPY(pCtx, &pPathSub, pPathLocal) ); SG_ERR_CHECK( SG_fsobj__exists__pathname(pCtx, pPathSub, &bExists, NULL, NULL) ); if (!bExists) SG_ERR_CHECK( SG_fsobj__mkdir__pathname(pCtx, pPathSub) ); SG_ERR_CHECK( _sg_workingdir__get_dir(pCtx, pRepo, pPathSub, pszidHidContent, pvhTimestamps) ); #ifdef SG_BUILD_FLAG_FEATURE_XATTR /* fix up the xattrs on that directory */ SG_ERR_CHECK( SG_treenode_entry__get_hid_xattrs(pCtx, pEntry, &pszidHidXattrs) ); if (pszidHidXattrs) { SG_ERR_CHECK( SG_repo__fetch_vhash(pCtx, pRepo, pszidHidXattrs, &pvhAttributes) ); SG_ERR_CHECK( SG_attributes__xattrs__apply(pCtx, pPathSub, pvhAttributes, pRepo) ); SG_VHASH_NULLFREE(pCtx, pvhAttributes); } #endif /* and the attrbits too */ SG_ERR_CHECK( SG_treenode_entry__get_attribute_bits(pCtx, pEntry, &iAttributeBits) ); SG_ERR_CHECK( SG_attributes__bits__apply(pCtx, pPathSub, iAttributeBits) ); SG_PATHNAME_NULLFREE(pCtx, pPathSub); SG_TREENODE_NULLFREE(pCtx, pTreenode); return; fail: /* TODO free stuff */ SG_VHASH_NULLFREE(pCtx, pvhAttributes); SG_NULLFREE(pCtx, pBytes); SG_STRING_NULLFREE(pCtx, pstrLink); }