void u0051_hidlookup__create_file__numbers( SG_context* pCtx, SG_pathname* pPath, const char* pszName, const SG_uint32 countLines ) { SG_pathname* pPathFile = NULL; SG_uint32 i; SG_file* pFile = NULL; VERIFY_ERR_CHECK( SG_PATHNAME__ALLOC__PATHNAME_SZ(pCtx, &pPathFile, pPath, pszName) ); VERIFY_ERR_CHECK( SG_file__open__pathname(pCtx, pPathFile, SG_FILE_CREATE_NEW | SG_FILE_RDWR, 0600, &pFile) ); for (i=0; i<countLines; i++) { char buf[64]; VERIFY_ERR_CHECK( SG_sprintf(pCtx, buf, sizeof(buf), "%d\n", i) ); VERIFY_ERR_CHECK( SG_file__write(pCtx, pFile, (SG_uint32) strlen(buf), (SG_byte*) buf, NULL) ); } VERIFY_ERR_CHECK( SG_file__close(pCtx, &pFile) ); SG_PATHNAME_NULLFREE(pCtx, pPathFile); return; fail: SG_FILE_NULLCLOSE(pCtx, pFile); SG_PATHNAME_NULLFREE(pCtx, pPathFile); }
void SG_unzip__fetch_next_file_into_file(SG_context* pCtx, SG_unzip* punzip, SG_pathname* pPath, SG_bool* pb, const char** ppsz_name, SG_uint64* piLength) { SG_byte* pBytes = NULL; SG_uint32 sofar = 0; SG_uint32 got = 0; SG_file* pFile = NULL; SG_bool b = SG_FALSE; SG_uint64 len = 0; const char* psz_name = NULL; SG_ERR_CHECK( SG_unzip__goto_next_file(pCtx, punzip, &b, &psz_name, &len) ); if (!b) { *pb = SG_FALSE; goto done; } SG_ERR_CHECK( SG_malloc(pCtx, (SG_uint32)SG_STREAMING_BUFFER_SIZE, &pBytes) ); SG_ERR_CHECK( SG_file__open__pathname(pCtx, pPath, SG_FILE_WRONLY | SG_FILE_CREATE_NEW, 0644, &pFile) ); SG_ERR_CHECK( SG_unzip__currentfile__open(pCtx, punzip) ); while (sofar < (SG_uint32) len) { SG_uint32 want = 0; if ((len - sofar) > SG_STREAMING_BUFFER_SIZE) { want = SG_STREAMING_BUFFER_SIZE; } else { want = (SG_uint32) (len - sofar); } SG_ERR_CHECK( SG_unzip__currentfile__read(pCtx, punzip, pBytes, want, &got) ); if (!got) { SG_ERR_THROW( SG_ERR_UNSPECIFIED ); /* TODO better error */ } SG_ERR_CHECK( SG_file__write(pCtx, pFile, got, pBytes, NULL) ); sofar += got; } SG_NULLFREE(pCtx, pBytes); SG_ERR_CHECK( SG_file__close(pCtx, &pFile) ); SG_ERR_CHECK( SG_unzip__currentfile__close(pCtx, punzip) ); *pb = SG_TRUE; *ppsz_name = psz_name; *piLength = len; done: /* fall through */ fail: SG_FILE_NULLCLOSE(pCtx, pFile); SG_NULLFREE(pCtx, pBytes); }
void SG_random__generate_random_binary_file(SG_context * pCtx, SG_pathname * pPath, SG_uint64 length) { SG_file * pFile = NULL; SG_NULLARGCHECK_RETURN(pPath); SG_ERR_CHECK( SG_file__open__pathname(pCtx, pPath, SG_FILE_OPEN_OR_CREATE|SG_FILE_WRONLY, 0644, &pFile) ); SG_ERR_CHECK( SG_random__write_random_bytes_to_file(pCtx, pFile, length) ); SG_ERR_CHECK( SG_file__close(pCtx, &pFile) ); return; fail: SG_FILE_NULLCLOSE(pCtx, pFile); }
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); }
int u0020_utf8pathnames__create_file(SG_context * pCtx, const SG_pathname * pPathnameTmpDir, _tableitem * pti) { // create a file in the given tmp dir using the given filename. SG_pathname * pPathnameNewFile; char * pBufUtf8; SG_uint32 lenUtf8; SG_file * pFile; int iResult; SG_bool bTest; // convert the utf32 string into utf8. VERIFY_ERR_CHECK_DISCARD( SG_utf8__from_utf32(pCtx, pti->pa32,&pBufUtf8,&lenUtf8) ); // we have to free pBufUtf8 // verify that the computed utf8 string matches what we thought it should be. // (this hopefully guards against the conversion layer playing NFC/NFD tricks.) iResult = SG_utf8__compare(pBufUtf8,(char *)pti->pa8); VERIFYP_COND("u0020_utf8pathnames",(iResult==0),("Compare failed [%s][%s]",pBufUtf8,pti->pa8)); // create full pathname to the file to create. VERIFY_ERR_CHECK_DISCARD( SG_PATHNAME__ALLOC__PATHNAME_SZ(pCtx, &pPathnameNewFile, pPathnameTmpDir,pBufUtf8) ); // create the file and close it. // on Linux when our locale is set to something other than UTF-8, we may // get an ICU(10) == U_INVALID_CHAR_FOUND error because the test data is // not necessarily friendly to any one locale and there are some NFD // cases too. we map ICU(10) to SG_ERR_UNMAPPABLE_UNICODE_CHAR SG_file__open__pathname(pCtx,pPathnameNewFile,SG_FILE_WRONLY|SG_FILE_CREATE_NEW,0755,&pFile); #if defined(LINUX) bTest = ( (!SG_context__has_err(pCtx)) || (SG_context__err_equals(pCtx,SG_ERR_UNMAPPABLE_UNICODE_CHAR)) ); #else bTest = ( (!SG_context__has_err(pCtx)) ); #endif SG_context__err_reset(pCtx); VERIFYP_COND("u0020_utf8pathnames",bTest, ("Error Creating file [%s]",SG_pathname__sz(pPathnameNewFile))); VERIFY_ERR_CHECK_DISCARD( SG_file__close(pCtx, &pFile) ); SG_PATHNAME_NULLFREE(pCtx, pPathnameNewFile); SG_NULLFREE(pCtx, pBufUtf8); return 1; }
void _read_template_file( SG_context *pCtx, const char *templateFn, SG_string **pContent, /**< we allocate, we free on error, else caller owns it */ const _request_headers *pRequestHeaders, _replacer_cb replacer) { SG_pathname *tpath = NULL; SG_file *pFile = NULL; SG_uint32 got = 0; char tbuf[1024]; //todo: make this thread-safe: if(_sg_uridispatch__templatePath==NULL) SG_ERR_CHECK( _sgui_set_templatePath(pCtx) ); SG_ERR_CHECK( SG_PATHNAME__ALLOC__COPY(pCtx, &tpath, _sg_uridispatch__templatePath) ); SG_ERR_CHECK( SG_pathname__append__from_sz(pCtx, tpath, templateFn) ); SG_ERR_CHECK( SG_file__open__pathname(pCtx, tpath, SG_FILE_RDONLY|SG_FILE_OPEN_EXISTING, 0644, &pFile) ); SG_PATHNAME_NULLFREE(pCtx, tpath); SG_ERR_CHECK( SG_STRING__ALLOC(pCtx, pContent) ); do { SG_file__read(pCtx, pFile, sizeof(tbuf), (SG_byte *)tbuf, &got); if (SG_context__err_equals(pCtx, SG_ERR_EOF)) { SG_context__err_reset(pCtx); break; } SG_ERR_CHECK_CURRENT; SG_ERR_CHECK( SG_string__append__buf_len(pCtx, *pContent, (const SG_byte *)tbuf, got) ); } while (got > 0); SG_ERR_CHECK( SG_file__close(pCtx, &pFile) ); SG_ERR_CHECK( _templatize(pCtx, *pContent, pRequestHeaders, replacer) ); return; fail: SG_STRING_NULLFREE(pCtx, *pContent); SG_FILE_NULLCLOSE(pCtx, pFile); SG_PATHNAME_NULLFREE(pCtx, tpath); }
/** * Export a blob-of-interest from the REPO into a temporary directory * so that we can let the external diff tool compare it with another * version somewhere. * * We create a file with a GID-based name rather than re-creating * the working-directory hierarchy in the temp directory. This lets * us flatten the export in one directory without collisions and * avoids move/rename and added/deleted sub-directory issues. * * pPathTempSessionDir should be something like "$TMPDIR/gid_session/". * This should be a unique directory name such that everything being * exported is isolated from other runs. (if we are doing a * changeset-vs-changeset diff, we may create lots of files on each * side -- and our command should not interfere with other diffs * in progress in other processes.) * * szVersion should be a value to let us group everything from cset[0] * in a different directory from stuff from cset[1]. this might be * simply "0" and "1" or it might be the cset's HIDs. * * szGidObject is the gid of the object. * * szHidBlob is the HID of the content. Normally this is the content * of the file that will be compared (corresponding to a user-file * under version control). However, we may also want to use this * to splat the XATTRs to a file so that they can be compared (on * non-apple systems) -- but this may be too weird. * * You are responsible for freeing the returned pathname and * deleting the file that we create. */ void SG_diff_utils__export_to_temp_file(SG_context * pCtx, SG_repo * pRepo, const SG_pathname * pPathTempSessionDir, // value of "$TMPDIR/session/" const char * szVersion, // an index (like 0 or 1, _older_ _newer_) or maybe cset HID const char * szGidObject, const char * szHidBlob, SG_pathname ** ppPathTempFile) { SG_pathname * pPathFile = NULL; SG_file * pFile = NULL; SG_bool bDirExists; // mkdir $TMPDIR/session/version // create pathname for the temp file: $TMPDIR/session/version/object_gid // // TODO do we want to append the suffix from the file to this pathname so that // TODO tools like SGDM can use it? what if the file is renamed and given a // TODO different suffix between versions? SG_ERR_CHECK( SG_PATHNAME__ALLOC__PATHNAME_SZ(pCtx,&pPathFile,pPathTempSessionDir,szVersion) ); SG_ERR_CHECK( SG_fsobj__exists__pathname(pCtx,pPathFile,&bDirExists,NULL,NULL) ); if (!bDirExists) SG_ERR_CHECK( SG_fsobj__mkdir_recursive__pathname(pCtx,pPathFile) ); SG_ERR_CHECK( SG_pathname__append__from_sz(pCtx,pPathFile,szGidObject) ); // open the file and copy the contents of the blob into it SG_ERR_CHECK( SG_file__open__pathname(pCtx,pPathFile,SG_FILE_WRONLY|SG_FILE_CREATE_NEW,0600,&pFile) ); SG_ERR_CHECK( SG_repo__fetch_blob_into_file(pCtx,pRepo,szHidBlob,pFile,NULL) ); SG_ERR_CHECK( SG_file__close(pCtx,&pFile) ); *ppPathTempFile = pPathFile; return; fail: if (pFile) // only if **WE** created the file, do we try to delete it on an error. { SG_FILE_NULLCLOSE(pCtx,pFile); SG_ERR_IGNORE( SG_fsobj__remove__pathname(pCtx,pPathFile) ); } SG_PATHNAME_NULLFREE(pCtx, pPathFile); }
void SG_unzip__nullclose(SG_context* pCtx, SG_unzip** pp) { SG_unzip* s = *pp; if (!s) { return; } if (s->pfile_in_zip_read) { SG_ERR_CHECK( SG_unzip__currentfile__close(pCtx, s) ); } SG_ERR_CHECK( SG_file__close(pCtx, &s->pFile) ); SG_NULLFREE(pCtx, s); fail: return; }
static void read_entire_stream__file( SG_context* pCtx, CFReadStreamRef myReadStream, SG_pathname* pPath, CFHTTPMessageRef* pp, SG_bool b_progress ) { CFHTTPMessageRef myResponse = NULL; CFIndex numBytesRead = 0; SG_file* pFile = NULL; SG_int64 content_length = 0; SG_int64 so_far = 0; SG_ERR_CHECK( SG_file__open__pathname(pCtx, pPath, SG_FILE_CREATE_NEW | SG_FILE_WRONLY, 0644, &pFile) ); do { UInt8 buf[8192]; // TODO numBytesRead = CFReadStreamRead(myReadStream, buf, sizeof(buf)); if( numBytesRead > 0 ) { SG_ERR_CHECK( SG_file__write(pCtx, pFile, numBytesRead, buf, NULL) ); if (!myResponse) { myResponse = (CFHTTPMessageRef)CFReadStreamCopyProperty(myReadStream, kCFStreamPropertyHTTPResponseHeader); CFStringRef contentLengthString = CFHTTPMessageCopyHeaderFieldValue(myResponse, CFSTR("Content-Length")); if (contentLengthString) { // TODO 32 bit limit problem here content_length = CFStringGetIntValue(contentLengthString); CFRelease(contentLengthString); } if (b_progress) { SG_ERR_CHECK( SG_log__set_steps(pCtx, content_length / 1024, "KB") ); } } so_far += (SG_uint32) numBytesRead; if (b_progress) { SG_ERR_CHECK( SG_log__set_finished(pCtx, so_far / 1024) ); } } else if( numBytesRead < 0 ) { CFStreamError myErr = CFReadStreamGetError(myReadStream); // TODO clean this up if (myErr.domain == kCFStreamErrorDomainPOSIX) { if (ETIMEDOUT == myErr.error) { usleep(5000); numBytesRead = 0; } else { // Interpret myErr.error as a UNIX errno. SG_ERR_THROW( SG_ERR_ERRNO(myErr.error) ); } } else if (myErr.domain == kCFStreamErrorDomainMacOSStatus) { // Interpret myErr.error as a MacOS error code. // TODO SG_ERR_THROW( SG_ERR_MAC((OSStatus) myErr.error) ); SG_ERR_THROW( SG_ERR_UNSPECIFIED ); } } } while( numBytesRead > 0 ); SG_ERR_CHECK( SG_file__close(pCtx, &pFile) ); if (!myResponse) { myResponse = (CFHTTPMessageRef)CFReadStreamCopyProperty(myReadStream, kCFStreamPropertyHTTPResponseHeader); } *pp = myResponse; myResponse = NULL; fail: if (pFile) { SG_ERR_CHECK( SG_file__close(pCtx, &pFile) ); // TODO delete it too } if (myResponse) { CFRelease(myResponse); } }
void MyFn(create_blob_from_file)(SG_context * pCtx, SG_repo * pRepo, const SG_pathname * pPathnameTempDir, SG_uint64 lenFile, const char * szSrc) { // create a file of length "lenFile" in the temp directory. // use it to create a blob. // try to create it a second time and verify that we get an duplicate-hid error. char* pszidGidRandom1 = NULL; char* pszidGidRandom2 = NULL; SG_pathname * pPathnameTempFile1 = NULL; SG_pathname * pPathnameTempFile2 = NULL; SG_file * pFileTempFile1 = NULL; SG_file * pFileTempFile2 = NULL; SG_uint32 lenSrc; SG_uint64 lenWritten; char* pszidHidBlob1 = NULL; char* pszidHidBlob1Dup = NULL; char* pszidHidBlob2 = NULL; char* pszidHidVerify1 = NULL; char* pszidHidVerify2 = NULL; SG_bool bEqual; SG_repo_tx_handle* pTx = NULL; SG_uint64 iBlobFullLength = 0; ////////////////////////////////////////////////////////////////// // create temp-file-1 of length "lenFile" in the temp directory. VERIFY_ERR_CHECK_DISCARD( SG_gid__alloc(pCtx, &pszidGidRandom1) ); VERIFY_ERR_CHECK_DISCARD( SG_gid__alloc(pCtx, &pszidGidRandom2) ); VERIFY_ERR_CHECK_DISCARD( SG_PATHNAME__ALLOC__PATHNAME_SZ(pCtx, &pPathnameTempFile1,pPathnameTempDir,(pszidGidRandom1)) ); VERIFY_ERR_CHECK_DISCARD( SG_file__open__pathname(pCtx, pPathnameTempFile1,SG_FILE_RDWR|SG_FILE_CREATE_NEW,0644,&pFileTempFile1) ); // write random gid at the beginning of the file // so that we won't get collisions if we are called // multiple times. VERIFY_ERR_CHECK_DISCARD( SG_file__write(pCtx, pFileTempFile1,(SG_uint32)strlen(pszidGidRandom1),(SG_byte *)pszidGidRandom1,NULL) ); VERIFY_ERR_CHECK_DISCARD( SG_file__write(pCtx, pFileTempFile1,1,(SG_byte *)"\n",NULL) ); // generate lots of data in the file so that we'll cause the // blob routines to exercise the chunking stuff. lenSrc = (SG_uint32)strlen(szSrc); lenWritten = 0; while (lenWritten < lenFile) { VERIFY_ERR_CHECK_DISCARD( SG_file__write(pCtx, pFileTempFile1,lenSrc,(SG_byte *)szSrc,NULL) ); lenWritten += lenSrc; } // the test file does NOT have a final LF. i'm not sure it matters one way or the // other, but i'm just saying that we're not putting on a final LF. SG_ERR_IGNORE( SG_file__seek(pCtx, pFileTempFile1,0) ); ////////////////////////////////////////////////////////////////// // use currently open temp file to create a blob. // we get the HID back. (we need to free it later.) VERIFY_ERR_CHECK_DISCARD( SG_repo__begin_tx(pCtx, pRepo, &pTx) ); VERIFY_ERR_CHECK_DISCARD( SG_repo__store_blob_from_file(pCtx, pRepo,pTx,NULL,SG_FALSE,pFileTempFile1,&pszidHidBlob1,&iBlobFullLength) ); VERIFY_ERR_CHECK_DISCARD( SG_repo__commit_tx(pCtx, pRepo, &pTx) ); INFOP("create_blob_from_file",("Created blob [%s]",(pszidHidBlob1))); ////////////////////////////////////////////////////////////////// // try to create blob again and verify we get an duplicate-hid error. // Ian TODO: Put this back when SG_ERR_BLOBFILEALREADYEXISTS has been replaced. // VERIFY_ERR_CHECK_DISCARD( SG_repo__begin_tx(pCtx, pRepo, &pTx) ); // err = SG_repo__store_blob_from_file(pRepo,pTx,SG_FALSE,pFileTempFile1,&pszidHidBlob1Dup); // VERIFYP_CTX_ERR_IS("create_blob_from_file(duplicate)", pCtx, SG_ERR_BLOBFILEALREADYEXISTS, ("Duplicate create failed [%s][%s]",pszidHidBlob1,pszidHidBlob1Dup)); // VERIFY_ERR_CHECK_DISCARD( SG_repo__commit_tx(pCtx, pRepo, SG_DAGNUM__NONE, NULL, &pTx) ); ////////////////////////////////////////////////////////////////// // create empty temp-file-2 and try to read the blob from the repo. VERIFY_ERR_CHECK_DISCARD( SG_PATHNAME__ALLOC__PATHNAME_SZ(pCtx, &pPathnameTempFile2,pPathnameTempDir,(pszidGidRandom2)) ); VERIFY_ERR_CHECK_DISCARD( SG_file__open__pathname(pCtx, pPathnameTempFile2,SG_FILE_RDWR|SG_FILE_CREATE_NEW,0644,&pFileTempFile2) ); VERIFY_ERR_CHECK_DISCARD( SG_repo__fetch_blob_into_file(pCtx, pRepo,pszidHidBlob1,pFileTempFile2,NULL) ); ////////////////////////////////////////////////////////////////// // verify that the contents of temp-file-2 is identical to the // contents of temp-file-1. (we already know that the HIDs match // and was verified during the fetch, but there are times when the // HID is just being used as a key -- it doesn't mean that what we // actually restored is correct. VERIFY_ERR_CHECK_DISCARD( SG_repo__alloc_compute_hash__from_file(pCtx, pRepo, pFileTempFile1, &pszidHidVerify1) ); VERIFY_ERR_CHECK_DISCARD( SG_repo__alloc_compute_hash__from_file(pCtx, pRepo, pFileTempFile2, &pszidHidVerify2) ); bEqual = (0 == (strcmp(pszidHidVerify1,pszidHidVerify2))); VERIFY_COND("create_blob_from_file(verify v1==v2)",bEqual); bEqual = (0 == (strcmp(pszidHidVerify1,pszidHidBlob1))); VERIFY_COND("create_blob_from_file(verify v1==id)",bEqual); ////////////////////////////////////////////////////////////////// // TODO delete temp source file SG_ERR_IGNORE( SG_file__close(pCtx, &pFileTempFile1) ); SG_ERR_IGNORE( SG_file__close(pCtx, &pFileTempFile2) ); ////////////////////////////////////////////////////////////////// // cleanup SG_NULLFREE(pCtx, pszidGidRandom1); SG_NULLFREE(pCtx, pszidGidRandom2); SG_NULLFREE(pCtx, pszidHidBlob1); SG_NULLFREE(pCtx, pszidHidBlob1Dup); SG_NULLFREE(pCtx, pszidHidBlob2); SG_NULLFREE(pCtx, pszidHidVerify1); SG_NULLFREE(pCtx, pszidHidVerify2); SG_PATHNAME_NULLFREE(pCtx, pPathnameTempFile1); SG_PATHNAME_NULLFREE(pCtx, pPathnameTempFile2); }
static void _sg_workingdir__get_entry2(SG_context * pCtx, SG_repo * pRepo, const SG_pathname * pPathSub, const char * pszGid, SG_treenode_entry_type type, const char * pszidHidContent, const char * pszidHidXattrs, SG_int64 iAttributeBits, SG_vhash * pvhTimestamps) { SG_file* pFile = NULL; SG_string* pstrLink = NULL; SG_byte* pBytes = NULL; SG_vhash * pvhGid = NULL; if (SG_TREENODEENTRY_TYPE_DIRECTORY == type) { /* create the directory and then recurse into it */ SG_ERR_CHECK( SG_fsobj__mkdir__pathname(pCtx, pPathSub) ); SG_ERR_CHECK( _sg_workingdir__get_dir(pCtx, pRepo, pPathSub, pszidHidContent, pvhTimestamps) ); } else if (SG_TREENODEENTRY_TYPE_REGULAR_FILE == type) { SG_ERR_CHECK( SG_file__open__pathname(pCtx, pPathSub, SG_FILE_RDWR | SG_FILE_CREATE_NEW, SG_FSOBJ_PERMS__MASK, &pFile) ); SG_ERR_CHECK( SG_repo__fetch_blob_into_file(pCtx, pRepo, pszidHidContent, pFile, NULL) ); SG_ERR_CHECK( SG_file__close(pCtx, &pFile) ); } else if (SG_TREENODEENTRY_TYPE_SYMLINK == type) { SG_uint64 iLenBytes = 0; SG_ERR_CHECK( SG_repo__fetch_blob_into_memory(pCtx, pRepo, pszidHidContent, &pBytes, &iLenBytes) ); SG_ERR_CHECK( SG_STRING__ALLOC__BUF_LEN(pCtx, &pstrLink, pBytes, (SG_uint32) iLenBytes) ); SG_ERR_CHECK( SG_fsobj__symlink(pCtx, pstrLink, pPathSub) ); SG_NULLFREE(pCtx, pBytes); SG_STRING_NULLFREE(pCtx, pstrLink); } else { SG_ERR_THROW(SG_ERR_NOTIMPLEMENTED); } if (pszidHidXattrs) { #ifdef SG_BUILD_FLAG_FEATURE_XATTR SG_ERR_CHECK( _sg_workingdir__set_xattrs(pCtx, pRepo, pPathSub, pszidHidXattrs) ); #else // TODO do we need to stuff something into the pendingtree to remind us // TODO that the entry originally had an XAttr and we just didn't restore // TODO it when we populated the WD on this Windows system? #endif } SG_ERR_CHECK( SG_attributes__bits__apply(pCtx, pPathSub, iAttributeBits) ); if (pvhTimestamps && (SG_TREENODEENTRY_TYPE_REGULAR_FILE == type)) { SG_fsobj_stat stat; SG_int64 iTimeNow; SG_ERR_CHECK( SG_fsobj__stat__pathname(pCtx, pPathSub, &stat) ); SG_ERR_CHECK( SG_time__get_milliseconds_since_1970_utc(pCtx, &iTimeNow) ); SG_ERR_CHECK( SG_VHASH__ALLOC(pCtx, &pvhGid) ); SG_ERR_CHECK( SG_vhash__add__int64(pCtx, pvhGid, "mtime_ms", stat.mtime_ms) ); SG_ERR_CHECK( SG_vhash__add__int64(pCtx, pvhGid, "clock_ms", iTimeNow) ); SG_ERR_CHECK( SG_vhash__add__vhash(pCtx, pvhTimestamps, pszGid, &pvhGid) ); // this steals our vhash } fail: SG_VHASH_NULLFREE(pCtx, pvhGid); }
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; }