Beispiel #1
0
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 perform_upload_request__string(
    SG_context* pCtx,
    CFHTTPMessageRef myRequest,
    SG_pathname* pPath,
    CFHTTPMessageRef* pmyResponse,
    SG_string** ppstr
)
{
    CFReadStreamRef myReadStream = NULL;
    CFHTTPMessageRef myResponse = NULL;
    SG_string* pstr = NULL;
    CFReadStreamRef upload = NULL;
    CFURLRef upload_file_url = NULL;

    // set the content-length header
    {
        SG_uint64 len = 0;
        SG_ERR_CHECK(  SG_fsobj__length__pathname(pCtx, pPath, &len, NULL)  );

        CFStringRef headerFieldName = CFSTR("Content-Length");
        CFStringRef headerFieldValue = CFStringCreateWithFormat (kCFAllocatorDefault, NULL,  CFSTR("%d"), len);
        CFHTTPMessageSetHeaderFieldValue(myRequest, headerFieldName, headerFieldValue);
        CFRelease(headerFieldValue);
    }

    upload_file_url = CFURLCreateFromFileSystemRepresentation(kCFAllocatorDefault, (UInt8*) SG_pathname__sz(pPath), SG_STRLEN(SG_pathname__sz(pPath)), SG_FALSE);
    upload = CFReadStreamCreateWithFile(kCFAllocatorDefault, upload_file_url);
    CFRelease(upload_file_url);
    if (!CFReadStreamOpen(upload))
    {
        CFStreamError myErr = CFReadStreamGetError(upload);

        if (myErr.domain == kCFStreamErrorDomainPOSIX)
        {
            // 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  );
        }
    }

    SG_ERR_CHECK(  send_upload_request(pCtx, myRequest, upload, &myReadStream)  );
    SG_ERR_CHECK(  read_entire_stream__string(pCtx, myReadStream, &pstr, &myResponse)  );

    *ppstr = pstr;
    pstr = NULL;

    *pmyResponse = myResponse;
    myResponse = NULL;

fail:
    if (upload)
    {
        CFRelease(upload);
    }
    if (myReadStream)
    {
        CFReadStreamClose(myReadStream);
        CFRelease(myReadStream);
        myReadStream = NULL;
    }

    if (myResponse)
    {
        CFRelease(myResponse);
        myResponse = NULL;
    }

    SG_STRING_NULLFREE(pCtx, pstr);
}
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);
}
/**
 * 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);
}