1 // Licensed to the .NET Foundation under one or more agreements.
2 // The .NET Foundation licenses this file to you under the MIT license.
3 // See the LICENSE file in the project root for more information.
15 Implementation of the file WIN API for the PAL
21 #include "pal/thread.hpp"
22 #include "pal/file.hpp"
23 #include "shmfilelockmgr.hpp"
24 #include "pal/malloc.hpp"
25 #include "pal/stackstring.hpp"
27 #include "pal/palinternal.h"
28 #include "pal/dbgmsg.h"
30 #include "pal/filetime.h"
31 #include "pal/utils.h"
36 #include <sys/types.h>
38 #include <sys/param.h>
39 #include <sys/mount.h>
43 using namespace CorUnix;
45 SET_DEFAULT_DEBUG_CHANNEL(FILE);
47 int MaxWCharToAcpLengthFactor = 3;
50 InternalSetFilePointerForUnixFd(
53 PLONG lpDistanceToMoveHigh,
55 PLONG lpNewFilePointerLow
61 IPalObject *pObjectToCleanup,
63 bool fCleanupSharedState
66 CObjectType CorUnix::otFile(
69 NULL, // No initialization routine
70 0, // No immutable data
71 sizeof(CFileProcessLocalData),
73 GENERIC_READ|GENERIC_WRITE, // Ignored -- no Win32 object security support
74 CObjectType::SecuritySupported,
75 CObjectType::OSPersistedSecurityInfo,
76 CObjectType::UnnamedObject,
77 CObjectType::LocalDuplicationOnly,
78 CObjectType::UnwaitableObject,
79 CObjectType::SignalingNotApplicable,
80 CObjectType::ThreadReleaseNotApplicable,
81 CObjectType::OwnershipNotApplicable
84 CAllowedObjectTypes CorUnix::aotFile(otiFile);
85 static CSharedMemoryFileLockMgr _FileLockManager;
86 IFileLockManager *CorUnix::g_pFileLockManager = &_FileLockManager;
91 IPalObject *pObjectToCleanup,
93 bool fCleanupSharedState
97 CFileProcessLocalData *pLocalData = NULL;
98 IDataLock *pLocalDataLock = NULL;
100 palError = pObjectToCleanup->GetProcessLocalData(
104 reinterpret_cast<void**>(&pLocalData)
107 if (NO_ERROR != palError)
109 ASSERT("Unable to obtain data to cleanup file object");
113 if (pLocalData->pLockController != NULL)
115 pLocalData->pLockController->ReleaseController();
118 if (!fShutdown && -1 != pLocalData->unix_fd)
120 close(pLocalData->unix_fd);
123 pLocalDataLock->ReleaseLock(pThread, FALSE);
133 #define PAL_LEGAL_FLAGS_ATTRIBS (FILE_ATTRIBUTE_NORMAL| \
134 FILE_FLAG_SEQUENTIAL_SCAN| \
135 FILE_FLAG_WRITE_THROUGH| \
136 FILE_FLAG_NO_BUFFERING| \
137 FILE_FLAG_RANDOM_ACCESS| \
138 FILE_FLAG_BACKUP_SEMANTICS)
140 /* Static global. The init function must be called
141 before any other functions and if it is not successful,
142 no other functions should be done. */
143 static HANDLE pStdIn = INVALID_HANDLE_VALUE;
144 static HANDLE pStdOut = INVALID_HANDLE_VALUE;
145 static HANDLE pStdErr = INVALID_HANDLE_VALUE;
149 FILEGetProperNotFoundError
151 Returns the proper error code, based on the
154 IN LPSTR lpPath - The path to check.
155 LPDWORD lpErrorCode - The error to set.
157 void FILEGetProperNotFoundError( LPCSTR lpPath, LPDWORD lpErrorCode )
159 struct stat stat_data;
160 LPSTR lpDupedPath = NULL;
161 LPSTR lpLastPathSeparator = NULL;
163 TRACE( "FILEGetProperNotFoundError( %s )\n", lpPath?lpPath:"(null)" );
167 ASSERT( "lpErrorCode has to be valid\n" );
171 if ( NULL == ( lpDupedPath = strdup(lpPath) ) )
173 ERROR( "strdup() failed!\n" );
174 *lpErrorCode = ERROR_NOT_ENOUGH_MEMORY;
178 /* Determine whether it's a file not found or path not found. */
179 lpLastPathSeparator = strrchr( lpDupedPath, '/');
180 if ( lpLastPathSeparator != NULL )
182 *lpLastPathSeparator = '\0';
184 /* If the last path component is a directory,
185 we return file not found. If it's a file or
186 doesn't exist, we return path not found. */
187 if ( '\0' == *lpDupedPath ||
188 ( stat( lpDupedPath, &stat_data ) == 0 &&
189 ( stat_data.st_mode & S_IFMT ) == S_IFDIR ) )
191 TRACE( "ERROR_FILE_NOT_FOUND\n" );
192 *lpErrorCode = ERROR_FILE_NOT_FOUND;
196 TRACE( "ERROR_PATH_NOT_FOUND\n" );
197 *lpErrorCode = ERROR_PATH_NOT_FOUND;
202 TRACE( "ERROR_FILE_NOT_FOUND\n" );
203 *lpErrorCode = ERROR_FILE_NOT_FOUND;
208 TRACE( "FILEGetProperNotFoundError returning TRUE\n" );
214 FILEGetLastErrorFromErrnoAndFilename
216 Returns the proper error code for errno, or, if errno is ENOENT,
217 based on the Windows behavior for nonexistent filenames.
219 IN LPSTR lpPath - The path to check.
221 PAL_ERROR FILEGetLastErrorFromErrnoAndFilename(LPCSTR lpPath)
226 FILEGetProperNotFoundError(lpPath, &palError);
230 palError = FILEGetLastErrorFromErrno();
236 CorUnix::RealPathHelper(LPCSTR lpUnixPath, PathCharString& lpBuffer)
238 StringHolder lpRealPath;
239 lpRealPath = realpath(lpUnixPath, NULL);
240 if (lpRealPath.IsNull())
245 lpBuffer.Set(lpRealPath, strlen(lpRealPath));
249 InternalCanonicalizeRealPath
250 Wraps realpath() to hide platform differences. See the man page for
251 realpath(3) for details of how realpath() works.
253 On systems on which realpath() allows the last path component to not
254 exist, this is a straight thunk through to realpath(). On other
255 systems, we remove the last path component, then call realpath().
259 CorUnix::InternalCanonicalizeRealPath(LPCSTR lpUnixPath, PathCharString& lpBuffer)
261 PAL_ERROR palError = NO_ERROR;
263 #if !REALPATH_SUPPORTS_NONEXISTENT_FILES
264 StringHolder lpExistingPath;
265 LPSTR pchSeparator = NULL;
266 LPSTR lpFilename = NULL;
268 DWORD cchFilename = 0;
269 #endif // !REALPATH_SUPPORTS_NONEXISTENT_FILES
271 if (lpUnixPath == NULL)
273 ERROR ("Invalid argument to InternalCanonicalizeRealPath\n");
274 palError = ERROR_INVALID_PARAMETER;
278 #if REALPATH_SUPPORTS_NONEXISTENT_FILES
279 RealPathHelper(lpUnixPath, lpBuffer);
280 #else // !REALPATH_SUPPORTS_NONEXISTENT_FILES
282 lpExistingPath = strdup(lpUnixPath);
283 if (lpExistingPath.IsNull())
285 ERROR ("strdup failed with error %d\n", errno);
286 palError = ERROR_NOT_ENOUGH_MEMORY;
290 pchSeparator = strrchr(lpExistingPath, '/');
291 if (pchSeparator == NULL)
293 PathCharString pszCwdBuffer;
295 if (GetCurrentDirectoryA(pszCwdBuffer)== 0)
297 WARN("getcwd(NULL) failed with error %d\n", errno);
298 palError = DIRGetLastErrorFromErrno();
302 if (! RealPathHelper(pszCwdBuffer, lpBuffer))
304 WARN("realpath() failed with error %d\n", errno);
305 palError = FILEGetLastErrorFromErrno();
307 // If we are here, then we tried to invoke realpath
308 // against a directory.
310 // On Mac64, realpath implementation differs from Mac32
311 // by *not* supporting invalid filenames in the path (while
312 // Mac32 implementation does).
314 // Thus, if we are here, and the error code we see is
315 // ERROR_FILE_NOT_FOUND, then we should map it to
316 // ERROR_PATH_NOT_FOUND since it was a directory that
317 // was not found (and not a file).
318 if (palError == ERROR_FILE_NOT_FOUND)
320 // Since lpBuffer can be modified by the realpath call,
321 // and can result in a truncated subset of the original buffer,
322 // we use strstr as a level of safety.
323 if (strstr(pszCwdBuffer, lpBuffer) != 0)
325 palError = ERROR_PATH_NOT_FOUND;
328 #endif // defined(_AMD64_)
332 lpFilename = lpExistingPath;
337 bool fSetFilename = true;
338 // Since realpath implementation cannot handle inexistent filenames,
339 // check if we are going to truncate the "/" corresponding to the
340 // root folder (e.g. case of "/Volumes"). If so:
342 // 1) Set the seperator to point to the NULL terminator of the specified
345 // 2) Null terminate lpBuffer
347 // 3) Since there is no explicit filename component in lpExistingPath (as
348 // we only have "/" corresponding to the root), set lpFilename to NULL,
349 // alongwith a flag indicating that it has already been set.
350 if (pchSeparator == lpExistingPath)
352 pchSeparator = lpExistingPath+strlen(lpExistingPath);
354 // Set the lpBuffer to NULL
357 fSetFilename = false;
360 #endif // defined(_AMD64_)
361 *pchSeparator = '\0';
363 if (!RealPathHelper(lpExistingPath, lpBuffer))
365 WARN("realpath() failed with error %d\n", errno);
366 palError = FILEGetLastErrorFromErrno();
369 // If we are here, then we tried to invoke realpath
370 // against a directory after stripping out the filename
371 // from the original path.
373 // On Mac64, realpath implementation differs from Mac32
374 // by *not* supporting invalid filenames in the path (while
375 // Mac32 implementation does).
377 // Thus, if we are here, and the error code we see is
378 // ERROR_FILE_NOT_FOUND, then we should map it to
379 // ERROR_PATH_NOT_FOUND since it was a directory that
380 // was not found (and not a file).
381 if (palError == ERROR_FILE_NOT_FOUND)
383 // Since lpBuffer can be modified by the realpath call,
384 // and can result in a truncated subset of the original buffer,
385 // we use strstr as a level of safety.
386 if (strstr(lpExistingPath, lpBuffer) != 0)
388 palError = ERROR_PATH_NOT_FOUND;
391 #endif // defined(_AMD64_)
397 if (fSetFilename == true)
398 #endif // defined(_AMD64_)
399 lpFilename = pchSeparator + 1;
403 if (lpFilename == NULL)
407 if (!lpBuffer.Append("/",1) || !lpBuffer.Append(lpFilename, strlen(lpFilename)))
409 ERROR ("Append failed!\n");
410 palError = ERROR_INSUFFICIENT_BUFFER;
412 // Doing a goto here since we want to exit now. This will work
413 // incase someone else adds another if clause below us.
417 #endif // REALPATH_SUPPORTS_NONEXISTENT_FILES
420 if ((palError == NO_ERROR) && lpBuffer.IsEmpty())
422 // convert all these into ERROR_PATH_NOT_FOUND
423 palError = ERROR_PATH_NOT_FOUND;
430 CorUnix::InternalCreateFile(
433 DWORD dwDesiredAccess,
435 LPSECURITY_ATTRIBUTES lpSecurityAttributes,
436 DWORD dwCreationDisposition,
437 DWORD dwFlagsAndAttributes,
438 HANDLE hTemplateFile,
442 PAL_ERROR palError = 0;
443 IPalObject *pFileObject = NULL;
444 IPalObject *pRegisteredFile = NULL;
445 IDataLock *pDataLock = NULL;
446 CFileProcessLocalData *pLocalData = NULL;
447 IFileLockController *pLockController = NULL;
448 CObjectAttributes oaFile(NULL, lpSecurityAttributes);
449 BOOL fFileExists = FALSE;
451 BOOL inheritable = FALSE;
452 PathCharString lpUnixPath;
454 int create_flags = (S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
456 int lock_mode = LOCK_SH;
458 // track whether we've created the file with the intended name,
459 // so that it can be removed on failure exit
460 BOOL bFileCreated = FALSE;
462 const char* szNonfilePrefix = "\\\\.\\";
463 PathCharString lpFullUnixPath;
465 /* for dwShareMode only three flags are accepted */
466 if ( dwShareMode & ~(FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE) )
468 ASSERT( "dwShareMode is invalid\n" );
469 palError = ERROR_INVALID_PARAMETER;
473 if ( lpFileName == NULL )
475 ERROR("InternalCreateFile called with NULL filename\n");
476 palError = ERROR_PATH_NOT_FOUND;
480 if ( strncmp(lpFileName, szNonfilePrefix, strlen(szNonfilePrefix)) == 0 )
482 ERROR("InternalCreateFile does not support paths beginning with %s\n", szNonfilePrefix);
483 palError = ERROR_INVALID_PARAMETER;
487 if( !lpUnixPath.Set(lpFileName,strlen(lpFileName)))
489 ERROR("strdup() failed\n");
490 palError = ERROR_NOT_ENOUGH_MEMORY;
494 FILEDosToUnixPathA( lpUnixPath );
496 // Compute the absolute pathname to the file. This pathname is used
497 // to determine if two file names represent the same file.
498 palError = InternalCanonicalizeRealPath(lpUnixPath, lpFullUnixPath);
499 if (palError != NO_ERROR)
504 lpUnixPath.Set(lpFullUnixPath);
506 switch( dwDesiredAccess )
509 /* Device Query Access was requested. let's use open() with
510 no flags, it's basically the equivalent of O_RDONLY, since
511 O_RDONLY is defined as 0x0000 */
513 case( GENERIC_READ ):
514 open_flags |= O_RDONLY;
516 case( GENERIC_WRITE ):
517 open_flags |= O_WRONLY;
519 case( GENERIC_READ | GENERIC_WRITE ):
520 open_flags |= O_RDWR;
523 ERROR("dwDesiredAccess value of %d is invalid\n", dwDesiredAccess);
524 palError = ERROR_INVALID_PARAMETER;
528 TRACE("open flags are 0x%lx\n", open_flags);
530 if ( lpSecurityAttributes )
532 if ( lpSecurityAttributes->nLength != sizeof( SECURITY_ATTRIBUTES ) ||
533 lpSecurityAttributes->lpSecurityDescriptor != NULL ||
534 !lpSecurityAttributes->bInheritHandle )
536 ASSERT("lpSecurityAttributes points to invalid values.\n");
537 palError = ERROR_INVALID_PARAMETER;
543 if ( (dwFlagsAndAttributes & PAL_LEGAL_FLAGS_ATTRIBS) !=
544 dwFlagsAndAttributes)
546 ASSERT("Bad dwFlagsAndAttributes\n");
547 palError = ERROR_INVALID_PARAMETER;
550 else if (dwFlagsAndAttributes & FILE_FLAG_BACKUP_SEMANTICS)
552 /* Override the open flags, and always open as readonly. This
553 flag is used when opening a directory, to change its
554 creation/modification/access times. On Windows, the directory
555 must be open for write, but on Unix, it needs to be readonly. */
556 open_flags = O_RDONLY;
560 if (stat(lpUnixPath, &st) == 0 && (st.st_mode & S_IFDIR))
562 /* The file exists and it is a directory. Without
563 FILE_FLAG_BACKUP_SEMANTICS, Win32 CreateFile always fails
564 to open directories. */
565 palError = ERROR_ACCESS_DENIED;
572 ASSERT("hTemplateFile is not NULL, as it should be.\n");
573 palError = ERROR_INVALID_PARAMETER;
578 // The file sharing mode checks are performed by the lock manager so we need
579 // to get the lock controller for this file.
580 // Do this before modifying the file system since we wouldn't want to, for
581 // instance, truncate a file before finding out if we have write access to it.
582 // It may seem odd that in some cases we will acquire a lock on a file that
583 // doesn't exist yet but the lock manager does not care -- files are
584 // abstract entities represented by a name from its point of view.
587 palError = g_pFileLockManager->GetLockControllerForFile(
595 if (NO_ERROR != palError)
600 /* NB: According to MSDN docs, When CREATE_ALWAYS or OPEN_ALWAYS is
601 set, CreateFile should SetLastError to ERROR_ALREADY_EXISTS,
602 even though/if CreateFile will be successful.
604 switch( dwCreationDisposition )
606 case( CREATE_ALWAYS ):
607 // check whether the file exists
608 if ( access( lpUnixPath, F_OK ) == 0 )
612 open_flags |= O_CREAT | O_TRUNC;
615 open_flags |= O_CREAT | O_EXCL;
617 case( OPEN_EXISTING ):
618 /* don't need to do anything here */
621 if ( access( lpUnixPath, F_OK ) == 0 )
625 open_flags |= O_CREAT;
627 case( TRUNCATE_EXISTING ):
628 open_flags |= O_TRUNC;
631 ASSERT("dwCreationDisposition value of %d is not valid\n",
632 dwCreationDisposition);
633 palError = ERROR_INVALID_PARAMETER;
637 if ( dwFlagsAndAttributes & FILE_FLAG_NO_BUFFERING )
639 TRACE("I/O will be unbuffered\n");
641 open_flags |= O_DIRECT;
646 TRACE("I/O will be buffered\n");
649 filed = InternalOpen(lpUnixPath, open_flags, create_flags);
650 TRACE("Allocated file descriptor [%d]\n", filed);
654 TRACE("open() failed; error is %s (%d)\n", strerror(errno), errno);
655 palError = FILEGetLastErrorFromErrnoAndFilename(lpUnixPath);
659 // Deduce whether we created a file in the previous operation (there's a
660 // small timing window between the access() used to determine fFileExists
661 // and the open() operation, but there's not much we can do about that.
662 bFileCreated = (dwCreationDisposition == CREATE_ALWAYS ||
663 dwCreationDisposition == CREATE_NEW ||
664 dwCreationDisposition == OPEN_ALWAYS) &&
668 // While the lock manager is able to provide support for share modes within an instance of
669 // the PAL, other PALs will ignore these locks. In order to support a basic level of cross
670 // process locking, we'll use advisory locks. FILE_SHARE_NONE implies a exclusive lock on the
671 // file and all other modes use a shared lock. While this is not as granular as Windows,
672 // you can atleast implement a lock file using this.
673 lock_mode = (dwShareMode == 0 /* FILE_SHARE_NONE */) ? LOCK_EX : LOCK_SH;
675 if(flock(filed, lock_mode | LOCK_NB) != 0)
677 TRACE("flock() failed; error is %s (%d)\n", strerror(errno), errno);
678 if (errno == EWOULDBLOCK)
680 palError = ERROR_SHARING_VIOLATION;
684 palError = FILEGetLastErrorFromErrno();
691 if ( dwFlagsAndAttributes & FILE_FLAG_NO_BUFFERING )
694 if (-1 == fcntl(filed, F_NOCACHE, 1))
696 ASSERT("Can't set F_NOCACHE; fcntl() failed. errno is %d (%s)\n",
697 errno, strerror(errno));
698 palError = ERROR_INTERNAL_ERROR;
702 #error Insufficient support for uncached I/O on this platform
707 /* make file descriptor close-on-exec; inheritable handles will get
708 "uncloseonexeced" in CreateProcess if they are actually being inherited*/
709 if(-1 == fcntl(filed,F_SETFD,1))
711 ASSERT("can't set close-on-exec flag; fcntl() failed. errno is %d "
712 "(%s)\n", errno, strerror(errno));
713 palError = ERROR_INTERNAL_ERROR;
717 palError = g_pObjectManager->AllocateObject(
724 if (NO_ERROR != palError)
729 palError = pFileObject->GetProcessLocalData(
733 reinterpret_cast<void**>(&pLocalData)
736 if (NO_ERROR != palError)
741 if (strcpy_s(pLocalData->unix_filename, sizeof(pLocalData->unix_filename), lpUnixPath) != SAFECRT_SUCCESS)
743 palError = ERROR_INSUFFICIENT_BUFFER;
744 TRACE("strcpy_s failed!\n");
748 pLocalData->inheritable = inheritable;
749 pLocalData->unix_fd = filed;
750 pLocalData->dwDesiredAccess = dwDesiredAccess;
751 pLocalData->open_flags = open_flags;
752 pLocalData->open_flags_deviceaccessonly = (dwDesiredAccess == 0);
755 // Transfer the lock controller reference from our local variable
756 // to the local file data
759 pLocalData->pLockController = pLockController;
760 pLockController = NULL;
763 // We've finished initializing our local data, so release that lock
766 pDataLock->ReleaseLock(pThread, TRUE);
769 palError = g_pObjectManager->RegisterObject(
779 // pFileObject is invalidated by the call to RegisterObject, so NULL it
780 // out here to ensure that we don't try to release a reference on
788 // At this point, if we've been successful, palError will be NO_ERROR.
789 // CreateFile can return ERROR_ALREADY_EXISTS in some success cases;
790 // those cases are flagged by fFileExists and are handled below.
791 if (NO_ERROR != palError)
799 if (-1 == unlink(lpUnixPath))
801 WARN("can't delete file; unlink() failed with errno %d (%s)\n",
802 errno, strerror(errno));
807 if (NULL != pLockController)
809 pLockController->ReleaseController();
812 if (NULL != pDataLock)
814 pDataLock->ReleaseLock(pThread, TRUE);
817 if (NULL != pFileObject)
819 pFileObject->ReleaseReference(pThread);
822 if (NULL != pRegisteredFile)
824 pRegisteredFile->ReleaseReference(pThread);
827 if (NO_ERROR == palError && fFileExists)
829 palError = ERROR_ALREADY_EXISTS;
840 Only bInherit flag is used from the LPSECURITY_ATTRIBUTES struct.
841 Desired access is READ, WRITE or 0
842 Share mode is READ, WRITE or DELETE
849 IN LPCSTR lpFileName,
850 IN DWORD dwDesiredAccess,
851 IN DWORD dwShareMode,
852 IN LPSECURITY_ATTRIBUTES lpSecurityAttributes,
853 IN DWORD dwCreationDisposition,
854 IN DWORD dwFlagsAndAttributes,
855 IN HANDLE hTemplateFile
859 PAL_ERROR palError = NO_ERROR;
860 HANDLE hRet = INVALID_HANDLE_VALUE;
862 PERF_ENTRY(CreateFileA);
863 ENTRY("CreateFileA(lpFileName=%p (%s), dwAccess=%#x, dwShareMode=%#x, "
864 "lpSecurityAttr=%p, dwDisposition=%#x, dwFlags=%#x, "
865 "hTemplateFile=%p )\n",lpFileName?lpFileName:"NULL",lpFileName?lpFileName:"NULL", dwDesiredAccess,
866 dwShareMode, lpSecurityAttributes, dwCreationDisposition,
867 dwFlagsAndAttributes, hTemplateFile);
869 pThread = InternalGetCurrentThread();
871 palError = InternalCreateFile(
876 lpSecurityAttributes,
877 dwCreationDisposition,
878 dwFlagsAndAttributes,
884 // We always need to set last error, even on success:
885 // we need to protect ourselves from the situation
886 // where last error is set to ERROR_ALREADY_EXISTS on
887 // entry to the function
890 pThread->SetLastError(palError);
892 LOGEXIT("CreateFileA returns HANDLE %p\n", hRet);
893 PERF_EXIT(CreateFileA);
903 Only bInherit flag is used from the LPSECURITY_ATTRIBUTES struct.
904 Desired access is READ, WRITE or 0
905 Share mode is READ, WRITE or DELETE
912 IN LPCWSTR lpFileName,
913 IN DWORD dwDesiredAccess,
914 IN DWORD dwShareMode,
915 IN LPSECURITY_ATTRIBUTES lpSecurityAttributes,
916 IN DWORD dwCreationDisposition,
917 IN DWORD dwFlagsAndAttributes,
918 IN HANDLE hTemplateFile)
921 PAL_ERROR palError = NO_ERROR;
922 PathCharString namePathString;
926 HANDLE hRet = INVALID_HANDLE_VALUE;
928 PERF_ENTRY(CreateFileW);
929 ENTRY("CreateFileW(lpFileName=%p (%S), dwAccess=%#x, dwShareMode=%#x, "
930 "lpSecurityAttr=%p, dwDisposition=%#x, dwFlags=%#x, hTemplateFile=%p )\n",
931 lpFileName?lpFileName:W16_NULLSTRING,
932 lpFileName?lpFileName:W16_NULLSTRING, dwDesiredAccess, dwShareMode,
933 lpSecurityAttributes, dwCreationDisposition, dwFlagsAndAttributes,
936 pThread = InternalGetCurrentThread();
938 if (lpFileName != NULL)
940 length = (PAL_wcslen(lpFileName)+1) * MaxWCharToAcpLengthFactor;
943 name = namePathString.OpenStringBuffer(length);
946 palError = ERROR_NOT_ENOUGH_MEMORY;
950 size = WideCharToMultiByte( CP_ACP, 0, lpFileName, -1, name, length,
955 namePathString.CloseBuffer(0);
956 DWORD dwLastError = GetLastError();
957 ASSERT("WideCharToMultiByte failure! error is %d\n", dwLastError);
958 palError = ERROR_INTERNAL_ERROR;
962 namePathString.CloseBuffer(size - 1);
964 palError = InternalCreateFile(
969 lpSecurityAttributes,
970 dwCreationDisposition,
971 dwFlagsAndAttributes,
977 // We always need to set last error, even on success:
978 // we need to protect ourselves from the situation
979 // where last error is set to ERROR_ALREADY_EXISTS on
980 // entry to the function
984 pThread->SetLastError(palError);
985 LOGEXIT( "CreateFileW returns HANDLE %p\n", hRet );
986 PERF_EXIT(CreateFileW);
998 There are several (most) error paths here that do not call SetLastError().
999 This is because we know that CreateFile, ReadFile, and WriteFile will do so,
1000 and will have a much better idea of the specific error.
1005 IN LPCWSTR lpExistingFileName,
1006 IN LPCWSTR lpNewFileName,
1007 IN BOOL bFailIfExists)
1009 CPalThread *pThread;
1010 PathCharString sourcePathString;
1011 PathCharString destPathString;
1014 int src_size, dest_size, length = 0;
1017 PERF_ENTRY(CopyFileW);
1018 ENTRY("CopyFileW(lpExistingFileName=%p (%S), lpNewFileName=%p (%S), bFailIfExists=%d)\n",
1019 lpExistingFileName?lpExistingFileName:W16_NULLSTRING,
1020 lpExistingFileName?lpExistingFileName:W16_NULLSTRING,
1021 lpNewFileName?lpNewFileName:W16_NULLSTRING,
1022 lpNewFileName?lpNewFileName:W16_NULLSTRING, bFailIfExists);
1024 pThread = InternalGetCurrentThread();
1025 if (lpExistingFileName != NULL)
1027 length = (PAL_wcslen(lpExistingFileName)+1) * MaxWCharToAcpLengthFactor;
1030 source = sourcePathString.OpenStringBuffer(length);
1033 pThread->SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1037 src_size = WideCharToMultiByte( CP_ACP, 0, lpExistingFileName, -1, source, length,
1042 sourcePathString.CloseBuffer(0);
1043 DWORD dwLastError = GetLastError();
1044 ASSERT("WideCharToMultiByte failure! error is %d\n", dwLastError);
1045 pThread->SetLastError(ERROR_INTERNAL_ERROR);
1049 sourcePathString.CloseBuffer(src_size - 1);
1052 if (lpNewFileName != NULL)
1054 length = (PAL_wcslen(lpNewFileName)+1) * MaxWCharToAcpLengthFactor;
1057 dest = destPathString.OpenStringBuffer(length);
1060 pThread->SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1063 dest_size = WideCharToMultiByte( CP_ACP, 0, lpNewFileName, -1, dest, length,
1066 if( dest_size == 0 )
1068 destPathString.CloseBuffer(0);
1069 DWORD dwLastError = GetLastError();
1070 ASSERT("WideCharToMultiByte failure! error is %d\n", dwLastError);
1071 pThread->SetLastError(ERROR_INTERNAL_ERROR);
1075 destPathString.CloseBuffer(dest_size - 1);
1076 bRet = CopyFileA(source,dest,bFailIfExists);
1079 LOGEXIT("CopyFileW returns BOOL %d\n", bRet);
1080 PERF_EXIT(CopyFileW);
1094 IN LPCSTR lpFileName)
1096 PAL_ERROR palError = NO_ERROR;
1097 CPalThread *pThread;
1100 DWORD dwLastError = 0;
1101 PathCharString lpunixFileName;
1102 PathCharString lpFullunixFileName;
1104 PERF_ENTRY(DeleteFileA);
1105 ENTRY("DeleteFileA(lpFileName=%p (%s))\n", lpFileName?lpFileName:"NULL", lpFileName?lpFileName:"NULL");
1107 pThread = InternalGetCurrentThread();
1109 if( !lpunixFileName.Set(lpFileName, strlen(lpFileName)))
1111 palError = ERROR_NOT_ENOUGH_MEMORY;
1115 FILEDosToUnixPathA( lpunixFileName );
1117 // Compute the absolute pathname to the file. This pathname is used
1118 // to determine if two file names represent the same file.
1119 palError = InternalCanonicalizeRealPath(lpunixFileName, lpFullunixFileName);
1120 if (palError != NO_ERROR)
1122 if (!lpFullunixFileName.Set(lpunixFileName, strlen(lpunixFileName)))
1124 palError = ERROR_NOT_ENOUGH_MEMORY;
1129 result = unlink( lpFullunixFileName );
1133 TRACE("unlink returns %d\n", result);
1134 dwLastError = FILEGetLastErrorFromErrnoAndFilename(lpFullunixFileName);
1144 pThread->SetLastError( dwLastError );
1147 LOGEXIT("DeleteFileA returns BOOL %d\n", bRet);
1148 PERF_EXIT(DeleteFileA);
1161 IN LPCWSTR lpFileName)
1163 CPalThread *pThread;
1165 PathCharString namePS;
1170 PERF_ENTRY(DeleteFileW);
1171 ENTRY("DeleteFileW(lpFileName=%p (%S))\n",
1172 lpFileName?lpFileName:W16_NULLSTRING,
1173 lpFileName?lpFileName:W16_NULLSTRING);
1175 pThread = InternalGetCurrentThread();
1177 if (lpFileName != NULL)
1179 length = (PAL_wcslen(lpFileName)+1) * MaxWCharToAcpLengthFactor;
1182 name = namePS.OpenStringBuffer(length);
1185 pThread->SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1189 size = WideCharToMultiByte( CP_ACP, 0, lpFileName, -1, name, length,
1194 namePS.CloseBuffer(0);
1195 DWORD dwLastError = GetLastError();
1196 ASSERT("WideCharToMultiByte failure! error is %d\n", dwLastError);
1197 pThread->SetLastError(ERROR_INTERNAL_ERROR);
1202 namePS.CloseBuffer(size - 1);
1203 bRet = DeleteFileA( name );
1206 LOGEXIT("DeleteFileW returns BOOL %d\n", bRet);
1207 PERF_EXIT(DeleteFileW);
1221 IN LPCSTR lpExistingFileName,
1222 IN LPCSTR lpNewFileName)
1226 PERF_ENTRY(MoveFileA);
1227 ENTRY("MoveFileA(lpExistingFileName=%p (%s), lpNewFileName=%p (%s))\n",
1228 lpExistingFileName?lpExistingFileName:"NULL",
1229 lpExistingFileName?lpExistingFileName:"NULL",
1230 lpNewFileName?lpNewFileName:"NULL",
1231 lpNewFileName?lpNewFileName:"NULL");
1233 bRet = MoveFileExA( lpExistingFileName,
1235 MOVEFILE_COPY_ALLOWED );
1237 LOGEXIT("MoveFileA returns BOOL %d\n", bRet);
1238 PERF_EXIT(MoveFileA);
1252 IN LPCWSTR lpExistingFileName,
1253 IN LPCWSTR lpNewFileName)
1257 PERF_ENTRY(MoveFileW);
1258 ENTRY("MoveFileW(lpExistingFileName=%p (%S), lpNewFileName=%p (%S))\n",
1259 lpExistingFileName?lpExistingFileName:W16_NULLSTRING,
1260 lpExistingFileName?lpExistingFileName:W16_NULLSTRING,
1261 lpNewFileName?lpNewFileName:W16_NULLSTRING,
1262 lpNewFileName?lpNewFileName:W16_NULLSTRING);
1264 bRet = MoveFileExW( lpExistingFileName,
1266 MOVEFILE_COPY_ALLOWED );
1268 LOGEXIT("MoveFileW returns BOOL %d\n", bRet);
1269 PERF_EXIT(MoveFileW);
1282 IN LPCSTR lpExistingFileName,
1283 IN LPCSTR lpNewFileName,
1286 CPalThread *pThread;
1288 PathCharString source;
1289 PathCharString dest;
1291 DWORD dwLastError = 0;
1293 PERF_ENTRY(MoveFileExA);
1294 ENTRY("MoveFileExA(lpExistingFileName=%p (%S), lpNewFileName=%p (%S), "
1296 lpExistingFileName?lpExistingFileName:"NULL",
1297 lpExistingFileName?lpExistingFileName:"NULL",
1298 lpNewFileName?lpNewFileName:"NULL",
1299 lpNewFileName?lpNewFileName:"NULL", dwFlags);
1301 pThread = InternalGetCurrentThread();
1302 /* only two flags are accepted */
1303 if ( dwFlags & ~(MOVEFILE_COPY_ALLOWED | MOVEFILE_REPLACE_EXISTING) )
1305 ASSERT( "dwFlags is invalid\n" );
1306 dwLastError = ERROR_INVALID_PARAMETER;
1311 if( !source.Set(lpExistingFileName, strlen(lpExistingFileName)))
1313 dwLastError = ERROR_NOT_ENOUGH_MEMORY;
1317 FILEDosToUnixPathA( source );
1319 if( !dest.Set(lpNewFileName, strlen(lpNewFileName)))
1321 dwLastError = ERROR_NOT_ENOUGH_MEMORY;
1325 FILEDosToUnixPathA( dest );
1327 if ( !(dwFlags & MOVEFILE_REPLACE_EXISTING) )
1329 #if HAVE_CASE_SENSITIVE_FILESYSTEM
1330 if ( strcmp(source, dest) != 0 )
1331 #else // HAVE_CASE_SENSITIVE_FILESYSTEM
1332 if ( strcasecmp(source, dest) != 0 )
1333 #endif // HAVE_CASE_SENSITIVE_FILESYSTEM
1335 // Let things proceed normally if source and
1336 // dest are the same.
1337 if ( access(dest, F_OK) == 0 )
1339 dwLastError = ERROR_ALREADY_EXISTS;
1345 result = rename( source, dest );
1346 if ((result < 0) && (dwFlags & MOVEFILE_REPLACE_EXISTING) &&
1347 ((errno == ENOTDIR) || (errno == EEXIST)))
1349 bRet = DeleteFileA( lpNewFileName );
1353 result = rename( source, dest );
1357 dwLastError = GetLastError();
1365 case EXDEV: /* we tried to link across devices */
1367 if ( dwFlags & MOVEFILE_COPY_ALLOWED )
1369 BOOL bFailIfExists = !(dwFlags & MOVEFILE_REPLACE_EXISTING);
1371 /* if CopyFile fails here, so should MoveFailEx */
1372 bRet = CopyFileA( lpExistingFileName,
1375 /* CopyFile should set the appropriate error */
1378 dwLastError = GetLastError();
1382 if (!DeleteFileA(lpExistingFileName))
1384 ERROR("Failed to delete the source file\n");
1385 dwLastError = GetLastError();
1387 /* Delete the destination file if we're unable to delete
1389 if (!DeleteFileA(lpNewFileName))
1391 ERROR("Failed to delete the destination file\n");
1398 dwLastError = ERROR_ACCESS_DENIED;
1401 case EINVAL: // tried to rename "." or ".."
1402 dwLastError = ERROR_SHARING_VIOLATION;
1407 if (lstat(source, &buf) == -1)
1409 FILEGetProperNotFoundError(source, &dwLastError);
1413 dwLastError = ERROR_PATH_NOT_FOUND;
1418 dwLastError = FILEGetLastErrorFromErrno();
1426 pThread->SetLastError( dwLastError );
1430 LOGEXIT( "MoveFileExA returns BOOL %d\n", bRet );
1431 PERF_EXIT(MoveFileExA);
1444 IN LPCWSTR lpExistingFileName,
1445 IN LPCWSTR lpNewFileName,
1448 CPalThread *pThread;
1449 PathCharString sourcePS;
1450 PathCharString destPS;
1454 int src_size,dest_size;
1457 PERF_ENTRY(MoveFileExW);
1458 ENTRY("MoveFileExW(lpExistingFileName=%p (%S), lpNewFileName=%p (%S), dwFlags=%#x)\n",
1459 lpExistingFileName?lpExistingFileName:W16_NULLSTRING,
1460 lpExistingFileName?lpExistingFileName:W16_NULLSTRING,
1461 lpNewFileName?lpNewFileName:W16_NULLSTRING,
1462 lpNewFileName?lpNewFileName:W16_NULLSTRING, dwFlags);
1464 pThread = InternalGetCurrentThread();
1466 if (lpExistingFileName != NULL)
1468 length = (PAL_wcslen(lpExistingFileName)+1) * MaxWCharToAcpLengthFactor;
1471 source = sourcePS.OpenStringBuffer(length);
1474 pThread->SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1477 src_size = WideCharToMultiByte( CP_ACP, 0, lpExistingFileName, -1, source, length,
1481 sourcePS.CloseBuffer(0);
1482 DWORD dwLastError = GetLastError();
1483 ASSERT("WideCharToMultiByte failure! error is %d\n", dwLastError);
1484 pThread->SetLastError(ERROR_INTERNAL_ERROR);
1488 sourcePS.CloseBuffer(src_size - 1);
1490 if (lpNewFileName != NULL)
1492 length = (PAL_wcslen(lpNewFileName)+1) * MaxWCharToAcpLengthFactor;
1495 dest = destPS.OpenStringBuffer(length);
1498 pThread->SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1501 dest_size = WideCharToMultiByte( CP_ACP, 0, lpNewFileName, -1, dest, length,
1504 if( dest_size == 0 )
1506 destPS.CloseBuffer(0);
1507 DWORD dwLastError = GetLastError();
1508 ASSERT("WideCharToMultiByte failure! error is %d\n", dwLastError);
1509 pThread->SetLastError(ERROR_INTERNAL_ERROR);
1513 destPS.CloseBuffer(dest_size - 1);
1514 bRet = MoveFileExA(source,dest,dwFlags);
1517 LOGEXIT("MoveFileExW returns BOOL %d\n", bRet);
1518 PERF_EXIT(MoveFileExW);
1527 Checking for directory and read-only file, according to Rotor spec.
1530 There are some important things to note about this implementation, which
1531 are due to the differences between the FAT filesystem and Unix filesystems:
1533 - fifo's, sockets, and symlinks will return -1, and GetLastError() will
1534 return ERROR_ACCESS_DENIED
1536 - if a file is write-only, or has no permissions at all, it is treated
1537 the same as if it had mode 'rw'. This is consistent with behaviour on
1538 NTFS files with the same permissions.
1540 - the following flags will never be returned:
1542 FILE_ATTRIBUTE_SYSTEM
1543 FILE_ATTRIBUTE_ARCHIVE
1544 FILE_ATTRIBUTE_HIDDEN
1550 IN LPCSTR lpFileName)
1552 CPalThread *pThread;
1553 struct stat stat_data;
1555 DWORD dwLastError = 0;
1556 PathCharString unixFileName;
1558 PERF_ENTRY(GetFileAttributesA);
1559 ENTRY("GetFileAttributesA(lpFileName=%p (%s))\n", lpFileName?lpFileName:"NULL", lpFileName?lpFileName:"NULL");
1561 pThread = InternalGetCurrentThread();
1562 if (lpFileName == NULL)
1564 dwLastError = ERROR_PATH_NOT_FOUND;
1569 if( !unixFileName.Set(lpFileName, strlen(lpFileName)))
1571 dwLastError = ERROR_NOT_ENOUGH_MEMORY;
1575 FILEDosToUnixPathA( unixFileName );
1577 if ( stat(unixFileName, &stat_data) != 0 )
1579 dwLastError = FILEGetLastErrorFromErrnoAndFilename(unixFileName);
1583 if ( (stat_data.st_mode & S_IFMT) == S_IFDIR )
1585 dwAttr |= FILE_ATTRIBUTE_DIRECTORY;
1587 else if ( (stat_data.st_mode & S_IFMT) != S_IFREG )
1589 ERROR("Not a regular file or directory, S_IFMT is %#x\n",
1590 stat_data.st_mode & S_IFMT);
1591 dwLastError = ERROR_ACCESS_DENIED;
1595 if ( UTIL_IsReadOnlyBitsSet( &stat_data ) )
1597 dwAttr |= FILE_ATTRIBUTE_READONLY;
1600 /* finally, if nothing is set... */
1603 dwAttr = FILE_ATTRIBUTE_NORMAL;
1609 pThread->SetLastError(dwLastError);
1610 dwAttr = INVALID_FILE_ATTRIBUTES;
1613 LOGEXIT("GetFileAttributesA returns DWORD %#x\n", dwAttr);
1614 PERF_EXIT(GetFileAttributesA);
1626 Checking for directory and read-only file
1633 IN LPCWSTR lpFileName)
1635 CPalThread *pThread;
1637 PathCharString filenamePS;
1640 DWORD dwRet = (DWORD) -1;
1642 PERF_ENTRY(GetFileAttributesW);
1643 ENTRY("GetFileAttributesW(lpFileName=%p (%S))\n",
1644 lpFileName?lpFileName:W16_NULLSTRING,
1645 lpFileName?lpFileName:W16_NULLSTRING);
1647 pThread = InternalGetCurrentThread();
1648 if (lpFileName == NULL)
1650 pThread->SetLastError(ERROR_PATH_NOT_FOUND);
1654 length = (PAL_wcslen(lpFileName)+1) * MaxWCharToAcpLengthFactor;
1655 filename = filenamePS.OpenStringBuffer(length);
1656 if (NULL == filename)
1658 pThread->SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1661 size = WideCharToMultiByte( CP_ACP, 0, lpFileName, -1, filename, length,
1666 filenamePS.CloseBuffer(0);
1667 DWORD dwLastError = GetLastError();
1668 ASSERT("WideCharToMultiByte failure! error is %d\n", dwLastError);
1669 pThread->SetLastError(ERROR_INTERNAL_ERROR);
1673 filenamePS.CloseBuffer(size - 1);
1674 dwRet = GetFileAttributesA( filename );
1678 LOGEXIT("GetFileAttributesW returns DWORD %#x\n", dwRet);
1679 PERF_EXIT(GetFileAttributesW);
1686 GetFileAttributesExW
1688 See MSDN doc, and notes for GetFileAttributesW.
1692 GetFileAttributesExW(
1693 IN LPCWSTR lpFileName,
1694 IN GET_FILEEX_INFO_LEVELS fInfoLevelId,
1695 OUT LPVOID lpFileInformation)
1697 CPalThread *pThread;
1699 DWORD dwLastError = 0;
1700 LPWIN32_FILE_ATTRIBUTE_DATA attr_data;
1702 struct stat stat_data;
1705 PathCharString namePS;
1709 PERF_ENTRY(GetFileAttributesExW);
1710 ENTRY("GetFileAttributesExW(lpFileName=%p (%S), fInfoLevelId=%d, "
1711 "lpFileInformation=%p)\n", lpFileName?lpFileName:W16_NULLSTRING, lpFileName?lpFileName:W16_NULLSTRING,
1712 fInfoLevelId, lpFileInformation);
1714 pThread = InternalGetCurrentThread();
1715 if ( fInfoLevelId != GetFileExInfoStandard )
1717 ASSERT("Unrecognized value for fInfoLevelId=%d\n", fInfoLevelId);
1718 dwLastError = ERROR_INVALID_PARAMETER;
1722 if ( !lpFileInformation )
1724 ASSERT("lpFileInformation is NULL\n");
1725 dwLastError = ERROR_INVALID_PARAMETER;
1729 if (lpFileName == NULL)
1731 dwLastError = ERROR_PATH_NOT_FOUND;
1735 length = (PAL_wcslen(lpFileName)+1) * MaxWCharToAcpLengthFactor;
1736 name = namePS.OpenStringBuffer(length);
1739 dwLastError = ERROR_NOT_ENOUGH_MEMORY;
1742 size = WideCharToMultiByte( CP_ACP, 0, lpFileName, -1, name, length,
1747 namePS.CloseBuffer(0);
1748 dwLastError = GetLastError();
1749 ASSERT("WideCharToMultiByte failure! error is %d\n", dwLastError);
1750 dwLastError = ERROR_INTERNAL_ERROR;
1754 namePS.CloseBuffer(size - 1);
1755 attr_data = (LPWIN32_FILE_ATTRIBUTE_DATA)lpFileInformation;
1757 attr_data->dwFileAttributes = GetFileAttributesW(lpFileName);
1758 /* assume that GetFileAttributes will call SetLastError appropriately */
1759 if ( attr_data->dwFileAttributes == (DWORD)-1 )
1764 FILEDosToUnixPathA(name);
1766 if ( stat(name, &stat_data) != 0 )
1768 ERROR("stat failed on %S\n", lpFileName);
1769 dwLastError = FILEGetLastErrorFromErrnoAndFilename(name);
1773 /* get the file times */
1774 attr_data->ftCreationTime =
1775 FILEUnixTimeToFileTime( stat_data.st_ctime,
1776 ST_CTIME_NSEC(&stat_data) );
1777 attr_data->ftLastAccessTime =
1778 FILEUnixTimeToFileTime( stat_data.st_atime,
1779 ST_ATIME_NSEC(&stat_data) );
1780 attr_data->ftLastWriteTime =
1781 FILEUnixTimeToFileTime( stat_data.st_mtime,
1782 ST_MTIME_NSEC(&stat_data) );
1784 /* Get the file size. GetFileSize is not used because it gets the
1785 size of an already-open file */
1786 attr_data->nFileSizeLow = (DWORD) stat_data.st_size;
1787 #if SIZEOF_OFF_T > 4
1788 attr_data->nFileSizeHigh = (DWORD)(stat_data.st_size >> 32);
1790 attr_data->nFileSizeHigh = 0;
1796 if (dwLastError) pThread->SetLastError(dwLastError);
1798 LOGEXIT("GetFileAttributesExW returns BOOL %d\n", bRet);
1799 PERF_EXIT(GetFileAttributesExW);
1808 Used for setting read-only attribute on file only.
1814 IN LPCWSTR lpFileName,
1815 IN DWORD dwFileAttributes)
1817 CPalThread *pThread;
1819 PathCharString namePS;
1823 DWORD dwLastError = 0;
1826 PERF_ENTRY(SetFileAttributesW);
1827 ENTRY("SetFileAttributesW(lpFileName=%p (%S), dwFileAttributes=%#x)\n",
1828 lpFileName?lpFileName:W16_NULLSTRING,
1829 lpFileName?lpFileName:W16_NULLSTRING, dwFileAttributes);
1831 pThread = InternalGetCurrentThread();
1832 if (lpFileName == NULL)
1834 dwLastError = ERROR_PATH_NOT_FOUND;
1838 length = (PAL_wcslen(lpFileName)+1) * MaxWCharToAcpLengthFactor;
1839 name = namePS.OpenStringBuffer(length);
1842 dwLastError = ERROR_NOT_ENOUGH_MEMORY;
1845 size = WideCharToMultiByte( CP_ACP, 0, lpFileName, -1, name, length,
1850 namePS.CloseBuffer(0);
1851 dwLastError = GetLastError();
1852 ASSERT("WideCharToMultiByte failure! error is %d\n", dwLastError);
1853 dwLastError = ERROR_INVALID_PARAMETER;
1856 namePS.CloseBuffer(size - 1);
1857 bRet = SetFileAttributesA(name,dwFileAttributes);
1860 if (dwLastError) pThread->SetLastError(dwLastError);
1862 LOGEXIT("SetFileAttributes returns BOOL %d\n", bRet);
1863 PERF_EXIT(SetFileAttributesW);
1868 CorUnix::InternalWriteFile(
1869 CPalThread *pThread,
1872 DWORD nNumberOfBytesToWrite,
1873 LPDWORD lpNumberOfBytesWritten,
1874 LPOVERLAPPED lpOverlapped
1877 PAL_ERROR palError = 0;
1878 IPalObject *pFileObject = NULL;
1879 CFileProcessLocalData *pLocalData = NULL;
1880 IDataLock *pLocalDataLock = NULL;
1881 IFileTransactionLock *pTransactionLock = NULL;
1884 LONG writeOffsetStartLow = 0, writeOffsetStartHigh = 0;
1887 if (NULL != lpNumberOfBytesWritten)
1890 // This must be set to 0 before any other error checking takes
1894 *lpNumberOfBytesWritten = 0;
1898 ASSERT( "lpNumberOfBytesWritten is NULL\n" );
1899 palError = ERROR_INVALID_PARAMETER;
1903 // Win32 WriteFile disallows writing to STD_INPUT_HANDLE
1904 if (hFile == INVALID_HANDLE_VALUE || hFile == pStdIn)
1906 palError = ERROR_INVALID_HANDLE;
1909 else if ( lpOverlapped )
1911 ASSERT( "lpOverlapped is not NULL, as it should be.\n" );
1912 palError = ERROR_INVALID_PARAMETER;
1916 palError = g_pObjectManager->ReferenceObjectByHandle(
1924 if (NO_ERROR != palError)
1929 palError = pFileObject->GetProcessLocalData(
1933 reinterpret_cast<void**>(&pLocalData)
1936 if (NO_ERROR != palError)
1941 if (pLocalData->open_flags_deviceaccessonly == TRUE)
1943 ERROR("File open for device access only\n");
1944 palError = ERROR_ACCESS_DENIED;
1948 ifd = pLocalData->unix_fd;
1951 // Inform the lock controller for this file (if any) of our intention
1952 // to perform a write. (Note that pipes don't have lock controllers.)
1955 if (NULL != pLocalData->pLockController)
1957 /* Get the current file position to calculate the region to lock */
1958 palError = InternalSetFilePointerForUnixFd(
1961 &writeOffsetStartHigh,
1963 &writeOffsetStartLow
1966 if (NO_ERROR != palError)
1968 ASSERT("Failed to get the current file position\n");
1969 palError = ERROR_INTERNAL_ERROR;
1973 palError = pLocalData->pLockController->GetTransactionLock(
1975 IFileLockController::WriteLock,
1976 writeOffsetStartLow,
1977 writeOffsetStartHigh,
1978 nNumberOfBytesToWrite,
1983 if (NO_ERROR != palError)
1985 ERROR("Unable to obtain write transaction lock");
1991 // Release the data lock before performing the (possibly blocking)
1995 pLocalDataLock->ReleaseLock(pThread, FALSE);
1996 pLocalDataLock = NULL;
1999 #if WRITE_0_BYTES_HANGS_TTY
2000 if( nNumberOfBytesToWrite == 0 && isatty(ifd) )
2003 *lpNumberOfBytesWritten = 0;
2008 res = write( ifd, lpBuffer, nNumberOfBytesToWrite );
2009 TRACE("write() returns %d\n", res);
2013 *lpNumberOfBytesWritten = res;
2017 palError = FILEGetLastErrorFromErrno();
2022 if (NULL != pTransactionLock)
2024 pTransactionLock->ReleaseLock();
2027 if (NULL != pLocalDataLock)
2029 pLocalDataLock->ReleaseLock(pThread, FALSE);
2032 if (NULL != pFileObject)
2034 pFileObject->ReleaseReference(pThread);
2046 lpOverlapped always NULL.
2054 IN LPCVOID lpBuffer,
2055 IN DWORD nNumberOfBytesToWrite,
2056 OUT LPDWORD lpNumberOfBytesWritten,
2057 IN LPOVERLAPPED lpOverlapped)
2060 CPalThread *pThread;
2062 PERF_ENTRY(WriteFile);
2063 ENTRY("WriteFile(hFile=%p, lpBuffer=%p, nToWrite=%u, lpWritten=%p, "
2064 "lpOverlapped=%p)\n", hFile, lpBuffer, nNumberOfBytesToWrite,
2065 lpNumberOfBytesWritten, lpOverlapped);
2067 pThread = InternalGetCurrentThread();
2069 palError = InternalWriteFile(
2073 nNumberOfBytesToWrite,
2074 lpNumberOfBytesWritten,
2078 if (NO_ERROR != palError)
2080 pThread->SetLastError(palError);
2083 LOGEXIT("WriteFile returns BOOL %d\n", NO_ERROR == palError);
2084 PERF_EXIT(WriteFile);
2085 return NO_ERROR == palError;
2089 CorUnix::InternalReadFile(
2090 CPalThread *pThread,
2093 DWORD nNumberOfBytesToRead,
2094 LPDWORD lpNumberOfBytesRead,
2095 LPOVERLAPPED lpOverlapped
2098 PAL_ERROR palError = 0;
2099 IPalObject *pFileObject = NULL;
2100 CFileProcessLocalData *pLocalData = NULL;
2101 IDataLock *pLocalDataLock = NULL;
2102 IFileTransactionLock *pTransactionLock = NULL;
2105 LONG readOffsetStartLow = 0, readOffsetStartHigh = 0;
2108 if (NULL != lpNumberOfBytesRead)
2111 // This must be set to 0 before any other error checking takes
2115 *lpNumberOfBytesRead = 0;
2119 ERROR( "lpNumberOfBytesRead is NULL\n" );
2120 palError = ERROR_INVALID_PARAMETER;
2124 if (INVALID_HANDLE_VALUE == hFile)
2126 ERROR( "Invalid file handle\n" );
2127 palError = ERROR_INVALID_HANDLE;
2130 else if (NULL != lpOverlapped)
2132 ASSERT( "lpOverlapped is not NULL, as it should be.\n" );
2133 palError = ERROR_INVALID_PARAMETER;
2136 else if (NULL == lpBuffer)
2138 ERROR( "Invalid parameter. (lpBuffer:%p)\n", lpBuffer);
2139 palError = ERROR_NOACCESS;
2143 palError = g_pObjectManager->ReferenceObjectByHandle(
2151 if (NO_ERROR != palError)
2156 palError = pFileObject->GetProcessLocalData(
2160 reinterpret_cast<void**>(&pLocalData)
2163 if (NO_ERROR != palError)
2168 if (pLocalData->open_flags_deviceaccessonly == TRUE)
2170 ERROR("File open for device access only\n");
2171 palError = ERROR_ACCESS_DENIED;
2175 ifd = pLocalData->unix_fd;
2178 // Inform the lock controller for this file (if any) of our intention
2179 // to perform a read. (Note that pipes don't have lock controllers.)
2182 if (NULL != pLocalData->pLockController)
2184 /* Get the current file position to calculate the region to lock */
2185 palError = InternalSetFilePointerForUnixFd(
2188 &readOffsetStartHigh,
2193 if (NO_ERROR != palError)
2195 ASSERT("Failed to get the current file position\n");
2196 palError = ERROR_INTERNAL_ERROR;
2200 palError = pLocalData->pLockController->GetTransactionLock(
2202 IFileLockController::ReadLock,
2204 readOffsetStartHigh,
2205 nNumberOfBytesToRead,
2210 if (NO_ERROR != palError)
2212 ERROR("Unable to obtain read transaction lock");
2218 // Release the data lock before performing the (possibly blocking)
2222 pLocalDataLock->ReleaseLock(pThread, FALSE);
2223 pLocalDataLock = NULL;
2227 TRACE("Reading from file descriptor %d\n", ifd);
2228 res = read(ifd, lpBuffer, nNumberOfBytesToRead);
2229 TRACE("read() returns %d\n", res);
2233 *lpNumberOfBytesRead = res;
2235 else if (errno == EINTR)
2237 // Try to read again.
2242 palError = FILEGetLastErrorFromErrno();
2247 if (NULL != pTransactionLock)
2249 pTransactionLock->ReleaseLock();
2252 if (NULL != pLocalDataLock)
2254 pLocalDataLock->ReleaseLock(pThread, FALSE);
2257 if (NULL != pFileObject)
2259 pFileObject->ReleaseReference(pThread);
2270 lpOverlapped always NULL.
2278 OUT LPVOID lpBuffer,
2279 IN DWORD nNumberOfBytesToRead,
2280 OUT LPDWORD lpNumberOfBytesRead,
2281 IN LPOVERLAPPED lpOverlapped)
2284 CPalThread *pThread;
2286 PERF_ENTRY(ReadFile);
2287 ENTRY("ReadFile(hFile=%p, lpBuffer=%p, nToRead=%u, "
2288 "lpRead=%p, lpOverlapped=%p)\n",
2289 hFile, lpBuffer, nNumberOfBytesToRead,
2290 lpNumberOfBytesRead, lpOverlapped);
2292 pThread = InternalGetCurrentThread();
2294 palError = InternalReadFile(
2298 nNumberOfBytesToRead,
2299 lpNumberOfBytesRead,
2303 if (NO_ERROR != palError)
2305 pThread->SetLastError(palError);
2308 LOGEXIT("ReadFile returns BOOL %d\n", NO_ERROR == palError);
2309 PERF_EXIT(ReadFile);
2310 return NO_ERROR == palError;
2323 IN DWORD nStdHandle)
2325 CPalThread *pThread;
2326 HANDLE hRet = INVALID_HANDLE_VALUE;
2328 PERF_ENTRY(GetStdHandle);
2329 ENTRY("GetStdHandle(nStdHandle=%#x)\n", nStdHandle);
2331 pThread = InternalGetCurrentThread();
2332 switch( nStdHandle )
2334 case STD_INPUT_HANDLE:
2337 case STD_OUTPUT_HANDLE:
2340 case STD_ERROR_HANDLE:
2344 ERROR("nStdHandle is invalid\n");
2345 pThread->SetLastError(ERROR_INVALID_PARAMETER);
2349 LOGEXIT("GetStdHandle returns HANDLE %p\n", hRet);
2350 PERF_EXIT(GetStdHandle);
2355 CorUnix::InternalSetEndOfFile(
2356 CPalThread *pThread,
2360 PAL_ERROR palError = 0;
2361 IPalObject *pFileObject = NULL;
2362 CFileProcessLocalData *pLocalData = NULL;
2363 IDataLock *pLocalDataLock = NULL;
2367 if (INVALID_HANDLE_VALUE == hFile)
2369 ERROR( "Invalid file handle\n" );
2370 palError = ERROR_INVALID_HANDLE;
2371 goto InternalSetEndOfFileExit;
2374 palError = g_pObjectManager->ReferenceObjectByHandle(
2382 if (NO_ERROR != palError)
2384 goto InternalSetEndOfFileExit;
2387 palError = pFileObject->GetProcessLocalData(
2391 reinterpret_cast<void**>(&pLocalData)
2394 if (NO_ERROR != palError)
2396 goto InternalSetEndOfFileExit;
2399 if (pLocalData->open_flags_deviceaccessonly == TRUE)
2401 ERROR("File open for device access only\n");
2402 palError = ERROR_ACCESS_DENIED;
2403 goto InternalSetEndOfFileExit;
2406 curr = lseek(pLocalData->unix_fd, 0, SEEK_CUR);
2408 TRACE("current file pointer offset is %u\n", curr);
2411 ERROR("lseek returned %ld\n", curr);
2412 palError = FILEGetLastErrorFromErrno();
2413 goto InternalSetEndOfFileExit;
2416 #if SIZEOF_OFF_T > 4
2417 #if !HAVE_FTRUNCATE_LARGE_LENGTH_SUPPORT
2418 // ftruncate will return the wrong value for some large lengths.
2419 // We'll short-circuit the process and simply return failure for
2420 // the set of values that covers those cases, all of which would
2421 // have failed anyway on any standard-sized hard drive.
2422 if (curr >= 0xFFFFFFFF000ULL)
2424 ERROR("Skipping ftruncate because the offset is too large\n");
2425 palError = ERROR_INVALID_PARAMETER;
2426 goto InternalSetEndOfFileExit;
2428 #endif // !HAVE_FTRUNCATE_LARGE_LENGTH_SUPPORT
2429 #endif // SIZEOF_OFF_T
2431 #if HAS_FTRUNCATE_LENGTH_ISSUE
2432 // Perform an additional check to make sure that there's likely to be enough free space to satisfy the
2433 // request. Do this because it's been observed on Mac OSX that ftruncate can return failure but still
2434 // extend the file to consume the remainder of free space.
2436 struct statfs sFileSystemStats;
2438 if (fstatfs(pLocalData->unix_fd, &sFileSystemStats) != 0)
2440 ERROR("fstatfs failed\n");
2441 palError = FILEGetLastErrorFromErrno();
2442 goto InternalSetEndOfFileExit;
2445 // Free space is free blocks times the size of each block in bytes.
2446 cbFreeSpace = (off_t)sFileSystemStats.f_bavail * (off_t)sFileSystemStats.f_bsize;
2448 if (curr > cbFreeSpace)
2450 ERROR("Not enough disk space for ftruncate\n");
2451 palError = ERROR_DISK_FULL;
2452 goto InternalSetEndOfFileExit;
2454 #endif // HAS_FTRUNCATE_LENGTH_ISSUE
2456 if ( ftruncate(pLocalData->unix_fd, curr) != 0 )
2458 ERROR("ftruncate failed\n");
2459 if ( errno == EACCES )
2461 ERROR("file may not be writable\n");
2463 palError = FILEGetLastErrorFromErrno();
2464 goto InternalSetEndOfFileExit;
2468 InternalSetEndOfFileExit:
2470 // Windows starts returning ERROR_INVALID_PARAMETER at an arbitrary file size (~16TB). The file system
2471 // underneath us may be able to support larger and it would be a shame to prevent that. As a compromise,
2472 // if the operation fails and the file size was above the Windows limit map ERROR_DISK_FULL to
2473 // ERROR_INVALID_PARAMETER.
2474 // curr has been checked to be positive after getting the value from lseek. The following cast is put to
2475 // suppress the compilation warning.
2476 if (palError == ERROR_DISK_FULL && (static_cast<UINT64>(curr) > 0x00000fffffff0000ULL ) )
2477 palError = ERROR_INVALID_PARAMETER;
2479 if (NULL != pLocalDataLock)
2481 pLocalDataLock->ReleaseLock(pThread, FALSE);
2484 if (NULL != pFileObject)
2486 pFileObject->ReleaseReference(pThread);
2505 PAL_ERROR palError = NO_ERROR;
2506 CPalThread *pThread;;
2508 PERF_ENTRY(SetEndOfFile);
2509 ENTRY("SetEndOfFile(hFile=%p)\n", hFile);
2511 pThread = InternalGetCurrentThread();
2513 palError = InternalSetEndOfFile(
2518 if (NO_ERROR != palError)
2520 pThread->SetLastError(palError);
2523 LOGEXIT("SetEndOfFile returns BOOL %d\n", NO_ERROR == palError);
2524 PERF_EXIT(SetEndOfFile);
2525 return NO_ERROR == palError;
2529 // We need to break out the actual mechanics of setting the file pointer
2530 // on the unix FD for InternalReadFile and InternalWriteFile, as they
2531 // need to call this routine in order to determine the value of the
2532 // current file pointer when computing the scope of their transaction
2533 // lock. If we didn't break out this logic we'd end up referencing the file
2534 // handle multiple times, and, in the process, would attempt to recursively
2535 // obtain the local process data lock for the underlying file object.
2539 InternalSetFilePointerForUnixFd(
2541 LONG lDistanceToMove,
2542 PLONG lpDistanceToMoveHigh,
2544 PLONG lpNewFilePointerLow
2547 PAL_ERROR palError = NO_ERROR;
2548 int seek_whence = 0;
2549 __int64 seek_offset = 0LL;
2550 __int64 seek_res = 0LL;
2553 switch( dwMoveMethod )
2556 seek_whence = SEEK_SET;
2559 seek_whence = SEEK_CUR;
2562 seek_whence = SEEK_END;
2565 ERROR("dwMoveMethod = %d is invalid\n", dwMoveMethod);
2566 palError = ERROR_INVALID_PARAMETER;
2571 // According to MSDN, if lpDistanceToMoveHigh is not null,
2572 // lDistanceToMove is treated as unsigned;
2573 // it is treated as signed otherwise
2576 if ( lpDistanceToMoveHigh )
2578 /* set the high 32 bits of the offset */
2579 seek_offset = ((__int64)*lpDistanceToMoveHigh << 32);
2581 /* set the low 32 bits */
2582 /* cast to unsigned long to avoid sign extension */
2583 seek_offset |= (ULONG) lDistanceToMove;
2587 seek_offset |= lDistanceToMove;
2590 /* store the current position, in case the lseek moves the pointer
2591 before the beginning of the file */
2592 old_offset = lseek(iUnixFd, 0, SEEK_CUR);
2593 if (old_offset == -1)
2595 ERROR("lseek(fd,0,SEEK_CUR) failed errno:%d (%s)\n",
2596 errno, strerror(errno));
2597 palError = ERROR_ACCESS_DENIED;
2601 // Check to see if we're going to seek to a negative offset.
2602 // If we're seeking from the beginning or the current mark,
2604 if ((seek_whence == SEEK_SET && seek_offset < 0) ||
2605 (seek_whence == SEEK_CUR && seek_offset + old_offset < 0))
2607 palError = ERROR_NEGATIVE_SEEK;
2610 else if (seek_whence == SEEK_END && seek_offset < 0)
2612 // We need to determine if we're seeking past the
2613 // beginning of the file, but we don't want to adjust
2614 // the mark in the process. stat is the only way to
2616 struct stat fileData;
2619 result = fstat(iUnixFd, &fileData);
2622 // It's a bad fd. This shouldn't happen because
2623 // we've already called lseek on it, but you
2624 // never know. This is the best we can do.
2625 palError = ERROR_ACCESS_DENIED;
2628 if (fileData.st_size < -seek_offset)
2630 // Seeking past the beginning.
2631 palError = ERROR_NEGATIVE_SEEK;
2636 seek_res = (__int64)lseek( iUnixFd,
2641 /* lseek() returns -1 on error, but also can seek to negative
2642 file offsets, so -1 can also indicate a successful seek to offset
2643 -1. Win32 doesn't allow negative file offsets, so either case
2645 ERROR("lseek failed errno:%d (%s)\n", errno, strerror(errno));
2646 lseek(iUnixFd, old_offset, SEEK_SET);
2647 palError = ERROR_ACCESS_DENIED;
2651 /* store high-order DWORD */
2652 if ( lpDistanceToMoveHigh )
2653 *lpDistanceToMoveHigh = (DWORD)(seek_res >> 32);
2655 /* return low-order DWORD of seek result */
2656 *lpNewFilePointerLow = (DWORD)seek_res;
2665 CorUnix::InternalSetFilePointer(
2666 CPalThread *pThread,
2668 LONG lDistanceToMove,
2669 PLONG lpDistanceToMoveHigh,
2671 PLONG lpNewFilePointerLow
2674 PAL_ERROR palError = NO_ERROR;
2675 IPalObject *pFileObject = NULL;
2676 CFileProcessLocalData *pLocalData = NULL;
2677 IDataLock *pLocalDataLock = NULL;
2679 if (INVALID_HANDLE_VALUE == hFile)
2681 ERROR( "Invalid file handle\n" );
2682 palError = ERROR_INVALID_HANDLE;
2683 goto InternalSetFilePointerExit;
2686 palError = g_pObjectManager->ReferenceObjectByHandle(
2694 if (NO_ERROR != palError)
2696 goto InternalSetFilePointerExit;
2699 palError = pFileObject->GetProcessLocalData(
2703 reinterpret_cast<void**>(&pLocalData)
2706 if (NO_ERROR != palError)
2708 goto InternalSetFilePointerExit;
2711 palError = InternalSetFilePointerForUnixFd(
2712 pLocalData->unix_fd,
2714 lpDistanceToMoveHigh,
2719 InternalSetFilePointerExit:
2721 if (NULL != pLocalDataLock)
2723 pLocalDataLock->ReleaseLock(pThread, FALSE);
2726 if (NULL != pFileObject)
2728 pFileObject->ReleaseReference(pThread);
2744 IN LONG lDistanceToMove,
2745 IN PLONG lpDistanceToMoveHigh,
2746 IN DWORD dwMoveMethod)
2748 PAL_ERROR palError = NO_ERROR;
2749 CPalThread *pThread;
2750 LONG lNewFilePointerLow = 0;
2752 PERF_ENTRY(SetFilePointer);
2753 ENTRY("SetFilePointer(hFile=%p, lDistance=%d, lpDistanceHigh=%p, "
2754 "dwMoveMethod=%#x)\n", hFile, lDistanceToMove,
2755 lpDistanceToMoveHigh, dwMoveMethod);
2757 pThread = InternalGetCurrentThread();
2759 palError = InternalSetFilePointer(
2763 lpDistanceToMoveHigh,
2768 if (NO_ERROR != palError)
2770 lNewFilePointerLow = INVALID_SET_FILE_POINTER;
2773 /* This function must always call SetLastError - even if successful.
2774 If we seek to a value greater than 2^32 - 1, we will effectively be
2775 returning a negative value from this function. Now, let's say that
2776 returned value is -1. Furthermore, assume that win32error has been
2777 set before even entering this function. Then, when this function
2778 returns to SetFilePointer in win32native.cs, it will have returned
2779 -1 and win32error will have been set, which will cause an error to be
2780 returned. Since -1 may not be an error in this case and since we
2781 can't assume that the win32error is related to SetFilePointer,
2782 we need to always call SetLastError here. That way, if this function
2783 succeeds, SetFilePointer in win32native won't mistakenly determine
2785 pThread->SetLastError(palError);
2787 LOGEXIT("SetFilePointer returns DWORD %#x\n", lNewFilePointerLow);
2788 PERF_EXIT(SetFilePointer);
2789 return lNewFilePointerLow;
2802 IN LARGE_INTEGER liDistanceToMove,
2803 OUT PLARGE_INTEGER lpNewFilePointer,
2804 IN DWORD dwMoveMethod)
2806 PAL_ERROR palError = NO_ERROR;
2807 CPalThread *pThread;
2810 PERF_ENTRY(SetFilePointerEx);
2811 ENTRY("SetFilePointerEx(hFile=%p, liDistanceToMove=0x%llx, "
2812 "lpNewFilePointer=%p (0x%llx), dwMoveMethod=0x%x)\n", hFile,
2813 liDistanceToMove.QuadPart, lpNewFilePointer,
2814 (lpNewFilePointer) ? (*lpNewFilePointer).QuadPart : 0, dwMoveMethod);
2816 LONG lDistanceToMove;
2817 lDistanceToMove = (LONG)liDistanceToMove.u.LowPart;
2818 LONG lDistanceToMoveHigh;
2819 lDistanceToMoveHigh = liDistanceToMove.u.HighPart;
2821 LONG lNewFilePointerLow = 0;
2823 pThread = InternalGetCurrentThread();
2825 palError = InternalSetFilePointer(
2829 &lDistanceToMoveHigh,
2834 if (NO_ERROR != palError)
2836 pThread->SetLastError(palError);
2840 if (lpNewFilePointer != NULL)
2842 lpNewFilePointer->u.LowPart = (DWORD)lNewFilePointerLow;
2843 lpNewFilePointer->u.HighPart = (DWORD)lDistanceToMoveHigh;
2848 LOGEXIT("SetFilePointerEx returns BOOL %d\n", Ret);
2849 PERF_EXIT(SetFilePointerEx);
2854 CorUnix::InternalGetFileSize(
2855 CPalThread *pThread,
2857 DWORD *pdwFileSizeLow,
2858 DWORD *pdwFileSizeHigh
2861 PAL_ERROR palError = NO_ERROR;
2862 IPalObject *pFileObject = NULL;
2863 CFileProcessLocalData *pLocalData = NULL;
2864 IDataLock *pLocalDataLock = NULL;
2866 struct stat stat_data;
2868 if (INVALID_HANDLE_VALUE == hFile)
2870 ERROR( "Invalid file handle\n" );
2871 palError = ERROR_INVALID_HANDLE;
2872 goto InternalGetFileSizeExit;
2875 palError = g_pObjectManager->ReferenceObjectByHandle(
2883 if (NO_ERROR != palError)
2885 goto InternalGetFileSizeExit;
2888 palError = pFileObject->GetProcessLocalData(
2892 reinterpret_cast<void**>(&pLocalData)
2895 if (NO_ERROR != palError)
2897 goto InternalGetFileSizeExit;
2900 if (fstat(pLocalData->unix_fd, &stat_data) != 0)
2902 ERROR("fstat failed of file descriptor %d\n", pLocalData->unix_fd);
2903 palError = FILEGetLastErrorFromErrno();
2904 goto InternalGetFileSizeExit;
2907 *pdwFileSizeLow = (DWORD)stat_data.st_size;
2909 if (NULL != pdwFileSizeHigh)
2911 #if SIZEOF_OFF_T > 4
2912 *pdwFileSizeHigh = (DWORD)(stat_data.st_size >> 32);
2914 *pdwFileSizeHigh = 0;
2918 InternalGetFileSizeExit:
2920 if (NULL != pLocalDataLock)
2922 pLocalDataLock->ReleaseLock(pThread, FALSE);
2925 if (NULL != pFileObject)
2927 pFileObject->ReleaseReference(pThread);
2943 OUT LPDWORD lpFileSizeHigh)
2945 PAL_ERROR palError = NO_ERROR;
2946 CPalThread *pThread;
2947 DWORD dwFileSizeLow;
2949 PERF_ENTRY(GetFileSize);
2950 ENTRY("GetFileSize(hFile=%p, lpFileSizeHigh=%p)\n", hFile, lpFileSizeHigh);
2952 pThread = InternalGetCurrentThread();
2954 palError = InternalGetFileSize(
2961 if (NO_ERROR != palError)
2963 pThread->SetLastError(palError);
2964 dwFileSizeLow = INVALID_FILE_SIZE;
2967 LOGEXIT("GetFileSize returns DWORD %u\n", dwFileSizeLow);
2968 PERF_EXIT(GetFileSize);
2969 return dwFileSizeLow;
2979 PALAPI GetFileSizeEx(
2981 OUT PLARGE_INTEGER lpFileSize)
2983 PAL_ERROR palError = NO_ERROR;
2984 CPalThread *pThread;
2985 DWORD dwFileSizeHigh;
2986 DWORD dwFileSizeLow;
2988 PERF_ENTRY(GetFileSizeEx);
2989 ENTRY("GetFileSizeEx(hFile=%p, lpFileSize=%p)\n", hFile, lpFileSize);
2991 pThread = InternalGetCurrentThread();
2993 if (lpFileSize != NULL)
2995 palError = InternalGetFileSize(
3002 lpFileSize->u.LowPart = dwFileSizeLow;
3003 lpFileSize->u.HighPart = dwFileSizeHigh;
3007 palError = ERROR_INVALID_PARAMETER;
3010 if (NO_ERROR != palError)
3012 pThread->SetLastError(palError);
3015 LOGEXIT("GetFileSizeEx returns BOOL %d\n", NO_ERROR == palError);
3016 PERF_EXIT(GetFileSizeEx);
3017 return NO_ERROR == palError;
3021 CorUnix::InternalFlushFileBuffers(
3022 CPalThread *pThread,
3026 PAL_ERROR palError = NO_ERROR;
3027 IPalObject *pFileObject = NULL;
3028 CFileProcessLocalData *pLocalData = NULL;
3029 IDataLock *pLocalDataLock = NULL;
3031 if (INVALID_HANDLE_VALUE == hFile)
3033 ERROR( "Invalid file handle\n" );
3034 palError = ERROR_INVALID_HANDLE;
3035 goto InternalFlushFileBuffersExit;
3038 palError = g_pObjectManager->ReferenceObjectByHandle(
3046 if (NO_ERROR != palError)
3048 goto InternalFlushFileBuffersExit;
3051 palError = pFileObject->GetProcessLocalData(
3055 reinterpret_cast<void**>(&pLocalData)
3058 if (NO_ERROR != palError)
3060 goto InternalFlushFileBuffersExit;
3063 if (pLocalData->open_flags_deviceaccessonly == TRUE)
3065 ERROR("File open for device access only\n");
3066 palError = ERROR_ACCESS_DENIED;
3067 goto InternalFlushFileBuffersExit;
3070 #if HAVE_FSYNC || defined(__APPLE__)
3074 #if defined(__APPLE__)
3075 if (fcntl(pLocalData->unix_fd, F_FULLFSYNC) != -1)
3078 if (fsync(pLocalData->unix_fd) == 0)
3085 // Execution was interrupted by a signal, so restart.
3086 TRACE("fsync(%d) was interrupted. Restarting\n", pLocalData->unix_fd);
3090 palError = FILEGetLastErrorFromErrno();
3091 WARN("fsync(%d) failed with error %d\n", pLocalData->unix_fd, errno);
3094 } while (NO_ERROR == palError);
3096 /* flush all buffers out to disk - there is no way to flush
3097 an individual file descriptor's buffers out. */
3099 #endif // HAVE_FSYNC else
3102 InternalFlushFileBuffersExit:
3104 if (NULL != pLocalDataLock)
3106 pLocalDataLock->ReleaseLock(pThread, FALSE);
3109 if (NULL != pFileObject)
3111 pFileObject->ReleaseReference(pThread);
3129 PAL_ERROR palError = NO_ERROR;
3130 CPalThread *pThread;
3132 PERF_ENTRY(FlushFileBuffers);
3133 ENTRY("FlushFileBuffers(hFile=%p)\n", hFile);
3135 pThread = InternalGetCurrentThread();
3137 palError = InternalFlushFileBuffers(
3142 if (NO_ERROR != palError)
3144 pThread->SetLastError(palError);
3147 LOGEXIT("FlushFileBuffers returns BOOL %d\n", NO_ERROR == palError);
3148 PERF_EXIT(FlushFileBuffers);
3149 return NO_ERROR == palError;
3153 CorUnix::InternalGetFileType(
3154 CPalThread *pThread,
3159 PAL_ERROR palError = NO_ERROR;
3160 IPalObject *pFileObject = NULL;
3161 CFileProcessLocalData *pLocalData = NULL;
3162 IDataLock *pLocalDataLock = NULL;
3164 struct stat stat_data;
3166 if (INVALID_HANDLE_VALUE == hFile)
3168 ERROR( "Invalid file handle\n" );
3169 palError = ERROR_INVALID_HANDLE;
3170 goto InternalGetFileTypeExit;
3173 palError = g_pObjectManager->ReferenceObjectByHandle(
3181 if (NO_ERROR != palError)
3183 goto InternalGetFileTypeExit;
3186 palError = pFileObject->GetProcessLocalData(
3190 reinterpret_cast<void**>(&pLocalData)
3193 if (NO_ERROR != palError)
3195 goto InternalGetFileTypeExit;
3198 if (pLocalData->open_flags_deviceaccessonly == TRUE)
3200 ERROR("File open for device access only\n");
3201 palError = ERROR_ACCESS_DENIED;
3202 goto InternalGetFileTypeExit;
3205 if (fstat(pLocalData->unix_fd, &stat_data) != 0)
3207 ERROR("fstat failed of file descriptor %d\n", pLocalData->unix_fd);
3208 palError = FILEGetLastErrorFromErrno();
3209 goto InternalGetFileTypeExit;
3212 TRACE("st_mode & S_IFMT = %#x\n", stat_data.st_mode & S_IFMT);
3213 if (S_ISREG(stat_data.st_mode) || S_ISDIR(stat_data.st_mode))
3215 *pdwFileType = FILE_TYPE_DISK;
3217 else if (S_ISCHR(stat_data.st_mode))
3219 *pdwFileType = FILE_TYPE_CHAR;
3221 else if (S_ISFIFO(stat_data.st_mode))
3223 *pdwFileType = FILE_TYPE_PIPE;
3227 *pdwFileType = FILE_TYPE_UNKNOWN;
3231 InternalGetFileTypeExit:
3233 if (NULL != pLocalDataLock)
3235 pLocalDataLock->ReleaseLock(pThread, FALSE);
3238 if (NULL != pFileObject)
3240 pFileObject->ReleaseReference(pThread);
3260 PAL_ERROR palError = NO_ERROR;
3261 CPalThread *pThread;
3264 PERF_ENTRY(GetFileType);
3265 ENTRY("GetFileType(hFile=%p)\n", hFile);
3267 pThread = InternalGetCurrentThread();
3269 palError = InternalGetFileType(
3275 if (NO_ERROR != palError)
3277 dwFileType = FILE_TYPE_UNKNOWN;
3278 pThread->SetLastError(palError);
3280 else if (FILE_TYPE_UNKNOWN == dwFileType)
3282 pThread->SetLastError(palError);
3286 LOGEXIT("GetFileType returns DWORD %#x\n", dwFileType);
3287 PERF_EXIT(GetFileType);
3291 #define ENSURE_UNIQUE_NOT_ZERO \
3292 if ( uUniqueSeed == 0 ) \
3301 uUnique is always 0.
3303 const int MAX_PREFIX = 3;
3304 const int MAX_SEEDSIZE = 8; /* length of "unique portion of
3305 the string, plus extension(FFFF.TMP). */
3306 static USHORT uUniqueSeed = 0;
3307 static BOOL IsInitialized = FALSE;
3312 IN LPCSTR lpPathName,
3313 IN LPCSTR lpPrefixString,
3315 OUT LPSTR lpTempFileName)
3317 CPalThread *pThread;
3319 PathCharString full_namePS;
3321 CHAR * file_template;
3322 PathCharString file_templatePS;
3323 CHAR chLastPathNameChar;
3328 USHORT uLoopCounter = 0;
3330 PERF_ENTRY(GetTempFileNameA);
3331 ENTRY("GetTempFileNameA(lpPathName=%p (%s), lpPrefixString=%p (%s), uUnique=%u, "
3332 "lpTempFileName=%p)\n", lpPathName?lpPathName:"NULL", lpPathName?lpPathName:"NULL",
3333 lpPrefixString?lpPrefixString:"NULL",
3334 lpPrefixString?lpPrefixString:"NULL", uUnique,
3335 lpTempFileName?lpTempFileName:"NULL");
3337 pThread = InternalGetCurrentThread();
3338 if ( !IsInitialized )
3340 uUniqueSeed = (USHORT)( time( NULL ) );
3342 /* On the off chance 0 is returned.
3343 0 being the error return code. */
3344 ENSURE_UNIQUE_NOT_ZERO
3345 IsInitialized = TRUE;
3348 if ( !lpPathName || *lpPathName == '\0' )
3350 pThread->SetLastError( ERROR_DIRECTORY );
3354 if ( NULL == lpTempFileName )
3356 ERROR( "lpTempFileName cannot be NULL\n" );
3357 pThread->SetLastError( ERROR_INVALID_PARAMETER );
3361 if ( strlen( lpPathName ) + MAX_SEEDSIZE + MAX_PREFIX >= MAX_LONGPATH )
3363 WARN( "File names larger than MAX_LONGPATH (%d)!\n", MAX_LONGPATH );
3364 pThread->SetLastError( ERROR_FILENAME_EXCED_RANGE );
3368 length = strlen(lpPathName) + MAX_SEEDSIZE + MAX_PREFIX + 10;
3369 file_template = file_templatePS.OpenStringBuffer(length);
3370 if (NULL == file_template)
3372 pThread->SetLastError(ERROR_NOT_ENOUGH_MEMORY);
3375 *file_template = '\0';
3376 strcat_s( file_template, file_templatePS.GetSizeOf(), lpPathName );
3377 file_templatePS.CloseBuffer(length);
3379 chLastPathNameChar = file_template[strlen(file_template)-1];
3380 if (chLastPathNameChar != '\\' && chLastPathNameChar != '/')
3382 strcat_s( file_template, file_templatePS.GetSizeOf(), "\\" );
3385 if ( lpPrefixString )
3387 strncat_s( file_template, file_templatePS.GetSizeOf(), lpPrefixString, MAX_PREFIX );
3389 FILEDosToUnixPathA( file_template );
3390 strncat_s( file_template, file_templatePS.GetSizeOf(), "%.4x.TMP", MAX_SEEDSIZE );
3392 /* Create the file. */
3393 dwError = GetLastError();
3394 pThread->SetLastError( NOERROR );
3396 length = strlen(file_template) + MAX_SEEDSIZE + MAX_PREFIX;
3397 full_name = full_namePS.OpenStringBuffer(length);
3398 if (NULL == full_name)
3400 pThread->SetLastError(ERROR_NOT_ENOUGH_MEMORY);
3403 sprintf_s( full_name, full_namePS.GetSizeOf(), file_template, (0 == uUnique) ? uUniqueSeed : uUnique);
3404 full_namePS.CloseBuffer(length);
3406 hTempFile = CreateFileA( full_name, GENERIC_WRITE,
3407 FILE_SHARE_READ, NULL, CREATE_NEW, 0, NULL );
3411 /* The USHORT will overflow back to 0 if we go past
3412 65536 files, so break the loop after 65536 iterations.
3413 If the CreateFile call was not successful within that
3414 number of iterations, then there are no temp file names
3415 left for that directory. */
3416 while ( ERROR_PATH_NOT_FOUND != GetLastError() &&
3417 INVALID_HANDLE_VALUE == hTempFile && uLoopCounter < 0xFFFF )
3420 ENSURE_UNIQUE_NOT_ZERO;
3422 pThread->SetLastError( NOERROR );
3423 sprintf_s( full_name, full_namePS.GetSizeOf(), file_template, uUniqueSeed );
3424 hTempFile = CreateFileA( full_name, GENERIC_WRITE,
3425 FILE_SHARE_READ, NULL, CREATE_NEW, 0, NULL );
3431 /* Reset the error code.*/
3432 if ( NOERROR == GetLastError() )
3434 pThread->SetLastError( dwError );
3437 /* Windows sets ERROR_FILE_EXISTS,if there
3438 are no available temp files. */
3439 if ( INVALID_HANDLE_VALUE != hTempFile )
3445 ENSURE_UNIQUE_NOT_ZERO;
3452 if ( CloseHandle( hTempFile ) )
3454 if (strcpy_s( lpTempFileName, MAX_LONGPATH, full_name ) != SAFECRT_SUCCESS)
3456 ERROR( "strcpy_s failed!\n");
3457 pThread->SetLastError( ERROR_FILENAME_EXCED_RANGE );
3458 *lpTempFileName = '\0';
3464 ASSERT( "Unable to close the handle %p\n", hTempFile );
3465 pThread->SetLastError( ERROR_INTERNAL_ERROR );
3466 *lpTempFileName = '\0';
3470 else if ( INVALID_HANDLE_VALUE == hTempFile && uLoopCounter < 0xFFFF )
3472 ERROR( "Unable to create temp file. \n" );
3475 if ( ERROR_PATH_NOT_FOUND == GetLastError() )
3477 /* CreateFile failed because it could not
3479 pThread->SetLastError( ERROR_DIRECTORY );
3480 } /* else use the lasterror value from CreateFileA */
3484 TRACE( "65535 files already exist in the directory. "
3485 "No temp files available for creation.\n" );
3486 pThread->SetLastError( ERROR_FILE_EXISTS );
3490 LOGEXIT("GetTempFileNameA returns UINT %u\n", uRet);
3491 PERF_EXIT(GetTempFileNameA);
3500 uUnique is always 0.
3505 IN LPCWSTR lpPathName,
3506 IN LPCWSTR lpPrefixString,
3508 OUT LPWSTR lpTempFileName)
3510 CPalThread *pThread;
3512 INT prefix_size = 0;
3514 CHAR * prefix_string;
3515 CHAR * tempfile_name;
3516 PathCharString full_namePS, prefix_stringPS;
3520 PERF_ENTRY(GetTempFileNameW);
3521 ENTRY("GetTempFileNameW(lpPathName=%p (%S), lpPrefixString=%p (%S), uUnique=%u, "
3522 "lpTempFileName=%p)\n", lpPathName?lpPathName:W16_NULLSTRING, lpPathName?lpPathName:W16_NULLSTRING,
3523 lpPrefixString?lpPrefixString:W16_NULLSTRING,
3524 lpPrefixString?lpPrefixString:W16_NULLSTRING,uUnique, lpTempFileName);
3526 pThread = InternalGetCurrentThread();
3527 /* Sanity checks. */
3528 if ( !lpPathName || *lpPathName == '\0' )
3530 pThread->SetLastError( ERROR_DIRECTORY );
3535 length = (PAL_wcslen(lpPathName)+1) * MaxWCharToAcpLengthFactor;
3536 full_name = full_namePS.OpenStringBuffer(length);
3537 if (NULL == full_name)
3539 pThread->SetLastError(ERROR_NOT_ENOUGH_MEMORY);
3543 path_size = WideCharToMultiByte( CP_ACP, 0, lpPathName, -1, full_name,
3544 length, NULL, NULL );
3546 if( path_size == 0 )
3548 full_namePS.CloseBuffer(0);
3549 DWORD dwLastError = GetLastError();
3550 ASSERT("WideCharToMultiByte failure! error is %d\n", dwLastError);
3551 pThread->SetLastError(ERROR_INTERNAL_ERROR);
3556 full_namePS.CloseBuffer(path_size - 1);
3558 if (lpPrefixString != NULL)
3560 length = (PAL_wcslen(lpPrefixString)+1) * MaxWCharToAcpLengthFactor;
3561 prefix_string = prefix_stringPS.OpenStringBuffer(length);
3562 if (NULL == prefix_string)
3564 pThread->SetLastError(ERROR_NOT_ENOUGH_MEMORY);
3568 prefix_size = WideCharToMultiByte( CP_ACP, 0, lpPrefixString, -1,
3570 MAX_LONGPATH - path_size - MAX_SEEDSIZE,
3573 if( prefix_size == 0 )
3575 prefix_stringPS.CloseBuffer(0);
3576 DWORD dwLastError = GetLastError();
3577 ASSERT("WideCharToMultiByte failure! error is %d\n", dwLastError);
3578 pThread->SetLastError(ERROR_INTERNAL_ERROR);
3582 prefix_stringPS.CloseBuffer(prefix_size - 1);
3585 tempfile_name = (char*)InternalMalloc(MAX_LONGPATH);
3586 if (tempfile_name == NULL)
3588 pThread->SetLastError(ERROR_NOT_ENOUGH_MEMORY);
3593 uRet = GetTempFileNameA(full_name,
3594 (lpPrefixString == NULL) ? NULL : prefix_string,
3598 path_size = MultiByteToWideChar( CP_ACP, 0, tempfile_name, -1,
3599 lpTempFileName, MAX_LONGPATH );
3601 free(tempfile_name);
3602 tempfile_name = NULL;
3605 DWORD dwLastError = GetLastError();
3606 if (dwLastError == ERROR_INSUFFICIENT_BUFFER)
3608 WARN("File names larger than MAX_PATH_FNAME (%d)! \n", MAX_LONGPATH);
3609 dwLastError = ERROR_FILENAME_EXCED_RANGE;
3613 ASSERT("MultiByteToWideChar failure! error is %d", dwLastError);
3614 dwLastError = ERROR_INTERNAL_ERROR;
3616 pThread->SetLastError(dwLastError);
3622 LOGEXIT("GetTempFileNameW returns UINT %u\n", uRet);
3623 PERF_EXIT(GetTempFileNameW);
3629 FILEGetLastErrorFromErrno
3631 Convert errno into the appropriate win32 error and return it.
3633 DWORD FILEGetLastErrorFromErrno( void )
3640 dwRet = ERROR_SUCCESS;
3643 dwRet = ERROR_FILENAME_EXCED_RANGE;
3646 dwRet = ERROR_PATH_NOT_FOUND;
3649 dwRet = ERROR_FILE_NOT_FOUND;
3655 dwRet = ERROR_ACCESS_DENIED;
3658 dwRet = ERROR_ALREADY_EXISTS;
3661 // ENOTEMPTY is the same as EEXIST on AIX. Meaningful when involving directory operations
3663 dwRet = ERROR_DIR_NOT_EMPTY;
3667 dwRet = ERROR_INVALID_HANDLE;
3670 dwRet = ERROR_NOT_ENOUGH_MEMORY;
3677 dwRet = ERROR_DISK_FULL;
3680 dwRet = ERROR_BAD_PATHNAME;
3683 dwRet = ERROR_WRITE_FAULT;
3686 dwRet = ERROR_BAD_PATHNAME;
3689 ERROR("unexpected errno %d (%s); returning ERROR_GEN_FAILURE\n",
3690 errno, strerror(errno));
3691 dwRet = ERROR_GEN_FAILURE;
3694 TRACE("errno = %d (%s), LastError = %d\n", errno, strerror(errno), dwRet);
3701 DIRGetLastErrorFromErrno
3703 Convert errno into the appropriate win32 error and return it.
3705 DWORD DIRGetLastErrorFromErrno( void )
3707 if (errno == ENOENT)
3708 return ERROR_PATH_NOT_FOUND;
3710 return FILEGetLastErrorFromErrno();
3721 There are several (most) error paths here that do not call SetLastError().
3722 This is because we know that CreateFile, ReadFile, and WriteFile will do so,
3723 and will have a much better idea of the specific error.
3728 IN LPCSTR lpExistingFileName,
3729 IN LPCSTR lpNewFileName,
3730 IN BOOL bFailIfExists)
3732 CPalThread *pThread;
3733 HANDLE hSource = INVALID_HANDLE_VALUE;
3734 HANDLE hDest = INVALID_HANDLE_VALUE;
3735 DWORD dwDestCreationMode;
3737 DWORD dwSrcFileAttributes;
3738 struct stat SrcFileStats;
3740 LPSTR lpUnixPath = NULL;
3741 const int buffer_size = 16*1024;
3742 char *buffer = (char*)alloca(buffer_size);
3744 DWORD bytes_written;
3748 PERF_ENTRY(CopyFileA);
3749 ENTRY("CopyFileA(lpExistingFileName=%p (%s), lpNewFileName=%p (%s), bFailIfExists=%d)\n",
3750 lpExistingFileName?lpExistingFileName:"NULL",
3751 lpExistingFileName?lpExistingFileName:"NULL",
3752 lpNewFileName?lpNewFileName:"NULL",
3753 lpNewFileName?lpNewFileName:"NULL", bFailIfExists);
3755 pThread = InternalGetCurrentThread();
3756 if ( bFailIfExists )
3758 dwDestCreationMode = CREATE_NEW;
3762 dwDestCreationMode = CREATE_ALWAYS;
3765 hSource = CreateFileA( lpExistingFileName,
3773 if ( hSource == INVALID_HANDLE_VALUE )
3775 ERROR("CreateFileA failed for %s\n", lpExistingFileName);
3779 /* Need to preserve the file attributes */
3780 dwSrcFileAttributes = GetFileAttributes(lpExistingFileName);
3781 if (dwSrcFileAttributes == 0xffffffff)
3783 ERROR("GetFileAttributes failed for %s\n", lpExistingFileName);
3787 /* Need to preserve the owner/group and chmod() flags */
3788 lpUnixPath = strdup(lpExistingFileName);
3789 if ( lpUnixPath == NULL )
3791 ERROR("strdup() failed\n");
3792 pThread->SetLastError(FILEGetLastErrorFromErrno());
3795 FILEDosToUnixPathA(lpUnixPath);
3796 if (stat (lpUnixPath, &SrcFileStats) == -1)
3798 ERROR("stat() failed for %s\n", lpExistingFileName);
3799 pThread->SetLastError(FILEGetLastErrorFromErrnoAndFilename(lpUnixPath));
3803 hDest = CreateFileA( lpNewFileName,
3811 if ( hDest == INVALID_HANDLE_VALUE )
3813 ERROR("CreateFileA failed for %s\n", lpNewFileName);
3818 lpUnixPath = strdup(lpNewFileName);
3819 if ( lpUnixPath == NULL )
3821 ERROR("strdup() failed\n");
3822 pThread->SetLastError(FILEGetLastErrorFromErrno());
3825 FILEDosToUnixPathA( lpUnixPath );
3828 // We don't set file attributes in CreateFile. The only attribute
3829 // that is reflected on disk in Unix is read-only, and we set that
3831 permissions = (S_IRWXU | S_IRWXG | S_IRWXO);
3832 if ((dwSrcFileAttributes & FILE_ATTRIBUTE_READONLY) != 0)
3834 permissions &= ~(S_IWUSR | S_IWGRP | S_IWOTH);
3837 /* Make sure the new file has the same chmod() flags. */
3838 if (chmod(lpUnixPath, SrcFileStats.st_mode & permissions) == -1)
3840 WARN ("chmod() failed to set mode 0x%x on new file\n",
3841 SrcFileStats.st_mode & permissions);
3842 pThread->SetLastError(FILEGetLastErrorFromErrnoAndFilename(lpUnixPath));
3846 while( (bGood = ReadFile( hSource, buffer, buffer_size, &bytes_read, NULL ))
3849 bGood = ( WriteFile( hDest, buffer, bytes_read, &bytes_written, NULL )
3850 && bytes_written == bytes_read);
3856 ERROR("Copy failed\n");
3858 if ( !CloseHandle(hDest) ||
3859 !DeleteFileA(lpNewFileName) )
3861 ERROR("Unable to clean up partial copy\n");
3863 hDest = INVALID_HANDLE_VALUE;
3870 if ( hSource != INVALID_HANDLE_VALUE )
3872 CloseHandle( hSource );
3874 if ( hDest != INVALID_HANDLE_VALUE )
3876 CloseHandle( hDest );
3883 LOGEXIT("CopyFileA returns BOOL %d\n", bGood);
3884 PERF_EXIT(CopyFileA);
3894 Used for setting read-only attribute on file only.
3900 IN LPCSTR lpFileName,
3901 IN DWORD dwFileAttributes)
3903 CPalThread *pThread;
3904 struct stat stat_data;
3907 DWORD dwLastError = 0;
3909 LPSTR unixFileName = NULL;
3911 PERF_ENTRY(SetFileAttributesA);
3912 ENTRY("SetFileAttributesA(lpFileName=%p (%s), dwFileAttributes=%#x)\n",
3913 lpFileName?lpFileName:"NULL",
3914 lpFileName?lpFileName:"NULL", dwFileAttributes);
3916 pThread = InternalGetCurrentThread();
3918 /* Windows behavior for SetFileAttributes is that any valid attributes
3919 are set on a file and any invalid attributes are ignored. SetFileAttributes
3920 returns success and does not set an error even if some or all of the
3921 attributes are invalid. If all the attributes are invalid, SetFileAttributes
3922 sets a file's attribute to NORMAL. */
3924 /* If dwFileAttributes does not contain READONLY or NORMAL, set it to NORMAL
3925 and print a warning message. */
3926 if ( !(dwFileAttributes & (FILE_ATTRIBUTE_READONLY |FILE_ATTRIBUTE_NORMAL)) )
3928 dwFileAttributes = FILE_ATTRIBUTE_NORMAL;
3929 WARN("dwFileAttributes(%#x) contains attributes that are either not supported "
3930 "or cannot be set via SetFileAttributes.\n");
3933 if ( (dwFileAttributes & FILE_ATTRIBUTE_NORMAL) &&
3934 (dwFileAttributes != FILE_ATTRIBUTE_NORMAL) )
3936 WARN("Ignoring FILE_ATTRIBUTE_NORMAL -- it must be used alone\n");
3939 if (lpFileName == NULL)
3941 dwLastError = ERROR_FILE_NOT_FOUND;
3945 if ((unixFileName = strdup(lpFileName)) == NULL)
3947 ERROR("strdup() failed\n");
3948 dwLastError = ERROR_NOT_ENOUGH_MEMORY;
3952 FILEDosToUnixPathA( unixFileName );
3953 if ( stat(unixFileName, &stat_data) != 0 )
3955 TRACE("stat failed on %s; errno is %d (%s)\n",
3956 unixFileName, errno, strerror(errno));
3957 dwLastError = FILEGetLastErrorFromErrnoAndFilename(unixFileName);
3961 new_mode = stat_data.st_mode;
3962 TRACE("st_mode is %#x\n", new_mode);
3964 /* if we can't do GetFileAttributes on it, don't do SetFileAttributes */
3965 if ( !(new_mode & S_IFREG) && !(new_mode & S_IFDIR) )
3967 ERROR("Not a regular file or directory, S_IFMT is %#x\n",
3969 dwLastError = ERROR_ACCESS_DENIED;
3973 /* set or unset the "read-only" attribute */
3974 if (dwFileAttributes & FILE_ATTRIBUTE_READONLY)
3976 /* remove the write bit from everybody */
3977 new_mode &= ~(S_IWUSR | S_IWGRP | S_IWOTH);
3981 /* give write permission to the owner if the owner
3982 * already has read permission */
3983 if ( new_mode & S_IRUSR )
3985 new_mode |= S_IWUSR;
3988 TRACE("new mode is %#x\n", new_mode);
3991 if ( new_mode != stat_data.st_mode )
3993 if ( chmod(unixFileName, new_mode) != 0 )
3995 ERROR("chmod(%s, %#x) failed\n", unixFileName, new_mode);
3996 dwLastError = FILEGetLastErrorFromErrnoAndFilename(unixFileName);
4004 pThread->SetLastError(dwLastError);
4009 LOGEXIT("SetFileAttributesA returns BOOL %d\n", bRet);
4010 PERF_EXIT(SetFileAttributesA);
4015 CorUnix::InternalCreatePipe(
4016 CPalThread *pThread,
4018 HANDLE *phWritePipe,
4019 LPSECURITY_ATTRIBUTES lpPipeAttributes,
4023 PAL_ERROR palError = NO_ERROR;
4024 IPalObject *pReadFileObject = NULL;
4025 IPalObject *pReadRegisteredFile = NULL;
4026 IPalObject *pWriteFileObject = NULL;
4027 IPalObject *pWriteRegisteredFile = NULL;
4028 IDataLock *pDataLock = NULL;
4029 CFileProcessLocalData *pLocalData = NULL;
4030 CObjectAttributes oaFile(NULL, lpPipeAttributes);
4032 int readWritePipeDes[2] = {-1, -1};
4034 if ((phReadPipe == NULL) || (phWritePipe == NULL))
4036 ERROR("One of the two parameters hReadPipe(%p) and hWritePipe(%p) is Null\n",phReadPipe,phWritePipe);
4037 palError = ERROR_INVALID_PARAMETER;
4038 goto InternalCreatePipeExit;
4041 if ((lpPipeAttributes == NULL) ||
4042 (lpPipeAttributes->bInheritHandle == FALSE) ||
4043 (lpPipeAttributes->lpSecurityDescriptor != NULL))
4045 ASSERT("invalid security attributes!\n");
4046 palError = ERROR_INVALID_PARAMETER;
4047 goto InternalCreatePipeExit;
4050 if (pipe(readWritePipeDes) == -1)
4052 ERROR("pipe() call failed errno:%d (%s) \n", errno, strerror(errno));
4053 palError = ERROR_INTERNAL_ERROR;
4054 goto InternalCreatePipeExit;
4057 /* enable close-on-exec for both pipes; if one gets passed to CreateProcess
4058 it will be "uncloseonexeced" in order to be inherited */
4059 if(-1 == fcntl(readWritePipeDes[0],F_SETFD,1))
4061 ASSERT("can't set close-on-exec flag; fcntl() failed. errno is %d "
4062 "(%s)\n", errno, strerror(errno));
4063 palError = ERROR_INTERNAL_ERROR;
4064 goto InternalCreatePipeExit;
4066 if(-1 == fcntl(readWritePipeDes[1],F_SETFD,1))
4068 ASSERT("can't set close-on-exec flag; fcntl() failed. errno is %d "
4069 "(%s)\n", errno, strerror(errno));
4070 palError = ERROR_INTERNAL_ERROR;
4071 goto InternalCreatePipeExit;
4075 // Setup the object for the read end of the pipe
4078 palError = g_pObjectManager->AllocateObject(
4085 if (NO_ERROR != palError)
4087 goto InternalCreatePipeExit;
4090 palError = pReadFileObject->GetProcessLocalData(
4094 reinterpret_cast<void**>(&pLocalData)
4097 if (NO_ERROR != palError)
4099 goto InternalCreatePipeExit;
4102 pLocalData->inheritable = TRUE;
4103 pLocalData->open_flags = O_RDONLY;
4106 // After storing the file descriptor in the object's local data
4107 // we want to clear it from the array to prevent a possible double
4108 // close if an error occurs.
4111 pLocalData->unix_fd = readWritePipeDes[0];
4112 readWritePipeDes[0] = -1;
4114 pDataLock->ReleaseLock(pThread, TRUE);
4118 // Setup the object for the write end of the pipe
4121 palError = g_pObjectManager->AllocateObject(
4128 if (NO_ERROR != palError)
4130 goto InternalCreatePipeExit;
4133 palError = pWriteFileObject->GetProcessLocalData(
4137 reinterpret_cast<void**>(&pLocalData)
4140 if (NO_ERROR != palError)
4142 goto InternalCreatePipeExit;
4145 pLocalData->inheritable = TRUE;
4146 pLocalData->open_flags = O_WRONLY;
4149 // After storing the file descriptor in the object's local data
4150 // we want to clear it from the array to prevent a possible double
4151 // close if an error occurs.
4154 pLocalData->unix_fd = readWritePipeDes[1];
4155 readWritePipeDes[1] = -1;
4157 pDataLock->ReleaseLock(pThread, TRUE);
4161 // Register the pipe objects
4164 palError = g_pObjectManager->RegisterObject(
4170 &pReadRegisteredFile
4174 // pReadFileObject is invalidated by the call to RegisterObject, so NULL it
4175 // out here to ensure that we don't try to release a reference on
4176 // it down the line.
4179 pReadFileObject = NULL;
4181 if (NO_ERROR != palError)
4183 goto InternalCreatePipeExit;
4186 palError = g_pObjectManager->RegisterObject(
4192 &pWriteRegisteredFile
4196 // pWriteFileObject is invalidated by the call to RegisterObject, so NULL it
4197 // out here to ensure that we don't try to release a reference on
4198 // it down the line.
4201 pWriteFileObject = NULL;
4203 InternalCreatePipeExit:
4205 if (NO_ERROR != palError)
4207 if (-1 != readWritePipeDes[0])
4209 close(readWritePipeDes[0]);
4212 if (-1 != readWritePipeDes[1])
4214 close(readWritePipeDes[1]);
4218 if (NULL != pReadFileObject)
4220 pReadFileObject->ReleaseReference(pThread);
4223 if (NULL != pReadRegisteredFile)
4225 pReadRegisteredFile->ReleaseReference(pThread);
4228 if (NULL != pWriteFileObject)
4230 pWriteFileObject->ReleaseReference(pThread);
4233 if (NULL != pWriteRegisteredFile)
4235 pWriteRegisteredFile->ReleaseReference(pThread);
4251 OUT PHANDLE hReadPipe,
4252 OUT PHANDLE hWritePipe,
4253 IN LPSECURITY_ATTRIBUTES lpPipeAttributes,
4257 CPalThread *pThread;
4259 PERF_ENTRY(CreatePipe);
4260 ENTRY("CreatePipe(hReadPipe:%p, hWritePipe:%p, lpPipeAttributes:%p, nSize:%d\n",
4261 hReadPipe, hWritePipe, lpPipeAttributes, nSize);
4263 pThread = InternalGetCurrentThread();
4265 palError = InternalCreatePipe(
4273 if (NO_ERROR != palError)
4275 pThread->SetLastError(palError);
4278 LOGEXIT("CreatePipe return %s\n", NO_ERROR == palError ? "TRUE":"FALSE");
4279 PERF_EXIT(CreatePipe);
4280 return NO_ERROR == palError;
4284 CorUnix::InternalLockFile(
4285 CPalThread *pThread,
4287 DWORD dwFileOffsetLow,
4288 DWORD dwFileOffsetHigh,
4289 DWORD nNumberOfBytesToLockLow,
4290 DWORD nNumberOfBytesToLockHigh
4293 PAL_ERROR palError = NO_ERROR;
4294 IPalObject *pFileObject = NULL;
4295 CFileProcessLocalData *pLocalData = NULL;
4296 IDataLock *pLocalDataLock = NULL;
4298 if (INVALID_HANDLE_VALUE == hFile)
4300 ERROR( "Invalid file handle\n" );
4301 palError = ERROR_INVALID_HANDLE;
4302 goto InternalLockFileExit;
4305 palError = g_pObjectManager->ReferenceObjectByHandle(
4313 if (NO_ERROR != palError)
4315 goto InternalLockFileExit;
4318 palError = pFileObject->GetProcessLocalData(
4322 reinterpret_cast<void**>(&pLocalData)
4325 if (NO_ERROR != palError)
4327 goto InternalLockFileExit;
4330 if (NULL != pLocalData->pLockController)
4332 palError = pLocalData->pLockController->CreateFileLock(
4336 nNumberOfBytesToLockLow,
4337 nNumberOfBytesToLockHigh,
4338 IFileLockController::ExclusiveFileLock,
4339 IFileLockController::FailImmediately
4345 // This isn't a lockable file (e.g., it may be a pipe)
4348 palError = ERROR_ACCESS_DENIED;
4349 goto InternalLockFileExit;
4352 InternalLockFileExit:
4354 if (NULL != pLocalDataLock)
4356 pLocalDataLock->ReleaseLock(pThread, FALSE);
4359 if (NULL != pFileObject)
4361 pFileObject->ReleaseReference(pThread);
4377 LockFile(HANDLE hFile,
4378 DWORD dwFileOffsetLow,
4379 DWORD dwFileOffsetHigh,
4380 DWORD nNumberOfBytesToLockLow,
4381 DWORD nNumberOfBytesToLockHigh)
4383 CPalThread *pThread;
4384 PAL_ERROR palError = NO_ERROR;
4386 PERF_ENTRY(LockFile);
4387 ENTRY("LockFile(hFile:%p, offsetLow:%u, offsetHigh:%u, nbBytesLow:%u,"
4388 " nbBytesHigh:%u\n", hFile, dwFileOffsetLow, dwFileOffsetHigh,
4389 nNumberOfBytesToLockLow, nNumberOfBytesToLockHigh);
4391 pThread = InternalGetCurrentThread();
4393 palError = InternalLockFile(
4398 nNumberOfBytesToLockLow,
4399 nNumberOfBytesToLockHigh
4402 if (NO_ERROR != palError)
4404 pThread->SetLastError(palError);
4407 LOGEXIT("LockFile returns %s\n", NO_ERROR == palError ? "TRUE":"FALSE");
4408 PERF_EXIT(LockFile);
4409 return NO_ERROR == palError;
4413 CorUnix::InternalUnlockFile(
4414 CPalThread *pThread,
4416 DWORD dwFileOffsetLow,
4417 DWORD dwFileOffsetHigh,
4418 DWORD nNumberOfBytesToUnlockLow,
4419 DWORD nNumberOfBytesToUnlockHigh
4422 PAL_ERROR palError = NO_ERROR;
4423 IPalObject *pFileObject = NULL;
4424 CFileProcessLocalData *pLocalData = NULL;
4425 IDataLock *pLocalDataLock = NULL;
4427 if (INVALID_HANDLE_VALUE == hFile)
4429 ERROR( "Invalid file handle\n" );
4430 palError = ERROR_INVALID_HANDLE;
4431 goto InternalUnlockFileExit;
4434 palError = g_pObjectManager->ReferenceObjectByHandle(
4442 if (NO_ERROR != palError)
4444 goto InternalUnlockFileExit;
4447 palError = pFileObject->GetProcessLocalData(
4451 reinterpret_cast<void**>(&pLocalData)
4454 if (NO_ERROR != palError)
4456 goto InternalUnlockFileExit;
4459 if (NULL != pLocalData->pLockController)
4461 palError = pLocalData->pLockController->ReleaseFileLock(
4465 nNumberOfBytesToUnlockLow,
4466 nNumberOfBytesToUnlockHigh
4472 // This isn't a lockable file (e.g., it may be a pipe)
4475 palError = ERROR_ACCESS_DENIED;
4476 goto InternalUnlockFileExit;
4479 InternalUnlockFileExit:
4481 if (NULL != pLocalDataLock)
4483 pLocalDataLock->ReleaseLock(pThread, FALSE);
4486 if (NULL != pFileObject)
4488 pFileObject->ReleaseReference(pThread);
4503 UnlockFile(HANDLE hFile,
4504 DWORD dwFileOffsetLow,
4505 DWORD dwFileOffsetHigh,
4506 DWORD nNumberOfBytesToUnlockLow,
4507 DWORD nNumberOfBytesToUnlockHigh)
4509 CPalThread *pThread;
4510 PAL_ERROR palError = NO_ERROR;
4512 PERF_ENTRY(UnlockFile);
4513 ENTRY("UnlockFile(hFile:%p, offsetLow:%u, offsetHigh:%u, nbBytesLow:%u,"
4514 "nbBytesHigh:%u\n", hFile, dwFileOffsetLow, dwFileOffsetHigh,
4515 nNumberOfBytesToUnlockLow, nNumberOfBytesToUnlockHigh);
4517 pThread = InternalGetCurrentThread();
4519 palError = InternalUnlockFile(
4524 nNumberOfBytesToUnlockLow,
4525 nNumberOfBytesToUnlockHigh
4528 if (NO_ERROR != palError)
4530 pThread->SetLastError(palError);
4533 LOGEXIT("UnlockFile returns %s\n", NO_ERROR == palError ? "TRUE" : "FALSE");
4534 PERF_EXIT(UnlockFile);
4535 return NO_ERROR == palError;
4539 init_std_handle [static]
4541 utility function for FILEInitStdHandles. do the work that is common to all
4542 three standard handles
4545 HANDLE pStd : Defines which standard handle to assign
4546 FILE *stream : file stream to associate to handle
4549 handle for specified stream, or INVALID_HANDLE_VALUE on failure
4551 static HANDLE init_std_handle(HANDLE * pStd, FILE *stream)
4553 CPalThread *pThread = InternalGetCurrentThread();
4554 PAL_ERROR palError = NO_ERROR;
4555 IPalObject *pFileObject = NULL;
4556 IPalObject *pRegisteredFile = NULL;
4557 IDataLock *pDataLock = NULL;
4558 CFileProcessLocalData *pLocalData = NULL;
4559 IFileLockController *pLockController = NULL;
4560 CObjectAttributes oa;
4562 HANDLE hFile = INVALID_HANDLE_VALUE;
4565 /* duplicate the FILE *, so that we can fclose() in FILECloseHandle without
4566 closing the original */
4567 new_fd = dup(fileno(stream));
4570 ERROR("dup() failed; errno is %d (%s)\n", errno, strerror(errno));
4574 palError = g_pObjectManager->AllocateObject(
4581 if (NO_ERROR != palError)
4586 palError = pFileObject->GetProcessLocalData(
4590 reinterpret_cast<void**>(&pLocalData)
4593 if (NO_ERROR != palError)
4598 pLocalData->inheritable = TRUE;
4599 pLocalData->unix_fd = new_fd;
4600 pLocalData->dwDesiredAccess = 0;
4601 pLocalData->open_flags = 0;
4602 pLocalData->open_flags_deviceaccessonly = FALSE;
4605 // Transfer the lock controller reference from our local variable
4606 // to the local file data
4609 pLocalData->pLockController = pLockController;
4610 pLockController = NULL;
4613 // We've finished initializing our local data, so release that lock
4616 pDataLock->ReleaseLock(pThread, TRUE);
4619 palError = g_pObjectManager->RegisterObject(
4629 // pFileObject is invalidated by the call to RegisterObject, so NULL it
4630 // out here to ensure that we don't try to release a reference on
4631 // it down the line.
4638 if (NULL != pLockController)
4640 pLockController->ReleaseController();
4643 if (NULL != pDataLock)
4645 pDataLock->ReleaseLock(pThread, TRUE);
4648 if (NULL != pFileObject)
4650 pFileObject->ReleaseReference(pThread);
4653 if (NULL != pRegisteredFile)
4655 pRegisteredFile->ReleaseReference(pThread);
4658 if (NO_ERROR == palError)
4662 else if (-1 != new_fd)
4674 Create handle objects for stdin, stdout and stderr
4679 TRUE on success, FALSE on failure
4681 BOOL FILEInitStdHandles(void)
4683 HANDLE stdin_handle;
4684 HANDLE stdout_handle;
4685 HANDLE stderr_handle;
4687 TRACE("creating handle objects for stdin, stdout, stderr\n");
4689 stdin_handle = init_std_handle(&pStdIn, stdin);
4690 if(INVALID_HANDLE_VALUE == stdin_handle)
4692 ERROR("failed to create stdin handle\n");
4696 stdout_handle = init_std_handle(&pStdOut, stdout);
4697 if(INVALID_HANDLE_VALUE == stdout_handle)
4699 ERROR("failed to create stdout handle\n");
4700 CloseHandle(stdin_handle);
4704 stderr_handle = init_std_handle(&pStdErr, stderr);
4705 if(INVALID_HANDLE_VALUE == stderr_handle)
4707 ERROR("failed to create stderr handle\n");
4708 CloseHandle(stdin_handle);
4709 CloseHandle(stdout_handle);
4715 pStdIn = INVALID_HANDLE_VALUE;
4716 pStdOut = INVALID_HANDLE_VALUE;
4717 pStdErr = INVALID_HANDLE_VALUE;
4722 FILECleanupStdHandles
4724 Remove all regions, locked by a file pointer, from shared memory
4729 void FILECleanupStdHandles(void)
4731 HANDLE stdin_handle;
4732 HANDLE stdout_handle;
4733 HANDLE stderr_handle;
4735 TRACE("closing standard handles\n");
4736 stdin_handle = pStdIn;
4737 stdout_handle = pStdOut;
4738 stderr_handle = pStdErr;
4740 pStdIn = INVALID_HANDLE_VALUE;
4741 pStdOut = INVALID_HANDLE_VALUE;
4742 pStdErr = INVALID_HANDLE_VALUE;
4744 if (stdin_handle != INVALID_HANDLE_VALUE)
4746 CloseHandle(stdin_handle);
4749 if (stdout_handle != INVALID_HANDLE_VALUE)
4751 CloseHandle(stdout_handle);
4754 if (stderr_handle != INVALID_HANDLE_VALUE)
4756 CloseHandle(stderr_handle);
4762 GetFileInformationByHandle
4768 GetFileInformationByHandle(
4770 OUT LPBY_HANDLE_FILE_INFORMATION lpFileInformation)
4772 CPalThread *pThread;
4774 DWORD dwLastError = 0;
4776 IPalObject *pFileObject = NULL;
4777 CFileProcessLocalData *pLocalData = NULL;
4778 IDataLock *pLocalDataLock = NULL;
4781 struct stat stat_data;
4783 PERF_ENTRY(GetFileInformationByHandle);
4784 ENTRY("GetFileInformationByHandle(hFile=%p, lpFileInformation=%p)\n",
4785 hFile, lpFileInformation);
4787 pThread = InternalGetCurrentThread();
4789 if (INVALID_HANDLE_VALUE == hFile)
4791 ERROR( "Invalid file handle\n" );
4792 dwLastError = ERROR_INVALID_HANDLE;
4796 dwLastError = g_pObjectManager->ReferenceObjectByHandle(
4804 if (NO_ERROR != dwLastError)
4809 dwLastError = pFileObject->GetProcessLocalData(
4813 reinterpret_cast<void**>(&pLocalData)
4816 if (NO_ERROR != dwLastError)
4821 if ( fstat(pLocalData->unix_fd, &stat_data) != 0 )
4823 if ((dwLastError = FILEGetLastErrorFromErrno()) == ERROR_INTERNAL_ERROR)
4825 ASSERT("fstat() not expected to fail with errno:%d (%s)\n",
4826 errno, strerror(errno));
4831 if ( (stat_data.st_mode & S_IFMT) == S_IFDIR )
4833 dwAttr |= FILE_ATTRIBUTE_DIRECTORY;
4835 else if ( (stat_data.st_mode & S_IFMT) != S_IFREG )
4837 ERROR("Not a regular file or directory, S_IFMT is %#x\n",
4838 stat_data.st_mode & S_IFMT);
4839 dwLastError = ERROR_ACCESS_DENIED;
4843 if ( UTIL_IsReadOnlyBitsSet( &stat_data ) )
4845 dwAttr |= FILE_ATTRIBUTE_READONLY;
4848 /* finally, if nothing is set... */
4851 dwAttr = FILE_ATTRIBUTE_NORMAL;
4854 lpFileInformation->dwFileAttributes = dwAttr;
4856 /* get the file times */
4857 lpFileInformation->ftCreationTime =
4858 FILEUnixTimeToFileTime( stat_data.st_ctime,
4859 ST_CTIME_NSEC(&stat_data) );
4860 lpFileInformation->ftLastAccessTime =
4861 FILEUnixTimeToFileTime( stat_data.st_atime,
4862 ST_ATIME_NSEC(&stat_data) );
4863 lpFileInformation->ftLastWriteTime =
4864 FILEUnixTimeToFileTime( stat_data.st_mtime,
4865 ST_MTIME_NSEC(&stat_data) );
4867 lpFileInformation->dwVolumeSerialNumber = stat_data.st_dev;
4869 /* Get the file size. GetFileSize is not used because it gets the
4870 size of an already-open file */
4871 lpFileInformation->nFileSizeLow = (DWORD) stat_data.st_size;
4872 #if SIZEOF_OFF_T > 4
4873 lpFileInformation->nFileSizeHigh = (DWORD)(stat_data.st_size >> 32);
4875 lpFileInformation->nFileSizeHigh = 0;
4878 lpFileInformation->nNumberOfLinks = stat_data.st_nlink;
4879 lpFileInformation->nFileIndexHigh = 0;
4880 lpFileInformation->nFileIndexLow = stat_data.st_ino;
4885 if (NULL != pLocalDataLock)
4887 pLocalDataLock->ReleaseLock(pThread, FALSE);
4890 if (NULL != pFileObject)
4892 pFileObject->ReleaseReference(pThread);
4895 if (dwLastError) pThread->SetLastError(dwLastError);
4897 LOGEXIT("GetFileInformationByHandle returns BOOL %d\n", bRet);
4898 PERF_EXIT(GetFileInformationByHandle);