diff options
Diffstat (limited to 'src/pal/src/cruntime/filecrt.cpp')
-rw-r--r-- | src/pal/src/cruntime/filecrt.cpp | 571 |
1 files changed, 571 insertions, 0 deletions
diff --git a/src/pal/src/cruntime/filecrt.cpp b/src/pal/src/cruntime/filecrt.cpp new file mode 100644 index 0000000000..48079b309c --- /dev/null +++ b/src/pal/src/cruntime/filecrt.cpp @@ -0,0 +1,571 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/*++ + + + +Module Name: + + filecrt.cpp + +Abstract: + + Implementation of the file functions in the C runtime library that + are Windows specific. + + + +--*/ + +#include "pal/thread.hpp" +#include "pal/file.hpp" + +#include "pal/palinternal.h" +#include "pal/dbgmsg.h" +#include "pal/file.h" +#include "pal/cruntime.h" + +#include <unistd.h> +#include <errno.h> +#include <sys/stat.h> + +#ifdef __APPLE__ +#include <sys/syscall.h> +#endif // __APPLE__ + +using namespace CorUnix; + +SET_DEFAULT_DEBUG_CHANNEL(CRT); + +/*++ +Function: + _open_osfhandle + +See MSDN doc. +--*/ +int +__cdecl +_open_osfhandle( INT_PTR osfhandle, int flags ) +{ + PAL_ERROR palError = NO_ERROR; + CPalThread *pthrCurrent = NULL; + IPalObject *pobjFile = NULL; + CFileProcessLocalData *pLocalData = NULL; + IDataLock *pDataLock = NULL; + INT nRetVal = -1; + INT openFlags = 0; + + PERF_ENTRY(_open_osfhandle); + ENTRY( "_open_osfhandle (osfhandle=%#x, flags=%#x)\n", osfhandle, flags ); + + pthrCurrent = InternalGetCurrentThread(); + + if (flags != _O_RDONLY) + { + ASSERT("flag(%#x) not supported\n", flags); + goto EXIT; + } + + openFlags |= O_RDONLY; + + palError = g_pObjectManager->ReferenceObjectByHandle( + pthrCurrent, + reinterpret_cast<HANDLE>(osfhandle), + &aotFile, + 0, + &pobjFile + ); + + if (NO_ERROR != palError) + { + ERROR("Error dereferencing file handle\n"); + goto EXIT; + } + + palError = pobjFile->GetProcessLocalData( + pthrCurrent, + ReadLock, + &pDataLock, + reinterpret_cast<void **>(&pLocalData) + ); + + if (NO_ERROR == palError) + { + if ('\0' != pLocalData->unix_filename[0]) + { + nRetVal = InternalOpen(pLocalData->unix_filename, openFlags); + } + else /* the only file object with no unix_filename is a pipe */ + { + /* check if the file pipe descrptor is for read or write */ + if (pLocalData->open_flags == O_WRONLY) + { + ERROR( "Couldn't open a write pipe on read mode\n"); + goto EXIT; + } + + nRetVal = pLocalData->unix_fd; + } + + if ( nRetVal == -1 ) + { + ERROR( "Error: %s.\n", strerror( errno ) ); + } + } + else + { + ASSERT("Unable to access file data"); + } + +EXIT: + + if (NULL != pDataLock) + { + pDataLock->ReleaseLock(pthrCurrent, FALSE); + } + + if (NULL != pobjFile) + { + pobjFile->ReleaseReference(pthrCurrent); + } + + LOGEXIT( "_open_osfhandle return nRetVal:%d\n", nRetVal); + PERF_EXIT(_open_osfhandle); + return nRetVal; +} + + +/*++ +Function: + PAL_fflush + +See MSDN for more details. +--*/ +int +_cdecl +PAL_fflush( PAL_FILE *stream ) +{ + int nRetVal = 0; + + PERF_ENTRY(fflush); + ENTRY( "fflush( %p )\n", stream ); + + nRetVal = fflush(stream ? stream->bsdFilePtr : NULL); + + LOGEXIT( "fflush returning %d\n", nRetVal ); + PERF_EXIT(fflush); + return nRetVal; +} + + +/*++ +PAL__getcwd + +Wrapper function for getcwd. + +Input parameters: + +szBuf = a copy of the absolute pathname of the current working directory +is copied into szBuf. +nSize = size, in bytes, of the array referenced by szBuf. + +Return value: + A pointer to the pathname if successful, otherwise NULL is returned +--*/ +char * +__cdecl +PAL__getcwd( + char *szBuf, + size_t nSize + ) +{ + return (char *)getcwd(szBuf, nSize); +} + + +/*++ +PAL_mkstemp + +Wrapper function for InternalMkstemp. + +Input parameters: + +szNameTemplate = template to follow when naming the created file + +Return value: + Open file descriptor on success, -1 if file could not be created +--*/ +int +__cdecl +PAL_mkstemp(char *szNameTemplate) +{ + return InternalMkstemp(szNameTemplate); +} + +/*++ +InternalMkstemp + +Wrapper for mkstemp. + +Input parameters: + +szNameTemplate = template to follow when naming the created file + +Return value: + Open file descriptor on success, -1 if file could not be created +--*/ +int +CorUnix::InternalMkstemp( + char *szNameTemplate + ) +{ + int nRet = -1; +#if MKSTEMP64_IS_USED_INSTEAD_OF_MKSTEMP + nRet = mkstemp64(szNameTemplate); +#else + nRet = mkstemp(szNameTemplate); +#endif + return nRet; +} + + +/*++ +PAL__open + +Wrapper function for InternalOpen. + +Input parameters: + +szPath = pointer to a pathname of a file to be opened +nFlags = arguments that control how the file should be accessed +mode = file permission settings that are used only when a file is created + +Return value: + File descriptor on success, -1 on failure +--*/ +int +__cdecl +PAL__open( + const char *szPath, + int nFlags, + ... + ) +{ + int nRet = -1; + int mode = 0; + va_list ap; + + // If nFlags does not contain O_CREAT, the mode parameter will be ignored. + if (nFlags & O_CREAT) + { + va_start(ap, nFlags); + mode = va_arg(ap, int); + va_end(ap); + } + + nRet = InternalOpen(szPath, nFlags, mode); + return nRet; +} + +/*++ +InternalOpen + +Wrapper for open. + +Input parameters: + +szPath = pointer to a pathname of a file to be opened +nFlags = arguments that control how the file should be accessed +mode = file permission settings that are used only when a file is created + +Return value: + File descriptor on success, -1 on failure +--*/ +int +CorUnix::InternalOpen( + const char *szPath, + int nFlags, + ... + ) +{ + int nRet = -1; + int mode = 0; + va_list ap; + + // If nFlags does not contain O_CREAT, the mode parameter will be ignored. + if (nFlags & O_CREAT) + { + va_start(ap, nFlags); + mode = va_arg(ap, int); + va_end(ap); + } + +#if OPEN64_IS_USED_INSTEAD_OF_OPEN + nRet = open64(szPath, nFlags, mode); +#else + nRet = open(szPath, nFlags, mode); +#endif + return nRet; +} + + +/*++ +PAL_rename + +Wrapper function for rename. + +Input parameters: + +szOldName = pointer to the pathname of the file to be renamed +szNewName = pointer to the new pathname of the file + +Return value: + Returns 0 on success and -1 on failure +--*/ +int +__cdecl +PAL_rename( + const char *szOldName, + const char *szNewName + ) +{ + return rename(szOldName, szNewName); +} + + +/*++ +PAL_fgets + +Wrapper function for InternalFgets. + +Input parameters: + +sz = stores characters read from the given file stream +nSize = number of characters to be read +pf = stream to read characters from + +Return value: + Returns a pointer to the string storing the characters on success + and NULL on failure. +--*/ +char * +__cdecl +PAL_fgets( + char *sz, + int nSize, + PAL_FILE *pf + ) +{ + char * szBuf; + + PERF_ENTRY(fgets); + ENTRY( "fgets(sz=%p (%s) nSize=%d pf=%p)\n", sz, sz, nSize, pf); + + if (pf != NULL) + { + szBuf = InternalFgets(sz, nSize, pf->bsdFilePtr, pf->bTextMode); + } + else + { + szBuf = NULL; + } + + LOGEXIT("fgets() returns %p\n", szBuf); + PERF_EXIT(fgets); + + return szBuf; +} + +/*++ +InternalFgets + +Wrapper for fgets. + +Input parameters: + +sz = stores characters read from the given file stream +nSize = number of characters to be read +f = stream to read characters from +fTextMode = flag that indicates if file contents are text or binary + +Return value: + Returns a pointer to the string storing the characters on success + and NULL on failure. + +Notes: +In Unix systems, fgets() can return an error if it gets interrupted by a +signal before reading anything, and errno is set to EINTR. When this +happens, it is SOP to call fgets again. +--*/ +char * +CorUnix::InternalFgets( + char *sz, + int nSize, + FILE *f, + bool fTextMode + ) +{ + char *retval = NULL; + + _ASSERTE(sz != NULL); + _ASSERTE(f != NULL); + +#if FILE_OPS_CHECK_FERROR_OF_PREVIOUS_CALL + clearerr(f); +#endif + + do + { + retval = fgets(sz, nSize, f); + if (NULL==retval) + { + if (feof(f)) + { + TRACE("Reached EOF\n"); + break; + } + /* The man page suggests using ferror and feof to distinguish + between error and EOF, but feof and errno is sufficient. + Not all cases that set errno also flag ferror, so just + checking errno is the best solution. */ + if (EINTR != errno) + { + WARN("got error; errno is %d (%s)\n",errno, strerror(errno)); + break; + } + /* we ignored a EINTR error, reset the stream's error state */ + clearerr(f); + TRACE("call got interrupted (EINTR), trying again\n"); + } + if (fTextMode) + { + int len = strlen(sz); + if ((len>=2) && (sz[len-1]=='\n') && (sz[len-2]=='\r')) + { + sz[len-2]='\n'; + sz[len-1]='\0'; + } + } + } while(NULL == retval); + + return retval; +} + +/*++ +PAL_fwrite + +Wrapper function for InternalFwrite. + +Input parameters: + +pvBuffer = array of objects to write to the given file stream +nSize = size of a object in bytes +nCount = number of objects to write +pf = stream to write characters to + +Return value: + Returns the number of objects written. +--*/ +size_t +__cdecl +PAL_fwrite( + const void *pvBuffer, + size_t nSize, + size_t nCount, + PAL_FILE *pf + ) +{ + size_t nWrittenBytes = 0; + + PERF_ENTRY(fwrite); + ENTRY( "fwrite( pvBuffer=%p, nSize=%d, nCount=%d, pf=%p )\n", + pvBuffer, nSize, nCount, pf); + _ASSERTE(pf != NULL); + + nWrittenBytes = InternalFwrite(pvBuffer, nSize, nCount, pf->bsdFilePtr, &pf->PALferrorCode); + + LOGEXIT( "fwrite returning size_t %d\n", nWrittenBytes ); + PERF_EXIT(fwrite); + return nWrittenBytes; +} + +/*++ +InternalFwrite + +Wrapper for fwrite. + +Input parameters: + +pvBuffer = array of objects to write to the given file stream +nSize = size of a object in bytes +nCount = number of objects to write +f = stream to write characters to +pnErrorCode = reference to a PAL_FILE's fwrite error code field + +Return value: + Returns the number of objects written. +--*/ +size_t +CorUnix::InternalFwrite( + const void *pvBuffer, + size_t nSize, + size_t nCount, + FILE *f, + INT *pnErrorCode + ) +{ + size_t nWrittenBytes = 0; + _ASSERTE(f != NULL); + +#if FILE_OPS_CHECK_FERROR_OF_PREVIOUS_CALL + clearerr(f); +#endif + + nWrittenBytes = fwrite(pvBuffer, nSize, nCount, f); + + // Make sure no error ocurred. + if ( nWrittenBytes < nCount ) + { + // Set the FILE* error code + *pnErrorCode = PAL_FILE_ERROR; + } + + return nWrittenBytes; +} + + +/*++ +PAL_fseek + +Wrapper function for fseek. + +Input parameters: + +pf = a given file stream +lOffset = distance from position to set file-position indicator +nWhence = method used to determine the file_position indicator location relative to lOffset + +Return value: + 0 on success, -1 on failure. +--*/ +int +_cdecl +PAL_fseek( + PAL_FILE * pf, + LONG lOffset, + int nWhence + ) +{ + int nRet = 0; + + PERF_ENTRY(fseek); + ENTRY( "fseek( %p, %ld, %d )\n", pf, lOffset, nWhence ); + + nRet = fseek(pf ? pf->bsdFilePtr : NULL, lOffset, nWhence); + + LOGEXIT("fseek returning %d\n", nRet); + PERF_EXIT(fseek); + return nRet; +} |