static void _sg_jscore_getpaths(SG_context *pCtx) { char * szServerFiles = NULL; if (gpJSCoreGlobalState->pPathToDispatchDotJS) return; // Figure out and store relavant paths... SG_ERR_CHECK( SG_localsettings__get__sz(pCtx, SG_LOCALSETTING__SERVER_FILES, NULL, &szServerFiles, NULL) ); if (szServerFiles) { SG_ERR_CHECK( SG_PATHNAME__ALLOC__SZ(pCtx, &gpJSCoreGlobalState->pPathToDispatchDotJS, szServerFiles) ); SG_ERR_CHECK( SG_pathname__append__from_sz(pCtx, gpJSCoreGlobalState->pPathToDispatchDotJS, "dispatch.js") ); SG_ERR_CHECK( SG_PATHNAME__ALLOC__SZ(pCtx, &gpJSCoreGlobalState->pPathToCore, szServerFiles) ); SG_ERR_CHECK( SG_pathname__append__from_sz(pCtx, gpJSCoreGlobalState->pPathToCore, "core") ); SG_ERR_CHECK( SG_PATHNAME__ALLOC__SZ(pCtx, &gpJSCoreGlobalState->pPathToModules, szServerFiles) ); SG_ERR_CHECK( SG_pathname__append__from_sz(pCtx, gpJSCoreGlobalState->pPathToModules, "modules") ); } fail: SG_NULLFREE(pCtx, szServerFiles); }
void u0038_test_wdmapping(SG_context * pCtx) { SG_vhash* pvh = NULL; SG_closet_descriptor_handle* ph = NULL; SG_pathname* pPath = NULL; SG_pathname* pMappedPath = NULL; SG_string* pstrRepoDescriptorName = NULL; char* pszidGid = NULL; char buf_tid[SG_TID_MAX_BUFFER_LENGTH]; VERIFY_ERR_CHECK_DISCARD( SG_tid__generate2__suffix(pCtx, buf_tid, sizeof(buf_tid), 32, "u0038") ); VERIFY_ERR_CHECK_DISCARD( SG_PATHNAME__ALLOC__SZ(pCtx, &pPath, buf_tid) ); VERIFY_ERR_CHECK_DISCARD( SG_fsobj__mkdir__pathname(pCtx, pPath) ); SG_ERR_IGNORE( SG_closet__descriptors__remove(pCtx, "r1") ); VERIFY_ERR_CHECK_DISCARD( SG_closet__descriptors__add_begin(pCtx, "r1", NULL, NULL, NULL, NULL, &pvh, &ph) ); VERIFY_ERR_CHECK_DISCARD( SG_closet__descriptors__add_commit(pCtx, &ph, pvh, SG_REPO_STATUS__NORMAL) ); SG_VHASH_NULLFREE(pCtx, pvh); VERIFY_ERR_CHECK_DISCARD( SG_workingdir__set_mapping(pCtx, pPath, "r1", NULL) ); VERIFY_ERR_CHECK_DISCARD( SG_workingdir__find_mapping(pCtx, pPath, &pMappedPath, &pstrRepoDescriptorName, &pszidGid) ); VERIFY_COND("ridesc match", (0 == strcmp("r1", SG_string__sz(pstrRepoDescriptorName)))); VERIFY_ERR_CHECK_DISCARD( SG_pathname__append__from_sz(pCtx, pPath, "foo") ); VERIFY_ERR_CHECK_DISCARD( SG_pathname__append__from_sz(pCtx, pPath, "bar") ); VERIFY_ERR_CHECK_DISCARD( SG_pathname__append__from_sz(pCtx, pPath, "plok") ); SG_STRING_NULLFREE(pCtx, pstrRepoDescriptorName); SG_PATHNAME_NULLFREE(pCtx, pMappedPath); VERIFY_ERR_CHECK_DISCARD( SG_workingdir__find_mapping(pCtx, pPath, &pMappedPath, &pstrRepoDescriptorName, &pszidGid) ); SG_STRING_NULLFREE(pCtx, pstrRepoDescriptorName); SG_PATHNAME_NULLFREE(pCtx, pMappedPath); SG_PATHNAME_NULLFREE(pCtx, pPath); }
/** * Initialize a WD (create .sgdrawer and friends) and set up shop. * The given directory pathname can either be to a new (to be created) * directory -or- an existing (possibly non-empty) directory. * * WARNING: This routine deviates from the model of the other SG_wc__ * WARNING: routines because the WD does not yet exist (and we haven't * WARNING: yet created .sgdrawer). The caller may have already created * WARNING: an empty directory for us, but that is it. * * WARNING: This routine also deviates in that we *ONLY* provide a wc8api * WARNING: version and *NOT* a wc7txapi version. Likewise we only provide * WARNING: a sg.wc.initialize() version and not a sg_wc_tx.initialize() version. * WARNING: This is because I want it to be a complete self-contained * WARNING: operation (and I want to hide the number of SQL TXs that are * WARNING: required to get everything set up). * * Also, the given path (to the new WD root) can be an absolute or * relative path or NULL (we'll substitute the CWD). Unlike the other * API routines, it cannot be a repo-path. * * This should only be used by 'vv init' or sg.vv2.init_new_repo() * (after the repo has been created). * */ void SG_wc__initialize(SG_context * pCtx, const char * pszRepoName, const char * pszPath, const char * pszHidCSet, const char * pszTargetBranchName) { SG_wc_tx * pWcTx = NULL; SG_NONEMPTYCHECK_RETURN( pszRepoName ); // repo-name is required // pszPath is optional; default to CWD. SG_NONEMPTYCHECK_RETURN( pszHidCSet ); // pszTargetBranchName is optional; default to unattached. // Create the WD root, the drawer, and the SQL DB. // Load the given CSET into the tne_L0 table. // // We DO NOT create a timestamp cache at this time // because of clock blurr problem. (We can't trust // mtime until about 2 seconds after we create the // files.) SG_ERR_CHECK( SG_WC_TX__ALLOC__BEGIN__CREATE(pCtx, &pWcTx, pszRepoName, pszPath, SG_FALSE, pszHidCSet) ); if (pszTargetBranchName) { SG_ERR_CHECK( sg_wc_db__branch__attach(pCtx, pWcTx->pDb, pszTargetBranchName, SG_VC_BRANCHES__CHECK_ATTACH_NAME__DONT_CARE, SG_TRUE) ); } #if defined(DEBUG) #define DEBUG_INIT_FAILURE__E2 "gb54c5ca2cfe349eaa3ce599100d1c4d737052960d1e411e1a51e002500da2b78.test" { // Force a failure while we are initializing a new repo using the current directory in // order to test the cleanup/recovery code. // See st_wc_checkout_W7885.js SG_bool bExists = SG_FALSE; SG_pathname * pPathTest = NULL; SG_ERR_CHECK( SG_PATHNAME__ALLOC__SZ(pCtx, &pPathTest, DEBUG_INIT_FAILURE__E2) ); SG_ERR_CHECK( SG_fsobj__exists__pathname(pCtx, pPathTest, &bExists, NULL, NULL) ); SG_PATHNAME_NULLFREE(pCtx, pPathTest); if (bExists) SG_ERR_THROW2( SG_ERR_DEBUG_1, (pCtx, "Init: %s", DEBUG_INIT_FAILURE__E2) ); } #endif SG_ERR_CHECK( _check_for_nested_drawer(pCtx, pWcTx) ); SG_ERR_CHECK( SG_wc_tx__apply(pCtx, pWcTx) ); SG_ERR_CHECK( SG_wc_tx__free(pCtx, pWcTx) ); return; fail: SG_ERR_IGNORE( SG_wc_tx__abort_create_and_free(pCtx, &pWcTx) ); }
/** * Select an appropriate difftool to use on this file. * We require that the common and right-side fields of * pvhDiffItem be filled in first. (The left-side fields * can be after this is called.) * */ static void _pick_tool(SG_context * pCtx, sg_wc6diff__setup_data * pData, const SG_vhash * pvhItem, SG_vhash * pvhDiffItem, SG_string * pStringHeader) { SG_filetool * pTool = NULL; const char * pszRepoPath_live = NULL; const char * pszAbsPath = NULL; SG_pathname * pPathname = NULL; const char * pszToolNameChosen = NULL; SG_bool bIsTmp_right = SG_FALSE; // use the suffix on the (always present) live-repo-path (rather than // the left- or right- version) to pick a tool. // // if that fails, use the suffix of current file in the WD // (provided it isn't a temp file). the left side is always // a temp file, so don't bother with it. SG_ERR_CHECK( SG_vhash__check__sz(pCtx, pvhItem, "path", &pszRepoPath_live) ); SG_ERR_CHECK( SG_vhash__check__bool(pCtx, pvhDiffItem, "right_is_temp", &bIsTmp_right) ); if (!bIsTmp_right) { SG_ERR_CHECK( SG_vhash__check__sz(pCtx, pvhDiffItem, "right_abs_path", &pszAbsPath) ); if (pszAbsPath) SG_ERR_CHECK( SG_PATHNAME__ALLOC__SZ(pCtx, &pPathname, pszAbsPath) ); } SG_ERR_CHECK( SG_difftool__select(pCtx, pData->pszDiffToolContext, // gui or console pszRepoPath_live, // current/live repo-path pPathname, // live or temp absolute pathname pData->pszTool, // suggested/requested tool pData->pWcTx->pDb->pRepo, &pTool) ); if (pTool) { SG_ERR_CHECK( SG_filetool__get_name(pCtx, pTool, &pszToolNameChosen) ); SG_ERR_CHECK( SG_vhash__add__string__sz(pCtx, pvhDiffItem, "tool", pszToolNameChosen) ); SG_ERR_CHECK( SG_vhash__add__string__sz(pCtx, pvhDiffItem, "context", pData->pszDiffToolContext) ); } else { SG_ERR_CHECK( SG_string__append__format(pCtx, pStringHeader, "=== No difftool configured for ('%s', '%s') in context '%s'.\n", pszRepoPath_live, pszAbsPath, pData->pszDiffToolContext) ); } fail: SG_FILETOOL_NULLFREE(pCtx, pTool); SG_PATHNAME_NULLFREE(pCtx, pPathname); }
void u0038_test_version(SG_context * pCtx) { /* This test pokes around in closet internals in ways normal closet callers shouldn't. */ SG_string* pstrEnv = NULL; SG_uint32 len; SG_pathname* pPathCloset = NULL; SG_pathname* pPathClosetVersion = NULL; SG_pathname* pPathClosetVersionBackup = NULL; SG_file* pFile = NULL; SG_vhash* pvh = NULL; /* Deliberately making this break for closet version 3 -- current is version 2. */ SG_byte buf[3]; VERIFY_ERR_CHECK( SG_environment__get__str(pCtx, "SGCLOSET", &pstrEnv, &len) ); if (len) { VERIFY_ERR_CHECK( SG_PATHNAME__ALLOC__SZ(pCtx, &pPathCloset, SG_string__sz(pstrEnv)) ); } else { VERIFY_ERR_CHECK( SG_PATHNAME__ALLOC__USER_APPDATA_DIRECTORY(pCtx, &pPathCloset) ); VERIFY_ERR_CHECK( SG_pathname__append__from_sz(pCtx, pPathCloset, ".sgcloset") ); } VERIFY_ERR_CHECK( SG_pathname__alloc__pathname_sz(pCtx, &pPathClosetVersion, pPathCloset, "version") ); VERIFY_ERR_CHECK( SG_pathname__alloc__pathname_sz(pCtx, &pPathClosetVersionBackup, pPathCloset, "version.bak") ); VERIFY_ERR_CHECK( SG_fsobj__move__pathname_pathname(pCtx, pPathClosetVersion, pPathClosetVersionBackup) ); VERIFY_ERR_CHECK( SG_file__open__pathname(pCtx, pPathClosetVersion, SG_FILE_OPEN_OR_CREATE|SG_FILE_WRONLY|SG_FILE_TRUNC, 0644, &pFile) ); VERIFY_ERR_CHECK( SG_file__write(pCtx, pFile, sizeof(buf), buf, NULL) ); VERIFY_ERR_CHECK( SG_file__close(pCtx, &pFile) ); SG_closet__descriptors__list(pCtx, &pvh); VERIFY_COND("", SG_context__err_equals(pCtx, SG_ERR_UNSUPPORTED_CLOSET_VERSION)); SG_ERR_DISCARD; VERIFY_ERR_CHECK( SG_fsobj__remove__pathname(pCtx, pPathClosetVersion) ); VERIFY_ERR_CHECK( SG_fsobj__move__pathname_pathname(pCtx, pPathClosetVersionBackup, pPathClosetVersion) ); /* Common cleanup */ fail: SG_STRING_NULLFREE(pCtx, pstrEnv); SG_PATHNAME_NULLFREE(pCtx, pPathCloset); SG_PATHNAME_NULLFREE(pCtx, pPathClosetVersion); SG_PATHNAME_NULLFREE(pCtx, pPathClosetVersionBackup); SG_FILE_NULLCLOSE(pCtx, pFile); SG_VHASH_NULLFREE(pCtx, pvh); }
void SG_getopt__set_app_name(SG_context * pCtx, SG_getopt * pGetopt, ARGV_CHAR_T * pBuf) { SG_pathname *tp = NULL; SG_string *st = NULL; SG_ERR_CHECK( SG_STRING__ALLOC(pCtx, &st) ); SG_ERR_CHECK( SG_UTF8__INTERN_FROM_OS_BUFFER(pCtx,st,pBuf) ); SG_ERR_CHECK( SG_PATHNAME__ALLOC__SZ(pCtx, &tp, SG_string__sz(st)) ); SG_STRING_NULLFREE(pCtx, st); SG_STRING_NULLFREE(pCtx, pGetopt->pStringAppName); SG_ERR_CHECK( SG_pathname__get_last(pCtx, tp, &pGetopt->pStringAppName) ); fail: SG_STRING_NULLFREE(pCtx, st); SG_PATHNAME_NULLFREE(pCtx, tp); }
/** * Create a new repo and *always* create a WD for it. * */ void vv2__do_cmd_init_new_repo(SG_context * pCtx, const char * pszRepoName, const char * pszFolder, const char * pszStorage, const char * pszHashMethod, const char * psz_shared_users) { SG_pathname * pPathLocalDirectory = NULL; SG_ERR_CHECK( SG_PATHNAME__ALLOC__SZ(pCtx, &pPathLocalDirectory, pszFolder) ); SG_workingdir__find_mapping(pCtx, pPathLocalDirectory, NULL, NULL, NULL); SG_ERR_CHECK_CURRENT_DISREGARD(SG_ERR_NOT_A_WORKING_COPY); SG_ERR_CHECK( SG_vv2__init_new_repo(pCtx, pszRepoName, pszFolder, pszStorage, pszHashMethod, SG_FALSE, // bNoWD psz_shared_users, SG_FALSE, NULL, NULL) ); fail: SG_PATHNAME_NULLFREE(pCtx, pPathLocalDirectory); // TODO 2010/10/25 Decide which error message we should try to provide a better error message for. // TODO Candidates include // TODO SG_ERR_INVALID_REPO_NAME // TODO SG_ERR_AMBIGUOUS_ID_PREFIX // TODO SG_ERR_MULTIPLE_HEADS_FROM_DAGNODE // TODO // TODO But we should look and see what the lower layers are throwing now. Some of // TODO of the messages that were here are now being handled. return; }
static void _set_up_logging( SG_context * pCtx, SG_log_console__data * pcLogStdData, SG_log_text__data * pcLogFileData, SG_log_text__writer__daily_path__data * pcLogFileWriterData) { // Code coppied from _my_main() in sg.c char * szLogLevel = NULL; char * szLogPath = NULL; SG_uint32 logFileFlags = SG_LOG__FLAG__HANDLER_TYPE__ALL; // find the appropriate log path SG_ERR_CHECK( SG_localsettings__get__sz(pCtx, SG_LOCALSETTING__LOG_PATH, NULL, &szLogPath, NULL) ); // get the configured log level SG_ERR_CHECK( SG_localsettings__get__sz(pCtx, SG_LOCALSETTING__LOG_LEVEL, NULL, &szLogLevel, NULL) ); // register the stdout logger SG_ERR_CHECK( SG_log_console__set_defaults(pCtx, pcLogStdData) ); SG_ERR_CHECK( SG_log_console__register(pCtx, pcLogStdData, NULL, SG_LOG__FLAG__HANDLER_TYPE__NORMAL) ); // register the file logger SG_ERR_CHECK( SG_log_text__set_defaults(pCtx, pcLogFileData) ); pcLogFileData->fWriter = SG_log_text__writer__daily_path; pcLogFileData->pWriterData = pcLogFileWriterData; pcLogFileData->szRegisterMessage = NULL; pcLogFileData->szUnregisterMessage = NULL; if (szLogLevel != NULL) { if (SG_stricmp(szLogLevel, "quiet") == 0) { logFileFlags = SG_LOG__FLAG__HANDLER_TYPE__QUIET; pcLogFileData->bLogVerboseOperations = SG_FALSE; pcLogFileData->bLogVerboseValues = SG_FALSE; pcLogFileData->szVerboseFormat = NULL; pcLogFileData->szInfoFormat = NULL; } else if (SG_stricmp(szLogLevel, "normal") == 0) { logFileFlags = SG_LOG__FLAG__HANDLER_TYPE__NORMAL; pcLogFileData->bLogVerboseOperations = SG_FALSE; pcLogFileData->bLogVerboseValues = SG_FALSE; pcLogFileData->szVerboseFormat = NULL; } else if (SG_stricmp(szLogLevel, "verbose") == 0) { logFileFlags = SG_LOG__FLAG__HANDLER_TYPE__ALL; pcLogFileData->szRegisterMessage = "---- vscript started logging ----"; pcLogFileData->szUnregisterMessage = "---- vscript stopped logging ----"; } } logFileFlags |= SG_LOG__FLAG__DETAILED_MESSAGES; SG_ERR_CHECK( SG_log_text__writer__daily_path__set_defaults(pCtx, pcLogFileWriterData) ); pcLogFileWriterData->bReopen = SG_FALSE; pcLogFileWriterData->ePermissions = 0666; if (szLogPath != NULL) SG_ERR_CHECK( SG_PATHNAME__ALLOC__SZ(pCtx, &pcLogFileWriterData->pBasePath, szLogPath) ); else SG_ERR_CHECK( SG_PATHNAME__ALLOC__LOG_DIRECTORY(pCtx, &pcLogFileWriterData->pBasePath) ); pcLogFileWriterData->szFilenameFormat = "vscript-%d-%02d-%02d.log"; SG_ERR_CHECK( SG_log_text__register(pCtx, pcLogFileData, NULL, logFileFlags) ); fail: SG_context__err_reset(pCtx); SG_NULLFREE(pCtx, szLogPath); SG_NULLFREE(pCtx, szLogLevel); }
/** * Assuming that we have something of the form: * * vv resolve [--foo] <arg_0> [<arg_1> [<arg_2> ...]] * * where each <arg_x> is an absolute or relative path in the WD * (probably not a repo-path). * * Use the PENDINGTREE to lookup each path and get the entry's GID. * Use the GID to search for an ISSUE in the list of issues. If we * find it, add the GID to the stringarray we are building. If not, * throw an error. */ static void _resolve__map_args_to_gids(SG_context * pCtx, struct _resolve_data * pData, SG_uint32 count_args, const char ** paszArgs, SG_bool bWantResolved, SG_bool bWantUnresolved) { SG_pathname * pPath_k = NULL; char * pszGid_k = NULL; SG_uint32 kArg; SG_bool bWantBoth = (bWantResolved && bWantUnresolved); SG_ERR_CHECK( SG_STRINGARRAY__ALLOC(pCtx, &pData->psaGids, count_args) ); for (kArg=0; kArg<count_args; kArg++) { const SG_vhash * pvhIssue_k; SG_bool bFound; SG_bool bDuplicate; SG_bool bWantThisOne; // take each <arg_k> and get a full pathname for it and // search for it in the pendingtree and get its GID. // in theory, if an entry has an issue, it is dirty and // should have a ptnode. if (paszArgs[kArg][0] == '@') SG_ERR_CHECK( SG_workingdir__construct_absolute_path_from_repo_path2(pCtx, pData->pPendingTree, paszArgs[kArg], &pPath_k) ); else SG_ERR_CHECK( SG_PATHNAME__ALLOC__SZ(pCtx, &pPath_k, paszArgs[kArg]) ); SG_ERR_CHECK( SG_pendingtree__get_gid_from_local_path(pCtx, pData->pPendingTree, pPath_k, &pszGid_k) ); #if 0 && defined(DEBUG) SG_ERR_IGNORE( SG_console(pCtx, SG_CS_STDERR, ("Mapped arg[%d] '%s' to:\n" "\t%s\n" "\t[gid %s]\n"), kArg, paszArgs[kArg], SG_pathname__sz(pPath_k), pszGid_k) ); #endif // see if there is an ISSUE for this GID. SG_ERR_CHECK( SG_pendingtree__find_wd_issue_by_gid(pCtx, pData->pPendingTree, pszGid_k, &bFound, &pvhIssue_k) ); if (!bFound) SG_ERR_THROW2( SG_ERR_ISSUE_NOT_FOUND, (pCtx, "No issue found for '%s': %s", paszArgs[kArg], SG_pathname__sz(pPath_k)) ); if (bWantBoth) bWantThisOne = SG_TRUE; else { SG_int64 s; SG_pendingtree_wd_issue_status status; SG_bool bResolved; SG_ERR_CHECK_RETURN( SG_vhash__get__int64(pCtx, pvhIssue_k, "status", &s) ); status = (SG_pendingtree_wd_issue_status)s; bResolved = ((status & SG_ISSUE_STATUS__MARKED_RESOLVED) == SG_ISSUE_STATUS__MARKED_RESOLVED); bWantThisOne = ((bWantResolved && bResolved) || (bWantUnresolved && !bResolved)); } if (bWantThisOne) { // check for duplicate args on command line. (or rather, args that // map to the same GID.) SG_ERR_CHECK( SG_stringarray__find(pCtx, pData->psaGids, pszGid_k, 0, &bDuplicate, NULL) ); if (bDuplicate) SG_ERR_THROW2( SG_ERR_DUPLICATE_ISSUE, (pCtx, "Argument '%s' maps to an issue already named.", paszArgs[kArg]) ); SG_ERR_CHECK( SG_stringarray__add(pCtx, pData->psaGids, pszGid_k) ); } SG_NULLFREE(pCtx, pszGid_k); SG_PATHNAME_NULLFREE(pCtx, pPath_k); } return; fail: SG_NULLFREE(pCtx, pszGid_k); SG_PATHNAME_NULLFREE(pCtx, pPath_k); }
void MyFn(test__simple)(SG_context* pCtx) { char bufTopDir[SG_TID_MAX_BUFFER_LENGTH]; SG_pathname* pPathTopDir = NULL; char buf_client_repo_name[SG_TID_MAX_BUFFER_LENGTH]; char buf_server_repo_name[SG_TID_MAX_BUFFER_LENGTH]; SG_pathname* pPathWorkingDir = NULL; SG_vhash* pvh = NULL; SG_repo* pClientRepo = NULL; SG_client* pClient = NULL; SG_repo* pServerRepo = NULL; SG_bool bMatch = SG_FALSE; SG_varray* pvaZingMergeLog = NULL; SG_varray* pvaZingMergeErr = NULL; VERIFY_ERR_CHECK( SG_tid__generate2(pCtx, bufTopDir, sizeof(bufTopDir), 32) ); VERIFY_ERR_CHECK( SG_PATHNAME__ALLOC__SZ(pCtx,&pPathTopDir,bufTopDir) ); VERIFY_ERR_CHECK( SG_fsobj__mkdir__pathname(pCtx,pPathTopDir) ); VERIFY_ERR_CHECK( SG_tid__generate2(pCtx, buf_client_repo_name, sizeof(buf_client_repo_name), 32) ); VERIFY_ERR_CHECK( SG_tid__generate2(pCtx, buf_server_repo_name, sizeof(buf_server_repo_name), 32) ); INFOP("test__simple", ("client repo: %s", buf_client_repo_name)); INFOP("test__simple", ("server repo: %s", buf_server_repo_name)); /* create the repo */ VERIFY_ERR_CHECK( SG_PATHNAME__ALLOC__PATHNAME_SZ(pCtx, &pPathWorkingDir, pPathTopDir, buf_server_repo_name) ); VERIFY_ERR_CHECK( SG_fsobj__mkdir__pathname(pCtx, pPathWorkingDir) ); VERIFY_ERR_CHECK( _ut_pt__new_repo2(pCtx, buf_server_repo_name, pPathWorkingDir, NULL) ); /* open that repo */ VERIFY_ERR_CHECK( SG_repo__open_repo_instance(pCtx, buf_server_repo_name, &pServerRepo) ); /* create an empty clone to pull into */ VERIFY_ERR_CHECK( SG_repo__create_empty_clone(pCtx, buf_server_repo_name, buf_client_repo_name) ); VERIFY_ERR_CHECK( SG_repo__open_repo_instance(pCtx, buf_client_repo_name, &pClientRepo) ); /* add stuff to server repo */ VERIFY_ERR_CHECK( MyFn(create_file__numbers)(pCtx, pPathWorkingDir, "aaa", 10) ); VERIFY_ERR_CHECK( _ut_pt__addremove(pCtx, pPathWorkingDir) ); VERIFY_ERR_CHECK( MyFn(commit_all)(pCtx, pPathWorkingDir, NULL) ); VERIFY_ERR_CHECK( MyFn(create_file__numbers)(pCtx, pPathWorkingDir, "bbb", 10) ); VERIFY_ERR_CHECK( _ut_pt__addremove(pCtx, pPathWorkingDir) ); VERIFY_ERR_CHECK( MyFn(commit_all)(pCtx, pPathWorkingDir, NULL) ); /* verify pre-pull repos are different */ VERIFY_ERR_CHECK( SG_sync__compare_repo_dags(pCtx, pClientRepo, pServerRepo, &bMatch) ); VERIFY_COND_FAIL("pre-pull repos differ", !bMatch); /* get a client and pull from server repo to empty client repo */ VERIFY_ERR_CHECK( SG_client__open(pCtx, buf_server_repo_name, NULL_CREDENTIAL, &pClient) ); // TODO Credentials VERIFY_ERR_CHECK( SG_pull__all(pCtx, buf_client_repo_name, pClient, &pvaZingMergeErr, &pvaZingMergeLog) ); VERIFY_COND("", !pvaZingMergeErr); SG_CLIENT_NULLFREE(pCtx, pClient); /* verify post-pull repos are identical */ VERIFY_ERR_CHECK( SG_sync__compare_repo_dags(pCtx, pClientRepo, pServerRepo, &bMatch) ); VERIFY_COND_FAIL("post-pull repo DAGs differ", bMatch); VERIFY_ERR_CHECK( SG_sync__compare_repo_blobs(pCtx, pClientRepo, pServerRepo, &bMatch) ); VERIFY_COND_FAIL("post-pull repo blobs differ", bMatch); VERIFY_ERR_CHECK( SG_repo__check_integrity(pCtx, pClientRepo, SG_REPO__CHECK_INTEGRITY__DAG_CONSISTENCY, SG_DAGNUM__VERSION_CONTROL, NULL, NULL) ); /* TODO: verify more stuff? */ /* Fall through to common cleanup */ fail: /* close client */ SG_CLIENT_NULLFREE(pCtx, pClient); /* close both repos */ SG_REPO_NULLFREE(pCtx, pServerRepo); SG_REPO_NULLFREE(pCtx, pClientRepo); SG_PATHNAME_NULLFREE(pCtx, pPathTopDir); SG_PATHNAME_NULLFREE(pCtx, pPathWorkingDir); SG_VHASH_NULLFREE(pCtx, pvh); SG_PATHNAME_NULLFREE(pCtx, pPathWorkingDir); SG_VARRAY_NULLFREE(pCtx, pvaZingMergeLog); SG_VARRAY_NULLFREE(pCtx, pvaZingMergeErr); }
void MyFn(test__wide_dag)(SG_context* pCtx) { char bufTopDir[SG_TID_MAX_BUFFER_LENGTH]; SG_pathname* pPathTopDir = NULL; char buf_client_repo_name[SG_TID_MAX_BUFFER_LENGTH]; char buf_server_repo_name[SG_TID_MAX_BUFFER_LENGTH]; SG_pathname* pPathWorkingDir = NULL; SG_vhash* pvh = NULL; SG_repo* pClientRepo = NULL; SG_client* pClient = NULL; char* pszidFirstChangeset = NULL; SG_pathname* pPathCsDir = NULL; SG_uint32 lines; SG_uint32 i, j; SG_repo* pServerRepo = NULL; SG_bool bMatch = SG_FALSE; char buf_filename[7]; SG_varray* pvaZingMergeLog = NULL; SG_varray* pvaZingMergeErr = NULL; VERIFY_ERR_CHECK( SG_tid__generate2(pCtx, bufTopDir, sizeof(bufTopDir), 32) ); VERIFY_ERR_CHECK( SG_PATHNAME__ALLOC__SZ(pCtx,&pPathTopDir,bufTopDir) ); VERIFY_ERR_CHECK( SG_fsobj__mkdir__pathname(pCtx,pPathTopDir) ); VERIFY_ERR_CHECK( SG_tid__generate2(pCtx, buf_client_repo_name, sizeof(buf_client_repo_name), 32) ); VERIFY_ERR_CHECK( SG_tid__generate2(pCtx, buf_server_repo_name, sizeof(buf_server_repo_name), 32) ); INFOP("test__wide_dag", ("client repo: %s", buf_client_repo_name)); INFOP("test__wide_dag", ("server repo: %s", buf_server_repo_name)); /* create the repo */ VERIFY_ERR_CHECK( SG_PATHNAME__ALLOC__PATHNAME_SZ(pCtx, &pPathWorkingDir, pPathTopDir, buf_server_repo_name) ); VERIFY_ERR_CHECK( SG_fsobj__mkdir__pathname(pCtx, pPathWorkingDir) ); VERIFY_ERR_CHECK( _ut_pt__new_repo2(pCtx, buf_server_repo_name, pPathWorkingDir, &pszidFirstChangeset) ); /* open that repo */ VERIFY_ERR_CHECK( SG_repo__open_repo_instance(pCtx, buf_server_repo_name, &pServerRepo) ); /* create an empty clone to pull into */ VERIFY_ERR_CHECK( SG_repo__create_empty_clone(pCtx, buf_server_repo_name, buf_client_repo_name) ); VERIFY_ERR_CHECK( SG_repo__open_repo_instance(pCtx, buf_client_repo_name, &pClientRepo) ); /* add stuff to server repo */ for (i = 0; i < 20; i++) // number of changesets { VERIFY_ERR_CHECK( _ut_pt__set_baseline(pCtx, pPathWorkingDir, pszidFirstChangeset) ); VERIFY_ERR_CHECK( SG_sprintf(pCtx, buf_filename, sizeof(buf_filename), "%d", i) ); VERIFY_ERR_CHECK( SG_PATHNAME__ALLOC__PATHNAME_SZ(pCtx, &pPathCsDir, pPathWorkingDir, buf_filename) ); VERIFY_ERR_CHECK( SG_fsobj__mkdir__pathname(pCtx, pPathCsDir) ); for (j = 0; j < 1; j++) // number of files added per changeset { VERIFY_ERR_CHECK( SG_sprintf(pCtx, buf_filename, sizeof(buf_filename), "%d", j) ); lines = (int)(2500.0 * (rand() / (RAND_MAX + 1.0))); VERIFY_ERR_CHECK( MyFn(create_file__numbers)(pCtx, pPathCsDir, buf_filename, lines) ); } SG_PATHNAME_NULLFREE(pCtx, pPathCsDir); VERIFY_ERR_CHECK( _ut_pt__addremove(pCtx, pPathWorkingDir) ); VERIFY_ERR_CHECK( MyFn(commit_all)(pCtx, pPathWorkingDir, NULL) ); } /* verify pre-pull repos are different */ VERIFY_ERR_CHECK( SG_sync__compare_repo_dags(pCtx, pClientRepo, pServerRepo, &bMatch) ); VERIFY_COND_FAIL("pre-pull repos differ", !bMatch); /* get a client and pull from server repo to empty client repo */ VERIFY_ERR_CHECK( SG_client__open(pCtx, buf_server_repo_name, NULL_CREDENTIAL, &pClient) ); // TODO Credentials VERIFY_ERR_CHECK( SG_pull__all(pCtx, buf_client_repo_name, pClient, &pvaZingMergeErr, &pvaZingMergeLog) ); VERIFY_COND("", !pvaZingMergeErr); /* verify post-pull repos are identical */ VERIFY_ERR_CHECK( SG_sync__compare_repo_dags(pCtx, pClientRepo, pServerRepo, &bMatch) ); VERIFY_COND_FAIL("post-pull repo DAGs differ", bMatch); VERIFY_ERR_CHECK( SG_sync__compare_repo_blobs(pCtx, pClientRepo, pServerRepo, &bMatch) ); VERIFY_COND_FAIL("post-pull repo blobs differ", bMatch); VERIFY_ERR_CHECK( SG_repo__check_integrity(pCtx, pClientRepo, SG_REPO__CHECK_INTEGRITY__DAG_CONSISTENCY, SG_DAGNUM__VERSION_CONTROL, NULL, NULL) ); SG_REPO_NULLFREE(pCtx, pClientRepo); /* Make another copy with clone */ VERIFY_ERR_CHECK( SG_tid__generate2(pCtx, buf_client_repo_name, sizeof(buf_client_repo_name), 32) ); SG_ERR_CHECK( SG_repo__create_empty_clone_from_remote(pCtx, pClient, buf_client_repo_name) ); VERIFY_ERR_CHECK( SG_pull__clone(pCtx, buf_client_repo_name, pClient) ); /* verify post-clone repos are identical */ VERIFY_ERR_CHECK( SG_repo__open_repo_instance(pCtx, buf_client_repo_name, &pClientRepo) ); VERIFY_ERR_CHECK( SG_sync__compare_repo_dags(pCtx, pClientRepo, pServerRepo, &bMatch) ); VERIFY_COND_FAIL("post-clone repo DAGs differ", bMatch); VERIFY_ERR_CHECK( SG_sync__compare_repo_blobs(pCtx, pClientRepo, pServerRepo, &bMatch) ); VERIFY_COND_FAIL("post-clone repo blobs differ", bMatch); VERIFY_ERR_CHECK( SG_repo__check_integrity(pCtx, pClientRepo, SG_REPO__CHECK_INTEGRITY__DAG_CONSISTENCY, SG_DAGNUM__VERSION_CONTROL, NULL, NULL) ); /* TODO: verify more stuff? */ /* Fall through to common cleanup */ fail: /* close client */ SG_CLIENT_NULLFREE(pCtx, pClient); /* close both repos */ SG_REPO_NULLFREE(pCtx, pServerRepo); SG_REPO_NULLFREE(pCtx, pClientRepo); SG_NULLFREE(pCtx, pszidFirstChangeset); SG_PATHNAME_NULLFREE(pCtx, pPathTopDir); SG_PATHNAME_NULLFREE(pCtx, pPathWorkingDir); SG_PATHNAME_NULLFREE(pCtx, pPathCsDir); SG_VHASH_NULLFREE(pCtx, pvh); SG_PATHNAME_NULLFREE(pCtx, pPathWorkingDir); SG_VARRAY_NULLFREE(pCtx, pvaZingMergeLog); SG_VARRAY_NULLFREE(pCtx, pvaZingMergeErr); }
/** * Return a pathname (live or temp) to a file that contains * the CURRENTLY QUEUED content that this item **SHOULD** have * at this point in the TX. * * That is, the caller could be in the middle of a TX and have * overwritten the file once or twice and then may now be * requesting the path to show a diff. Or the file content may * be unchanged, but we have queued one or more moves/renames to * it or parent directories. * * As a good player INSIDE THE TX, we need to give them a path * to a CURRENT IN-TX COPY OF THE ***CONTENT*** (wherever it * may be). * * So the path we return may be to a temp file that was created * as a source for a QUEUED overwrite. Or it may be a path to * the unmodified content in the WD -- WHERE IT WAS BEFORE THE * TX -- because until APPLY is called, the WD hasn't been * changed yet. * * Regardless of whether the result is a temp file or not, the * caller should be careful to not let the user modify the file * without participating in the TX. That is, if we return the * actual non-temp working copy of a file and they use it in a * DIFF and the user's difftool is interactive and they alter * it and then we cancel the TX, what should the WD version of * the file contain? * * See also: * __overwrite_file_from_file() * __overwrite_file_from_repo() * __add_special() * __undo_delete() * * * We return an indication of whether the file is a TEMP file * and shouldn't be written to. It DOES NOT indicate that you * can delete it -- it indicates that you should not edit it because * *WE* will probably delete the file if the TX is rolled-back and so * the user would lose their edits. * */ void sg_wc_liveview_item__get_proxy_file_path(SG_context * pCtx, sg_wc_liveview_item * pLVI, SG_wc_tx * pWcTx, SG_pathname ** ppPath, SG_bool * pbIsTmp) { SG_string * pStringRepoPath = NULL; SG_pathname * pPathAbsolute = NULL; char * pszGid = NULL; const char * psz; SG_bool bIsTmp = SG_TRUE; if (pLVI->tneType != SG_TREENODEENTRY_TYPE_REGULAR_FILE) SG_ERR_THROW2_RETURN( SG_ERR_INVALIDARG, (pCtx, "GetProxyFilePath: '%s' is not a file.", SG_string__sz(pLVI->pStringEntryname)) ); if (pLVI->queuedOverwrites.pvhContent == NULL) { // No changes to the content yet in this TX. Return the PRE-TX // pathname of this file. (We may have QUEUED moves/renames on // the file or a parent directory, but they haven't been applied // yet.) SG_ASSERT( pLVI->pPrescanRow ); SG_ASSERT( pLVI->pPrescanRow->pStringEntryname ); SG_ASSERT( pLVI->pPrescanRow->pPrescanDir_Ref ); SG_ASSERT( pLVI->pPrescanRow->pPrescanDir_Ref->pStringRefRepoPath ); SG_ERR_CHECK( SG_STRING__ALLOC__COPY(pCtx, &pStringRepoPath, pLVI->pPrescanRow->pPrescanDir_Ref->pStringRefRepoPath) ); SG_ERR_CHECK( SG_repopath__append_entryname(pCtx, pStringRepoPath, SG_string__sz(pLVI->pPrescanRow->pStringEntryname), SG_FALSE) ); SG_ERR_CHECK( sg_wc_db__path__repopath_to_absolute(pCtx, pWcTx->pDb, pStringRepoPath, &pPathAbsolute) ); bIsTmp = SG_FALSE; // path is to actual WC file goto done; } SG_ERR_CHECK_RETURN( SG_vhash__check__sz(pCtx, pLVI->queuedOverwrites.pvhContent, "file", &psz) ); if (psz) { // return path to existing TEMP file. someone else owns the file. SG_ERR_CHECK( SG_PATHNAME__ALLOC__SZ(pCtx, &pPathAbsolute, psz) ); bIsTmp = SG_TRUE; // path is to a TEMP file (for which an overwrite-from-file has already been scheduled). goto done; } SG_ERR_CHECK_RETURN( SG_vhash__check__sz(pCtx, pLVI->queuedOverwrites.pvhContent, "hid", &psz) ); if (psz) { // synthesize a TEMP file for this. caller owns the new temp file. SG_ERR_CHECK( sg_wc_db__gid__get_gid_from_alias(pCtx, pWcTx->pDb, pLVI->uiAliasGid, &pszGid) ); SG_ERR_CHECK( sg_wc_diff_utils__export_to_temp_file(pCtx, pWcTx, "ref", pszGid, psz, SG_string__sz(pLVI->pStringEntryname), // for suffix only &pPathAbsolute) ); bIsTmp = SG_TRUE; // path is to a TEMP file that we just created. goto done; } SG_ERR_THROW2_RETURN( SG_ERR_NOTIMPLEMENTED, (pCtx, "GetProxyFilePath: required field missing from vhash for: %s", SG_string__sz(pLVI->pStringEntryname)) ); done: #if TRACE_WC_LIE SG_ERR_IGNORE( SG_console(pCtx, SG_CS_STDERR, "GetProxyFilePath: '%s' ==> '%s' [bIsTmp %d]\n", SG_string__sz(pLVI->pStringEntryname), SG_pathname__sz(pPathAbsolute), bIsTmp) ); #endif *ppPath = pPathAbsolute; pPathAbsolute = NULL; *pbIsTmp = bIsTmp; fail: SG_PATHNAME_NULLFREE(pCtx, pPathAbsolute); SG_STRING_NULLFREE(pCtx, pStringRepoPath); SG_NULLFREE(pCtx, pszGid); }
void u0052_zip__test_1(SG_context * pCtx) { SG_zip* pzip = NULL; SG_unzip* punzip = NULL; char buf_tid[SG_TID_MAX_BUFFER_LENGTH]; SG_pathname* pPath = NULL; SG_uint32 count = 0; SG_byte buf[256]; SG_uint32 iBytesRead; SG_bool b; const char* psz_name = NULL; SG_uint64 iLen = 0; VERIFY_ERR_CHECK( SG_tid__generate2(pCtx, buf_tid, sizeof(buf_tid), 32) ); VERIFY_ERR_CHECK( SG_PATHNAME__ALLOC__SZ(pCtx, &pPath, buf_tid) ); /* ---------------------------------------------------------------- */ /* Create the zip file */ /* ---------------------------------------------------------------- */ VERIFY_ERR_CHECK( SG_zip__open(pCtx, pPath, &pzip) ); #define FILE1_CONTENTS "hello world" VERIFY_ERR_CHECK( SG_zip__begin_file(pCtx, pzip, "f1") ); VERIFY_ERR_CHECK( SG_zip__write(pCtx, pzip, (SG_byte*) FILE1_CONTENTS, (SG_uint32) (1 + strlen(FILE1_CONTENTS))) ); VERIFY_ERR_CHECK( SG_zip__end_file(pCtx, pzip) ); #define FILE2_CONTENTS "this is a test of the emergency broadcast system" VERIFY_ERR_CHECK( SG_zip__begin_file(pCtx, pzip, "f2") ); VERIFY_ERR_CHECK( SG_zip__write(pCtx, pzip, (SG_byte*) FILE2_CONTENTS, (SG_uint32) (1 + strlen(FILE2_CONTENTS))) ); VERIFY_ERR_CHECK( SG_zip__end_file(pCtx, pzip) ); #define FILE3_CONTENTS "x" VERIFY_ERR_CHECK( SG_zip__begin_file(pCtx, pzip, "f3") ); VERIFY_ERR_CHECK( SG_zip__write(pCtx, pzip, (SG_byte*) FILE3_CONTENTS, (SG_uint32) (1 + strlen(FILE3_CONTENTS))) ); VERIFY_ERR_CHECK( SG_zip__end_file(pCtx, pzip) ); #define FILE4_CONTENTS "spain" VERIFY_ERR_CHECK( SG_zip__begin_file(pCtx, pzip, "f4") ); VERIFY_ERR_CHECK( SG_zip__write(pCtx, pzip, (SG_byte*) FILE4_CONTENTS, (SG_uint32) (1 + strlen(FILE4_CONTENTS))) ); VERIFY_ERR_CHECK( SG_zip__end_file(pCtx, pzip) ); VERIFY_ERR_CHECK( SG_zip__nullclose(pCtx, &pzip) ); /* ---------------------------------------------------------------- */ /* Read the zip file */ /* ---------------------------------------------------------------- */ VERIFY_ERR_CHECK( SG_unzip__open(pCtx, pPath, &punzip) ); count = 0; b = SG_FALSE; VERIFY_ERR_CHECK( SG_unzip__goto_first_file(pCtx, punzip, &b, NULL, NULL) ); while (b) { count++; VERIFY_ERR_CHECK( SG_unzip__goto_next_file(pCtx, punzip, &b, NULL, NULL) ); } VERIFY_COND("count", (4 == count)); b = SG_FALSE; VERIFY_ERR_CHECK( SG_unzip__goto_first_file(pCtx, punzip, &b, &psz_name, &iLen) ); VERIFY_COND("b", b); VERIFY_COND("name", (0 == strcmp(psz_name, "f1"))); VERIFY_COND("len", (iLen == (1 + strlen(FILE1_CONTENTS)))); b = SG_FALSE; VERIFY_ERR_CHECK( SG_unzip__goto_next_file(pCtx, punzip, &b, &psz_name, &iLen) ); VERIFY_COND("b", b); VERIFY_COND("name", (0 == strcmp(psz_name, "f2"))); VERIFY_COND("len", (iLen == (1 + strlen(FILE2_CONTENTS)))); b = SG_FALSE; VERIFY_ERR_CHECK( SG_unzip__goto_next_file(pCtx, punzip, &b, &psz_name, &iLen) ); VERIFY_COND("b", b); VERIFY_COND("name", (0 == strcmp(psz_name, "f3"))); VERIFY_COND("len", (iLen == (1 + strlen(FILE3_CONTENTS)))); b = SG_FALSE; VERIFY_ERR_CHECK( SG_unzip__goto_next_file(pCtx, punzip, &b, &psz_name, &iLen) ); VERIFY_COND("b", b); VERIFY_COND("name", (0 == strcmp(psz_name, "f4"))); VERIFY_COND("len", (iLen == (1 + strlen(FILE4_CONTENTS)))); /* verify that locate_file works */ VERIFY_ERR_CHECK( SG_unzip__locate_file(pCtx, punzip, "f2", &b, &iLen) ); VERIFY_COND("b", b); VERIFY_COND("len", (iLen == (1 + strlen(FILE2_CONTENTS)))); VERIFY_ERR_CHECK( SG_unzip__currentfile__open(pCtx, punzip) ); VERIFY_ERR_CHECK( SG_unzip__currentfile__read(pCtx, punzip, buf, sizeof(buf), &iBytesRead) ); VERIFY_ERR_CHECK( SG_unzip__currentfile__close(pCtx, punzip) ); VERIFY_COND("len", (iLen == iBytesRead)); VERIFY_COND("match", (0 == strcmp((char*) buf, FILE2_CONTENTS))); /* verify that locate_file does not disturb things when it fails */ VERIFY_ERR_CHECK( SG_unzip__locate_file(pCtx, punzip, "not there", &b, &iLen) ); VERIFY_COND("b", !b); memset(buf, 0, 20); VERIFY_ERR_CHECK( SG_unzip__currentfile__open(pCtx, punzip) ); VERIFY_ERR_CHECK( SG_unzip__currentfile__read(pCtx, punzip, buf, sizeof(buf), &iBytesRead) ); VERIFY_ERR_CHECK( SG_unzip__currentfile__close(pCtx, punzip) ); VERIFY_COND("len", ((1 + strlen(FILE2_CONTENTS)) == iBytesRead)); VERIFY_COND("match", (0 == strcmp((char*) buf, FILE2_CONTENTS))); VERIFY_ERR_CHECK( SG_unzip__nullclose(pCtx, &punzip) ); SG_PATHNAME_NULLFREE(pCtx, pPath); return; fail: SG_ERR_IGNORE( SG_unzip__nullclose(pCtx, &punzip) ); SG_PATHNAME_NULLFREE(pCtx, pPath); }
/** * Import a raw string (probably as the user typed it) and * transform it into a repo-path. And scrub it as appropriate. * * This routine is inside WC and takes a "pDb" because we need * to be able to interpret a null or relative path and convert * them into a wd-root-based current/live repo-path. * * But we also need to be able to call it for arbitrary-cset-based * repo-paths that when we don't have a WD. * * We return both the observed/computed repo-path and the * observed/computed repo-path-domain. The returned repo-path * will contain the repo-path-domain so that they are always * in normal form. * * It is up to the caller to decide whether the domain is * valid for their purposes and/or throw. * */ void sg_wc_db__path__anything_to_repopath(SG_context * pCtx, const sg_wc_db * pDb, const char * pszInput, sg_wc_db__path__import_flags flags, SG_string ** ppStringRepoPath, char * pcDomain) { SG_pathname * pPathTemp = NULL; SG_string * pStringTemp = NULL; SG_bool bValid; if (!pszInput || !*pszInput) // when null, assume either CWD or ROOT. { switch (flags) { default: case SG_WC_DB__PATH__IMPORT_FLAGS__TREAT_NULL_AS_ERROR: SG_ERR_THROW_RETURN( SG_ERR_INVALIDARG ); case SG_WC_DB__PATH__IMPORT_FLAGS__TREAT_NULL_AS_ROOT: SG_ERR_CHECK( SG_PATHNAME__ALLOC__COPY(pCtx, &pPathTemp, pDb->pPathWorkingDirectoryTop) ); SG_ERR_CHECK( sg_wc_db__path__absolute_to_repopath(pCtx, pDb, pPathTemp, ppStringRepoPath) ); SG_PATHNAME_NULLFREE(pCtx, pPathTemp); *pcDomain = SG_WC__REPO_PATH_DOMAIN__LIVE; return; case SG_WC_DB__PATH__IMPORT_FLAGS__TREAT_NULL_AS_CWD: SG_ERR_CHECK( SG_PATHNAME__ALLOC(pCtx, &pPathTemp) ); SG_ERR_CHECK( SG_pathname__set__from_cwd(pCtx, pPathTemp) ); SG_ERR_CHECK( sg_wc_db__path__absolute_to_repopath(pCtx, pDb, pPathTemp, ppStringRepoPath) ); SG_PATHNAME_NULLFREE(pCtx, pPathTemp); *pcDomain = SG_WC__REPO_PATH_DOMAIN__LIVE; return; } } if (pszInput[0] != '@') // a non-repo pathname { SG_bool bPathIsRelative = SG_FALSE; SG_ERR_CHECK( SG_pathname__is_relative(pCtx, pszInput, &bPathIsRelative) ); if (bPathIsRelative) SG_ERR_CHECK( _check_if_relative_paths_allowed(pCtx, pDb) ); SG_ERR_CHECK( SG_PATHNAME__ALLOC__SZ(pCtx, &pPathTemp, pszInput) ); SG_ERR_CHECK( sg_wc_db__path__absolute_to_repopath(pCtx, pDb, pPathTemp, ppStringRepoPath) ); SG_PATHNAME_NULLFREE(pCtx, pPathTemp); *pcDomain = SG_WC__REPO_PATH_DOMAIN__LIVE; return; } // if they gave us something that started with a "@" we // either return it as is or throw if we can't parse it. // this ensures that any error messages don't leave the // domain out of the repo-path. switch (pszInput[1]) { case 0: SG_ERR_THROW2_RETURN( SG_ERR_INVALIDARG, (pCtx, "The input '%s' is not a valid repo-path input.", pszInput) ); case SG_WC__REPO_PATH_DOMAIN__G: // domain "@g..." is a GID and not a path. // A '@g' domain input should look like // "@gae9ce8e7eaf04b58aef9470b439329f32249aae2358511e1b77b002500da2b78" // That is, the 'g' domain specifier is shared with the 'g' in the // full GID. For now a full GID is required; we don't try to do the // unique prefix trick like we do for CSET HIDs in a REV-SPEC. We // may think about adding that later. SG_ERR_CHECK( SG_gid__verify_format(pCtx, &pszInput[1], &bValid) ); if (!bValid) SG_ERR_THROW2( SG_ERR_INVALIDARG, (pCtx, "The input '%s' is not a valid gid-domain input.", pszInput) ); SG_ERR_CHECK( SG_STRING__ALLOC__SZ(pCtx, ppStringRepoPath, pszInput) ); *pcDomain = SG_WC__REPO_PATH_DOMAIN__G; return; case SG_WC__REPO_PATH_DOMAIN__T: // domain "@t..." is a temporary GID and not a path. // A '@t' domain input should look like // "@tae9ce8e7eaf04b58aef9470b439329f32249aae2358511e1b77b002500da2b78" // That is, the 't' domain specifier replaces the normal 'g' in the // full GID. For now a full GID is required; we don't try to do the // unique prefix trick like we do for CSET HIDs in a REV-SPEC. We // may think about adding that later. We use a 't' when reporting // STATUS rather than a 'g' as a reminder that the ID is only valid // until the end of the transaction. // // make a g-version of the string so we can validate it. // but still return the t-version. SG_ERR_CHECK( SG_STRING__ALLOC(pCtx, &pStringTemp) ); SG_ERR_CHECK( SG_string__sprintf(pCtx, pStringTemp, "%c%s", SG_WC__REPO_PATH_DOMAIN__G, &pszInput[2]) ); SG_ERR_CHECK( SG_gid__verify_format(pCtx, SG_string__sz(pStringTemp), &bValid) ); SG_STRING_NULLFREE(pCtx, pStringTemp); if (!bValid) SG_ERR_THROW2( SG_ERR_INVALIDARG, (pCtx, "The input '%s' is not a valid temp-gid-domain input.", pszInput) ); SG_ERR_CHECK( SG_STRING__ALLOC__SZ(pCtx, ppStringRepoPath, pszInput) ); *pcDomain = SG_WC__REPO_PATH_DOMAIN__T; return; case SG_WC__REPO_PATH_DOMAIN__LIVE: // domain "@/foo..." is a normal current/live repo-path SG_ERR_CHECK( _complain_if_unnormalized(pCtx, &pszInput[1]) ); SG_ERR_CHECK( SG_STRING__ALLOC__SZ(pCtx, ppStringRepoPath, pszInput) ); *pcDomain = SG_WC__REPO_PATH_DOMAIN__LIVE; return; default: // we allow any other SINGLE character to be a domain. if (pszInput[2] != '/') SG_ERR_THROW2_RETURN( SG_ERR_INVALIDARG, (pCtx, "The input '%s' is not a valid repo-path input.", pszInput) ); // we have "@x/foo...." for some character x. SG_ERR_CHECK( _complain_if_unnormalized(pCtx, &pszInput[2]) ); SG_ERR_CHECK( SG_STRING__ALLOC__SZ(pCtx, ppStringRepoPath, pszInput) ); *pcDomain = pszInput[1]; return; } fail: SG_PATHNAME_NULLFREE(pCtx, pPathTemp); SG_STRING_NULLFREE(pCtx, pStringTemp); }
int u0040_unc__stat_dir(SG_context * pCtx, const char * szDir) { SG_pathname * pPathname = NULL; SG_pathname * pPathnameFile = NULL; SG_file * pf = NULL; SG_fsobj_stat fsobjStat; SG_bool bFileExists; SG_int_to_string_buffer bufSize; char bufDate[100]; SG_context__err_reset(pCtx); ////////////////////////////////////////////////////////////////// // stat the given directory. ////////////////////////////////////////////////////////////////// INFOP("u0040_unc",("Inspecting [%s]",szDir)); VERIFY_ERR_CHECK_RETURN( SG_PATHNAME__ALLOC__SZ(pCtx,&pPathname,szDir) ); VERIFY_ERR_CHECK( SG_fsobj__stat__pathname(pCtx,pPathname,&fsobjStat) ); VERIFY_COND("u0040_unc",(fsobjStat.type == SG_FSOBJ_TYPE__DIRECTORY)); // TODO should we verify length == 0 ? // TODO should we verify modtime ? SG_uint64_to_sz(fsobjStat.size, bufSize); VERIFY_ERR_CHECK_DISCARD( SG_time__format_utc__i64(pCtx,fsobjStat.mtime_ms,bufDate,SG_NrElements(bufDate)) ); INFOP("u0040_unc",("Result: [perms %04o][type %d][size %s][mtime %s]", fsobjStat.perms,fsobjStat.type, bufSize,bufDate)); ////////////////////////////////////////////////////////////////// // create a unique file in the directory and stat it. ////////////////////////////////////////////////////////////////// VERIFY_ERR_CHECK( unittest__alloc_unique_pathname(pCtx,szDir,&pPathnameFile) ); INFOP("u0040_unc",(" Creating file [%s]",SG_pathname__sz(pPathnameFile))); VERIFY_ERR_CHECK( SG_file__open__pathname(pCtx,pPathnameFile,SG_FILE_CREATE_NEW | SG_FILE_RDWR,0777,&pf) ); VERIFY_ERR_CHECK( SG_fsobj__stat__pathname(pCtx,pPathnameFile,&fsobjStat) ); VERIFY_COND("u0040_unc",(fsobjStat.type == SG_FSOBJ_TYPE__REGULAR)); VERIFY_COND("u0040_unc",(fsobjStat.size == 0)); VERIFY_COND("u0040_unc",(SG_fsobj__equivalent_perms(fsobjStat.perms,0777))); // TODO should we verify modtime ? SG_uint64_to_sz(fsobjStat.size, bufSize); VERIFY_ERR_CHECK_DISCARD( SG_time__format_utc__i64(pCtx,fsobjStat.mtime_ms,bufDate,SG_NrElements(bufDate)) ); INFOP("u0040_unc",(" Result: [perms %04o][type %d][size %s][mtime %s]", fsobjStat.perms,fsobjStat.type, bufSize,bufDate)); VERIFY_ERR_CHECK_DISCARD( SG_file__close(pCtx, &pf) ); // delete the file and stat it again VERIFY_ERR_CHECK_DISCARD( SG_fsobj__remove__pathname(pCtx,pPathnameFile) ); VERIFY_ERR_CHECK_DISCARD( SG_fsobj__exists__pathname(pCtx,pPathnameFile,&bFileExists,NULL,NULL) ); VERIFY_COND("u0040_unc",(!bFileExists)); ////////////////////////////////////////////////////////////////// // clean up ////////////////////////////////////////////////////////////////// SG_PATHNAME_NULLFREE(pCtx, pPathnameFile); SG_PATHNAME_NULLFREE(pCtx, pPathname); return 1; fail: SG_FILE_NULLCLOSE(pCtx, pf); SG_PATHNAME_NULLFREE(pCtx, pPathnameFile); SG_PATHNAME_NULLFREE(pCtx, pPathname); return 0; }