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); }
/** * Export the contents of the given file entry (which reflects a specific version) * into a temp file so that an external tool can use it. * * You own the returned pathname and the file on disk. */ void _sg_mrg__export_to_temp_file(SG_context * pCtx, SG_mrg * pMrg, const char * pszHidBlob, const SG_pathname * pPathTempFile) { SG_file * pFile = NULL; SG_bool bExists; SG_ERR_CHECK( SG_fsobj__exists__pathname(pCtx,pPathTempFile,&bExists,NULL,NULL) ); if (bExists) { #if TRACE_WC_MERGE SG_ERR_IGNORE( SG_console(pCtx,SG_CS_STDERR, "Skipping export of [blob %s] to [%s]\n",pszHidBlob,SG_pathname__sz(pPathTempFile)) ); #endif } else { #if TRACE_WC_MERGE SG_ERR_IGNORE( SG_console(pCtx,SG_CS_STDERR, "Exporting [blob %s] to [%s]\n",pszHidBlob,SG_pathname__sz(pPathTempFile)) ); #endif // Ideally, when we create this TEMP file it should be read-only. // Afterall, it does represent a historical version of the file and // it should only be used as INPUT to whatever merge tool the user // has configured. So it should be read-only. This might allow // a GUI merge tool to show locks/whatever and/or prevent accidental // editing of these files. // // However, this can cause an "Access is Denied" error on Windows // when we get ready to delete the contents of the TEMP directory. // We'll deal with that there rather than here. SG_ERR_CHECK( SG_file__open__pathname(pCtx,pPathTempFile,SG_FILE_WRONLY|SG_FILE_CREATE_NEW,0400,&pFile) ); SG_ERR_CHECK( SG_repo__fetch_blob_into_file(pCtx, pMrg->pWcTx->pDb->pRepo, pszHidBlob,pFile,NULL) ); SG_FILE_NULLCLOSE(pCtx,pFile); } return; fail: if (pFile) // only if **WE** created the file, do we try to delete it on error. { SG_FILE_NULLCLOSE(pCtx,pFile); SG_ERR_IGNORE( SG_fsobj__remove__pathname(pCtx,pPathTempFile) ); } }
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_vfile__end( SG_context* pCtx, SG_vfile** ppvf, const SG_vhash* pvh ) { SG_string* pstr = NULL; SG_vfile* pvf = NULL; SG_NULLARGCHECK_RETURN(ppvf); pvf = *ppvf; if (pvh) { SG_ARGCHECK_RETURN( !(pvf->mode & SG_FILE_RDONLY) , pvh ); SG_ERR_CHECK( SG_STRING__ALLOC(pCtx, &pstr) ); SG_ERR_CHECK( SG_vhash__to_json(pCtx, pvh,pstr) ); SG_ERR_CHECK( SG_file__seek(pCtx, pvf->pFile, 0) ); SG_ERR_CHECK( SG_file__truncate(pCtx, pvf->pFile) ); #if TRACE_VFILE SG_ERR_IGNORE( SG_console(pCtx, SG_CS_STDERR, "VFileEnd: Writing %d bytes to file.\n", SG_string__length_in_bytes(pstr)) ); #endif SG_ERR_CHECK( SG_file__write(pCtx, pvf->pFile, SG_string__length_in_bytes(pstr), (const SG_byte *)SG_string__sz(pstr), NULL) ); SG_STRING_NULLFREE(pCtx, pstr); } else { if (!(pvf->mode & SG_FILE_RDONLY)) { SG_ERR_CHECK( SG_file__seek(pCtx, pvf->pFile, 0) ); SG_ERR_CHECK( SG_file__truncate(pCtx, pvf->pFile) ); #if TRACE_VFILE SG_ERR_IGNORE( SG_console(pCtx, SG_CS_STDERR, "VFileEnd: Truncating file.\n") ); #endif } } SG_FILE_NULLCLOSE(pCtx, pvf->pFile); SG_NULLFREE(pCtx, pvf); *ppvf = NULL; return; fail: SG_STRING_NULLFREE(pCtx, pstr); }
void sg_vfile__dispose( SG_context* pCtx, SG_vfile* pvf ) { if (!pvf) return; SG_FILE_NULLCLOSE(pCtx, pvf->pFile); SG_NULLFREE(pCtx, pvf); }
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); }
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); }
void SG_vfile__abort( SG_context* pCtx, SG_vfile** ppvf ) { SG_vfile* pvf = NULL; if (!ppvf) return; pvf = *ppvf; if (!pvf) return; SG_FILE_NULLCLOSE(pCtx, pvf->pFile); SG_NULLFREE(pCtx, pvf); *ppvf = NULL; }
/** * 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_vfile__begin( SG_context* pCtx, const SG_pathname* pPath, /**< The path of the file containing the JSON text */ SG_file_flags mode, SG_vhash** ppvh, /**< If there are no errors, the resulting vhash table will be returned here. */ SG_vfile** ppvf ) { SG_vfile* pvf = NULL; SG_vhash* pvh = NULL; SG_uint32 len32; SG_fsobj_type t; SG_byte* p = NULL; SG_bool bExists; SG_fsobj_type FsObjType; SG_fsobj_perms FsObjPerms; SG_ERR_CHECK( SG_fsobj__exists__pathname(pCtx, pPath, &bExists, &FsObjType, &FsObjPerms) ); if ( bExists && (SG_FSOBJ_TYPE__REGULAR != FsObjType) ) { SG_ERR_THROW_RETURN(SG_ERR_NOTAFILE); } if (bExists) { SG_uint64 len64; SG_ERR_CHECK( SG_fsobj__length__pathname(pCtx, pPath, &len64, &t) ); // TODO "len" is uint64 because we can have huge files, but // TODO our buffer is limited to uint32 (on 32bit systems). // TODO verify that len will fit in uint32. len32 = (SG_uint32)len64; } else { len32 = 0; } SG_ERR_CHECK_RETURN( SG_alloc1(pCtx, pvf) ); SG_ERR_CHECK( SG_file__open__pathname(pCtx, pPath, mode | SG_FILE_LOCK, SG_FSOBJ_PERMS__UNUSED, &pvf->pFile) ); pvf->mode = mode; #if TRACE_VFILE SG_ERR_IGNORE( SG_console(pCtx, SG_CS_STDERR, "VFileBegin: Reading %d bytes from %s\n", len32, SG_pathname__sz(pPath)) ); #endif if (len32 > 0) { SG_ERR_CHECK( SG_alloc(pCtx, 1,len32+1,&p) ); SG_ERR_CHECK( SG_file__read(pCtx, pvf->pFile, len32, p, NULL) ); p[len32] = 0; SG_ERR_CHECK( SG_VHASH__ALLOC__FROM_JSON(pCtx, &pvh, (const char*) p) ); SG_NULLFREE(pCtx, p); p = NULL; } else { pvh = NULL; } *ppvf = pvf; *ppvh = pvh; return; fail: SG_FILE_NULLCLOSE(pCtx, pvf->pFile); SG_NULLFREE(pCtx, p); SG_NULLFREE(pCtx, pvf); }
static void sg_read_entire_file( SG_context* pCtx, const SG_pathname* pPath, char** ppbuf, SG_uint32* plen ) { SG_uint32 len32; SG_fsobj_type t; SG_byte* p = NULL; SG_bool bExists; SG_fsobj_type FsObjType; SG_fsobj_perms FsObjPerms; SG_file* pFile = NULL; SG_ERR_CHECK( SG_fsobj__exists__pathname(pCtx, pPath, &bExists, &FsObjType, &FsObjPerms) ); if ( bExists && (SG_FSOBJ_TYPE__REGULAR != FsObjType) ) { SG_ERR_IGNORE( SG_log__report_error(pCtx, "Unable to open file: %s.", SG_pathname__sz(pPath)) ); SG_ERR_THROW_RETURN(SG_ERR_NOTAFILE); } if (bExists) { SG_uint64 len64; SG_ERR_CHECK( SG_fsobj__length__pathname(pCtx, pPath, &len64, &t) ); // TODO "len" is uint64 because we can have huge files, but // TODO our buffer is limited to uint32 (on 32bit systems). // TODO verify that len will fit in uint32. len32 = (SG_uint32)len64; SG_ERR_CHECK( SG_file__open__pathname(pCtx, pPath, SG_FILE_RDONLY | SG_FILE_OPEN_EXISTING, SG_FSOBJ_PERMS__UNUSED, &pFile) ); } else { SG_ERR_THROW_RETURN(SG_ERR_NOTAFILE); //len32 = 0; } if (len32 > 0) { SG_ERR_CHECK( SG_alloc(pCtx, 1,len32+1,&p) ); SG_ERR_CHECK( SG_file__read(pCtx, pFile, len32, p, NULL) ); p[len32] = 0; *ppbuf = (char*) p; p = NULL; *plen = len32; } else { *ppbuf = NULL; *plen = 0; } fail: SG_FILE_NULLCLOSE(pCtx, pFile); SG_NULLFREE(pCtx, p); }
void SG_unzip__open(SG_context* pCtx, const SG_pathname* pPath, SG_unzip** ppResult) { SG_unzip us; SG_unzip *s; SG_uint64 central_pos = 0; SG_uint32 uL; SG_uint16 number_disk = 0; /* number of the current dist, used for spaning ZIP, unsupported, always 0*/ SG_uint16 number_disk_with_CD = 0; /* number the the disk with central dir, used for spaning ZIP, unsupported, always 0*/ SG_uint16 number_entry_CD = 0; /* total number of entries in the central dir (same than number_entry on nospan) */ SG_ERR_CHECK( SG_file__open__pathname(pCtx, pPath, SG_FILE_RDONLY | SG_FILE_OPEN_EXISTING, SG_FSOBJ_PERMS__UNUSED, &us.pFile) ); SG_ERR_CHECK( sg_unzip__locate_central_dir(pCtx, us.pFile, ¢ral_pos) ); SG_ERR_CHECK( SG_file__seek(pCtx, us.pFile, central_pos) ); /* the signature, already checked */ SG_ERR_CHECK( sg_unzip__get_uint32(pCtx, us.pFile,&uL) ); /* number of this disk */ SG_ERR_CHECK( sg_unzip__get_uint16(pCtx, us.pFile,&number_disk) ); /* number of the disk with the start of the central directory */ SG_ERR_CHECK( sg_unzip__get_uint16(pCtx, us.pFile,&number_disk_with_CD) ); /* total number of entries in the central dir on this disk */ SG_ERR_CHECK( sg_unzip__get_uint16(pCtx, us.pFile,&us.gi.number_entry) ); /* total number of entries in the central dir */ SG_ERR_CHECK( sg_unzip__get_uint16(pCtx, us.pFile,&number_entry_CD) ); if ((number_entry_CD!=us.gi.number_entry) || (number_disk_with_CD!=0) || (number_disk!=0)) { SG_ERR_THROW( SG_ERR_ZIP_BAD_FILE ); } /* size of the central directory */ SG_ERR_CHECK( sg_unzip__get_uint32(pCtx, us.pFile,&us.size_central_dir) ); /* offset of start of central directory with respect to the starting disk number */ SG_ERR_CHECK( sg_unzip__get_uint32(pCtx, us.pFile,&us.offset_central_dir) ); /* zipfile comment length */ SG_ERR_CHECK( sg_unzip__get_uint16(pCtx, us.pFile,&us.gi.size_comment) ); if (central_pos<us.offset_central_dir+us.size_central_dir) { SG_ERR_THROW( SG_ERR_ZIP_BAD_FILE ); } us.byte_before_the_zipfile = (SG_uint32) (central_pos - (us.offset_central_dir+us.size_central_dir)); us.central_pos = central_pos; us.pfile_in_zip_read = NULL; us.current_file_ok = SG_FALSE; SG_ERR_CHECK( SG_malloc(pCtx, sizeof(SG_unzip), &s) ); *s=us; *ppResult = s; return; fail: /* TODO free stuff */ SG_FILE_NULLCLOSE(pCtx, us.pFile); }
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; }
/** * create 1 test file. * cat it to a second file using files bound to child's STDIN and STDOUT. * cat both files to third file using cl args for input and third bound to child's STDOUT. * cat all 3 files using cl args to OUR STDOUT. */ void MyFn(test1)(SG_context * pCtx) { SG_exit_status exitStatusChild; SG_file * pFileF1 = NULL; SG_file * pFileF2 = NULL; SG_file * pFileF3 = NULL; SG_pathname * pPathTempDir = NULL; SG_pathname * pPathF1 = NULL; SG_pathname * pPathF2 = NULL; SG_pathname * pPathF3 = NULL; SG_exec_argvec * pArgVec = NULL; // create a GID temp directory in the current directory. VERIFY_ERR_CHECK( unittest__alloc_unique_pathname_in_cwd(pCtx,&pPathTempDir) ); VERIFY_ERR_CHECK( SG_fsobj__mkdir_recursive__pathname(pCtx,pPathTempDir) ); // create a couple of pathnames to test files in the temp directory. VERIFY_ERR_CHECK( unittest__alloc_unique_pathname_in_dir(pCtx,SG_pathname__sz(pPathTempDir),&pPathF1) ); INFOP("exec",("PathF1 is %s",SG_pathname__sz(pPathF1))); VERIFY_ERR_CHECK( unittest__alloc_unique_pathname_in_dir(pCtx,SG_pathname__sz(pPathTempDir),&pPathF2) ); INFOP("exec",("PathF2 is %s",SG_pathname__sz(pPathF2))); VERIFY_ERR_CHECK( unittest__alloc_unique_pathname_in_dir(pCtx,SG_pathname__sz(pPathTempDir),&pPathF3) ); INFOP("exec",("PathF3 is %s",SG_pathname__sz(pPathF3))); ////////////////////////////////////////////////////////////////// // create F1 and write some data to it. VERIFY_ERR_CHECK( SG_file__open__pathname(pCtx,pPathF1,SG_FILE_WRONLY|SG_FILE_CREATE_NEW,0644,&pFileF1) ); VERIFY_ERR_CHECK( SG_file__write(pCtx,pFileF1, SG_pathname__length_in_bytes(pPathF1), (SG_byte *)SG_pathname__sz(pPathF1), NULL) ); VERIFY_ERR_CHECK( SG_file__write(pCtx,pFileF1, 1, (SG_byte *)"\n", NULL) ); VERIFY_ERR_CHECK( SG_file__write(pCtx,pFileF1, SG_pathname__length_in_bytes(pPathF1), (SG_byte *)SG_pathname__sz(pPathF1), NULL) ); VERIFY_ERR_CHECK( SG_file__write(pCtx,pFileF1, 1, (SG_byte *)"\n", NULL) ); SG_FILE_NULLCLOSE(pCtx, pFileF1); ////////////////////////////////////////////////////////////////// // re-open F1 for reading. // create F2 as a place for STDOUT of command. VERIFY_ERR_CHECK( SG_file__open__pathname(pCtx,pPathF1,SG_FILE_RDONLY|SG_FILE_OPEN_EXISTING,0644,&pFileF1) ); VERIFY_ERR_CHECK( SG_file__open__pathname(pCtx,pPathF2,SG_FILE_WRONLY|SG_FILE_CREATE_NEW, 0644,&pFileF2) ); // exec: /bin/cat <f1 >f2 VERIFY_ERR_CHECK( SG_exec__exec_sync__files(pCtx,MY_CAT_COMMAND,NULL,pFileF1,pFileF2,NULL,&exitStatusChild) ); VERIFY_COND("child status",(exitStatusChild == 0)); INFOP("/bin/cat <f1 >f2",("Child exit status is [%d]",exitStatusChild)); SG_FILE_NULLCLOSE(pCtx, pFileF1); SG_FILE_NULLCLOSE(pCtx, pFileF2); ////////////////////////////////////////////////////////////////// // let F1 and F2 be given on the command line. // create F3 as a place for STDOUT of command. VERIFY_ERR_CHECK( SG_file__open__pathname(pCtx,pPathF3,SG_FILE_WRONLY|SG_FILE_CREATE_NEW, 0644,&pFileF3) ); // exec: /bin/cat -n f1 f2 >f3 VERIFY_ERR_CHECK( SG_exec_argvec__alloc(pCtx,&pArgVec) ); VERIFY_ERR_CHECK( SG_exec_argvec__append__sz(pCtx,pArgVec,"-n") ); VERIFY_ERR_CHECK( SG_exec_argvec__append__sz(pCtx,pArgVec,SG_pathname__sz(pPathF1)) ); VERIFY_ERR_CHECK( SG_exec_argvec__append__sz(pCtx,pArgVec,SG_pathname__sz(pPathF2)) ); VERIFY_ERR_CHECK( SG_exec__exec_sync__files(pCtx,MY_CAT_COMMAND,pArgVec,NULL,pFileF3,NULL,&exitStatusChild) ); VERIFY_COND("child status",(exitStatusChild == 0)); INFOP("/bin/cat -n f1 f2 >f3",("Child exit status is [%d]",exitStatusChild)); SG_FILE_NULLCLOSE(pCtx, pFileF3); SG_EXEC_ARGVEC_NULLFREE(pCtx, pArgVec); ////////////////////////////////////////////////////////////////// // exec: /bin/cat f1 f2 f3 (to our stdout) VERIFY_ERR_CHECK( SG_exec_argvec__alloc(pCtx,&pArgVec) ); VERIFY_ERR_CHECK( SG_exec_argvec__append__sz(pCtx,pArgVec,SG_pathname__sz(pPathF1)) ); VERIFY_ERR_CHECK( SG_exec_argvec__append__sz(pCtx,pArgVec,SG_pathname__sz(pPathF2)) ); VERIFY_ERR_CHECK( SG_exec_argvec__append__sz(pCtx,pArgVec,SG_pathname__sz(pPathF3)) ); VERIFY_ERR_CHECK( SG_exec__exec_sync__files(pCtx,MY_CAT_COMMAND,pArgVec,NULL,NULL,NULL,&exitStatusChild) ); VERIFY_COND("child status",(exitStatusChild == 0)); INFOP("/bin/cat -n f1 f2 f3",("Child exit status is [%d]",exitStatusChild)); SG_EXEC_ARGVEC_NULLFREE(pCtx, pArgVec); ////////////////////////////////////////////////////////////////// // exec: /bin/cat f3 f2 f1 (to our stdout) VERIFY_ERR_CHECK( SG_exec_argvec__alloc(pCtx,&pArgVec) ); VERIFY_ERR_CHECK( SG_exec_argvec__append__sz(pCtx,pArgVec,SG_pathname__sz(pPathF3)) ); VERIFY_ERR_CHECK( SG_exec_argvec__append__sz(pCtx,pArgVec,SG_pathname__sz(pPathF2)) ); VERIFY_ERR_CHECK( SG_exec_argvec__append__sz(pCtx,pArgVec,SG_pathname__sz(pPathF1)) ); VERIFY_ERR_CHECK( SG_exec__exec_sync__files(pCtx,MY_CAT_COMMAND,pArgVec,NULL,NULL,NULL,&exitStatusChild) ); VERIFY_COND("child status",(exitStatusChild == 0)); INFOP("/bin/cat -n f3 f2 f1",("Child exit status is [%d]",exitStatusChild)); SG_EXEC_ARGVEC_NULLFREE(pCtx, pArgVec); // fall through to common cleanup. fail: SG_EXEC_ARGVEC_NULLFREE(pCtx, pArgVec); SG_PATHNAME_NULLFREE(pCtx, pPathTempDir); SG_PATHNAME_NULLFREE(pCtx, pPathF1); SG_PATHNAME_NULLFREE(pCtx, pPathF2); SG_PATHNAME_NULLFREE(pCtx, pPathF3); SG_FILE_NULLCLOSE(pCtx, pFileF1); SG_FILE_NULLCLOSE(pCtx, pFileF2); SG_FILE_NULLCLOSE(pCtx, pFileF3); }
/** * create 1 test file. * cat it to a second file using files bound to child's STDIN and STDOUT. * repeat using still open files. * verify that we get an append effect. * * do this again using input file on the command line into a third file. */ void MyFn(test2)(SG_context * pCtx) { SG_exit_status exitStatusChild; SG_file * pFileF1 = NULL; SG_file * pFileF2 = NULL; SG_file * pFileF3 = NULL; SG_pathname * pPathTempDir = NULL; SG_pathname * pPathF1 = NULL; SG_pathname * pPathF2 = NULL; SG_pathname * pPathF3 = NULL; SG_exec_argvec * pArgVec = NULL; SG_uint64 lenFileF1, lenFileF2, lenFileF3; SG_uint64 posFileF1, posFileF2, posFileF3; // create a GID temp directory in the current directory. VERIFY_ERR_CHECK( unittest__alloc_unique_pathname_in_cwd(pCtx,&pPathTempDir) ); VERIFY_ERR_CHECK( SG_fsobj__mkdir_recursive__pathname(pCtx,pPathTempDir) ); // create a couple of pathnames to test files in the temp directory. VERIFY_ERR_CHECK( unittest__alloc_unique_pathname_in_dir(pCtx,SG_pathname__sz(pPathTempDir),&pPathF1) ); INFOP("exec",("PathF1 is %s",SG_pathname__sz(pPathF1))); VERIFY_ERR_CHECK( unittest__alloc_unique_pathname_in_dir(pCtx,SG_pathname__sz(pPathTempDir),&pPathF2) ); INFOP("exec",("PathF2 is %s",SG_pathname__sz(pPathF2))); VERIFY_ERR_CHECK( unittest__alloc_unique_pathname_in_dir(pCtx,SG_pathname__sz(pPathTempDir),&pPathF3) ); INFOP("exec",("PathF3 is %s",SG_pathname__sz(pPathF3))); ////////////////////////////////////////////////////////////////// // create F1 and write some data to it. VERIFY_ERR_CHECK( SG_file__open__pathname(pCtx,pPathF1,SG_FILE_WRONLY|SG_FILE_CREATE_NEW,0644,&pFileF1) ); VERIFY_ERR_CHECK( SG_file__write(pCtx,pFileF1, SG_pathname__length_in_bytes(pPathF1), (SG_byte *)SG_pathname__sz(pPathF1), NULL) ); VERIFY_ERR_CHECK( SG_file__write(pCtx,pFileF1, 1, (SG_byte *)"\n", NULL) ); SG_FILE_NULLCLOSE(pCtx, pFileF1); // get length of F1 as created on disk. VERIFY_ERR_CHECK( SG_fsobj__length__pathname(pCtx,pPathF1,&lenFileF1,NULL) ); INFOP("lenCheck",("Length F1[%d]",(SG_uint32)lenFileF1)); VERIFY_COND("lenCheck",(lenFileF1 > 0)); ////////////////////////////////////////////////////////////////// // re-open F1 for reading. // create F2 as a place for STDOUT of command. VERIFY_ERR_CHECK( SG_file__open__pathname(pCtx,pPathF1,SG_FILE_RDONLY|SG_FILE_OPEN_EXISTING,0644,&pFileF1) ); VERIFY_ERR_CHECK( SG_file__open__pathname(pCtx,pPathF2,SG_FILE_WRONLY|SG_FILE_CREATE_NEW, 0644,&pFileF2) ); // exec: "/bin/cat <f1 >f2" three times holding the file handles open between runs. VERIFY_ERR_CHECK( SG_exec__exec_sync__files(pCtx,MY_CAT_COMMAND,NULL,pFileF1,pFileF2,NULL,&exitStatusChild) ); VERIFY_COND("child status",(exitStatusChild == 0)); INFOP("/bin/cat <f1 >f2",("Child exit status is [%d]",exitStatusChild)); VERIFY_ERR_CHECK( SG_file__tell(pCtx,pFileF1,&posFileF1) ); VERIFY_ERR_CHECK( SG_file__tell(pCtx,pFileF2,&posFileF2) ); INFOP("tell",("Position F1[%d] Position F2[%d]",(SG_uint32)posFileF1,(SG_uint32)posFileF2)); VERIFY_COND("tell",(posFileF1 == lenFileF1)); // child has dup'd version of handles and so we share seek positions. VERIFY_COND("tell",(posFileF2 == posFileF1)); // so, the child should have caused our position to change. VERIFY_ERR_CHECK( SG_file__seek(pCtx,pFileF1,0) ); VERIFY_ERR_CHECK( SG_exec__exec_sync__files(pCtx,MY_CAT_COMMAND,NULL,pFileF1,pFileF2,NULL,&exitStatusChild) ); VERIFY_COND("child status",(exitStatusChild == 0)); INFOP("/bin/cat <f1 >f2",("Child exit status is [%d]",exitStatusChild)); VERIFY_ERR_CHECK( SG_file__tell(pCtx,pFileF1,&posFileF1) ); VERIFY_ERR_CHECK( SG_file__tell(pCtx,pFileF2,&posFileF2) ); INFOP("tell",("Position F1[%d] Position F2[%d]",(SG_uint32)posFileF1,(SG_uint32)posFileF2)); VERIFY_COND("tell",(posFileF1 == lenFileF1)); // child has dup'd version of handles and so we share seek positions. VERIFY_COND("tell",(posFileF2 == 2*posFileF1)); // so, the child should have caused our position to change. VERIFY_ERR_CHECK( SG_file__seek(pCtx,pFileF1,0) ); VERIFY_ERR_CHECK( SG_exec__exec_sync__files(pCtx,MY_CAT_COMMAND,NULL,pFileF1,pFileF2,NULL,&exitStatusChild) ); VERIFY_COND("child status",(exitStatusChild == 0)); INFOP("/bin/cat <f1 >f2",("Child exit status is [%d]",exitStatusChild)); VERIFY_ERR_CHECK( SG_file__tell(pCtx,pFileF1,&posFileF1) ); VERIFY_ERR_CHECK( SG_file__tell(pCtx,pFileF2,&posFileF2) ); INFOP("tell",("Position F1[%d] Position F2[%d]",(SG_uint32)posFileF1,(SG_uint32)posFileF2)); VERIFY_COND("tell",(posFileF1 == lenFileF1)); // child has dup'd version of handles and so we share seek positions. VERIFY_COND("tell",(posFileF2 == 3*posFileF1)); // so, the child should have caused our position to change. SG_FILE_NULLCLOSE(pCtx, pFileF1); SG_FILE_NULLCLOSE(pCtx, pFileF2); // get length of F2 and see how it compares with F1. VERIFY_ERR_CHECK( SG_fsobj__length__pathname(pCtx,pPathF2,&lenFileF2,NULL) ); INFOP("lenCheck",("Length F1[%d] Length F2[%d]",(SG_uint32)lenFileF1,(SG_uint32)lenFileF2)); VERIFY_COND("lenCheck",(lenFileF2 == 3*lenFileF1)); ////////////////////////////////////////////////////////////////// // let F1 be given on the command line. // create F3 as a place for STDOUT of command. VERIFY_ERR_CHECK( SG_file__open__pathname(pCtx,pPathF3,SG_FILE_WRONLY|SG_FILE_CREATE_NEW, 0644,&pFileF3) ); // exec: "/bin/cat f1 >f3" three times holding F3 open between runs. VERIFY_ERR_CHECK( SG_exec_argvec__alloc(pCtx,&pArgVec) ); VERIFY_ERR_CHECK( SG_exec_argvec__append__sz(pCtx,pArgVec,SG_pathname__sz(pPathF1)) ); VERIFY_ERR_CHECK( SG_exec__exec_sync__files(pCtx,MY_CAT_COMMAND,pArgVec,NULL,pFileF3,NULL,&exitStatusChild) ); VERIFY_COND("child status",(exitStatusChild == 0)); INFOP("/bin/cat f1 >f3",("Child exit status is [%d]",exitStatusChild)); VERIFY_ERR_CHECK( SG_file__tell(pCtx,pFileF3,&posFileF3) ); INFOP("tell",("Position F3[%d]",(SG_uint32)posFileF3)); VERIFY_COND("tell",(posFileF3 == lenFileF1)); VERIFY_ERR_CHECK( SG_exec__exec_sync__files(pCtx,MY_CAT_COMMAND,pArgVec,NULL,pFileF3,NULL,&exitStatusChild) ); VERIFY_COND("child status",(exitStatusChild == 0)); INFOP("/bin/cat f1 >f3",("Child exit status is [%d]",exitStatusChild)); VERIFY_ERR_CHECK( SG_file__tell(pCtx,pFileF3,&posFileF3) ); INFOP("tell",("Position F3[%d]",(SG_uint32)posFileF3)); VERIFY_COND("tell",(posFileF3 == 2*lenFileF1)); VERIFY_ERR_CHECK( SG_exec__exec_sync__files(pCtx,MY_CAT_COMMAND,pArgVec,NULL,pFileF3,NULL,&exitStatusChild) ); VERIFY_COND("child status",(exitStatusChild == 0)); INFOP("/bin/cat f1 >f3",("Child exit status is [%d]",exitStatusChild)); VERIFY_ERR_CHECK( SG_file__tell(pCtx,pFileF3,&posFileF3) ); INFOP("tell",("Position F3[%d]",(SG_uint32)posFileF3)); VERIFY_COND("tell",(posFileF3 == 3*lenFileF1)); SG_FILE_NULLCLOSE(pCtx, pFileF3); // get length of F3 and see how it compares with F1. VERIFY_ERR_CHECK( SG_fsobj__length__pathname(pCtx,pPathF3,&lenFileF3,NULL) ); INFOP("lenCheck",("Length F1[%d] Length F3[%d]",(SG_uint32)lenFileF1,(SG_uint32)lenFileF3)); VERIFY_COND("tell",(lenFileF3 == 3*lenFileF1)); ////////////////////////////////////////////////////////////////// // fall through to common cleanup. fail: SG_EXEC_ARGVEC_NULLFREE(pCtx, pArgVec); SG_PATHNAME_NULLFREE(pCtx, pPathTempDir); SG_PATHNAME_NULLFREE(pCtx, pPathF1); SG_PATHNAME_NULLFREE(pCtx, pPathF2); SG_PATHNAME_NULLFREE(pCtx, pPathF3); SG_FILE_NULLCLOSE(pCtx, pFileF1); SG_FILE_NULLCLOSE(pCtx, pFileF2); SG_FILE_NULLCLOSE(pCtx, pFileF3); }