6443a5e7b9ee59cd9635294f445efbdcb6d5a8a8
[platform/upstream/coreclr.git] / src / pal / src / file / file.cpp
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.
4
5 /*++
6
7
8
9 Module Name:
10
11     file.cpp
12
13 Abstract:
14
15     Implementation of the file WIN API for the PAL
16
17
18
19 --*/
20
21 #include "pal/thread.hpp"
22 #include "pal/file.hpp"
23 #include "shmfilelockmgr.hpp"
24 #include "pal/malloc.hpp"
25 #include "pal/stackstring.hpp"
26
27 #include "pal/palinternal.h"
28 #include "pal/dbgmsg.h"
29 #include "pal/file.h"
30 #include "pal/filetime.h"
31 #include "pal/utils.h"
32
33 #include <time.h>
34 #include <stdio.h>
35 #include <sys/file.h>
36 #include <sys/types.h>
37 #include <sys/stat.h>
38 #include <sys/param.h>
39 #include <sys/mount.h>
40 #include <errno.h>
41 #include <limits.h>
42
43 using namespace CorUnix;
44
45 SET_DEFAULT_DEBUG_CHANNEL(FILE);
46
47 int MaxWCharToAcpLengthFactor = 3;
48
49 PAL_ERROR
50 InternalSetFilePointerForUnixFd(
51     int iUnixFd,
52     LONG lDistanceToMove,
53     PLONG lpDistanceToMoveHigh,
54     DWORD dwMoveMethod,
55     PLONG lpNewFilePointerLow
56     );
57
58 void
59 FileCleanupRoutine(
60     CPalThread *pThread,
61     IPalObject *pObjectToCleanup,
62     bool fShutdown,
63     bool fCleanupSharedState
64     );
65
66 CObjectType CorUnix::otFile(
67                 otiFile,
68                 FileCleanupRoutine,
69                 NULL,   // No initialization routine
70                 0,      // No immutable data
71                 sizeof(CFileProcessLocalData),
72                 0,      // No shared data
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
82                 );
83
84 CAllowedObjectTypes CorUnix::aotFile(otiFile);
85 static CSharedMemoryFileLockMgr _FileLockManager;
86 IFileLockManager *CorUnix::g_pFileLockManager = &_FileLockManager;
87
88 void
89 FileCleanupRoutine(
90     CPalThread *pThread,
91     IPalObject *pObjectToCleanup,
92     bool fShutdown,
93     bool fCleanupSharedState
94     )
95 {
96     PAL_ERROR palError;
97     CFileProcessLocalData *pLocalData = NULL;
98     IDataLock *pLocalDataLock = NULL;
99
100     palError = pObjectToCleanup->GetProcessLocalData(
101         pThread, 
102         ReadLock,
103         &pLocalDataLock,
104         reinterpret_cast<void**>(&pLocalData)
105         );
106
107     if (NO_ERROR != palError)
108     {
109         ASSERT("Unable to obtain data to cleanup file object");
110         return;
111     }
112
113     if (pLocalData->pLockController != NULL)
114     {
115         pLocalData->pLockController->ReleaseController();
116     }
117
118     if (!fShutdown && -1 != pLocalData->unix_fd)
119     {
120         close(pLocalData->unix_fd);
121     }
122
123     pLocalDataLock->ReleaseLock(pThread, FALSE);
124 }
125
126 typedef enum
127 {
128   PIID_STDIN_HANDLE, 
129   PIID_STDOUT_HANDLE,
130   PIID_STDERR_HANDLE
131 } PROCINFO_ID; 
132
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)
139
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;
146
147 /*++
148 Function : 
149     FILEGetProperNotFoundError
150     
151 Returns the proper error code, based on the
152 Windows behavior.
153
154     IN LPSTR lpPath - The path to check.
155     LPDWORD lpErrorCode - The error to set.
156 */
157 void FILEGetProperNotFoundError( LPCSTR lpPath, LPDWORD lpErrorCode )
158 {
159     struct stat stat_data;
160     LPSTR lpDupedPath = NULL;
161     LPSTR lpLastPathSeparator = NULL;
162
163     TRACE( "FILEGetProperNotFoundError( %s )\n", lpPath?lpPath:"(null)" );
164
165     if ( !lpErrorCode )
166     {
167         ASSERT( "lpErrorCode has to be valid\n" );
168         return;
169     }
170
171     if ( NULL == ( lpDupedPath = strdup(lpPath) ) )
172     {
173         ERROR( "strdup() failed!\n" );
174         *lpErrorCode = ERROR_NOT_ENOUGH_MEMORY;
175         return;
176     }
177
178     /* Determine whether it's a file not found or path not found. */
179     lpLastPathSeparator = strrchr( lpDupedPath, '/');
180     if ( lpLastPathSeparator != NULL )
181     {
182         *lpLastPathSeparator = '\0';
183         
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 ) )
190         {
191             TRACE( "ERROR_FILE_NOT_FOUND\n" );
192             *lpErrorCode = ERROR_FILE_NOT_FOUND;
193         }
194         else
195         {
196             TRACE( "ERROR_PATH_NOT_FOUND\n" );
197             *lpErrorCode = ERROR_PATH_NOT_FOUND;
198         }
199     }
200     else
201     {
202         TRACE( "ERROR_FILE_NOT_FOUND\n" );
203         *lpErrorCode = ERROR_FILE_NOT_FOUND;
204     }
205     
206     free(lpDupedPath);
207     lpDupedPath = NULL;
208     TRACE( "FILEGetProperNotFoundError returning TRUE\n" );
209     return;
210 }
211
212 /*++
213 Function : 
214     FILEGetLastErrorFromErrnoAndFilename
215     
216 Returns the proper error code for errno, or, if errno is ENOENT,
217 based on the Windows behavior for nonexistent filenames.
218
219     IN LPSTR lpPath - The path to check.
220 */
221 PAL_ERROR FILEGetLastErrorFromErrnoAndFilename(LPCSTR lpPath)
222 {
223     PAL_ERROR palError;
224     if (ENOENT == errno)
225     {
226         FILEGetProperNotFoundError(lpPath, &palError);
227     }
228     else
229     {
230         palError = FILEGetLastErrorFromErrno();
231     }
232     return palError;
233 }
234
235 BOOL 
236 CorUnix::RealPathHelper(LPCSTR lpUnixPath, PathCharString& lpBuffer)
237 {
238     StringHolder lpRealPath;
239     lpRealPath = realpath(lpUnixPath, NULL);
240     if (lpRealPath.IsNull())
241     {
242         return FALSE;
243     }
244
245     lpBuffer.Set(lpRealPath, strlen(lpRealPath));
246     return TRUE; 
247 }
248 /*++
249 InternalCanonicalizeRealPath
250     Wraps realpath() to hide platform differences. See the man page for
251     realpath(3) for details of how realpath() works.
252     
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().
256
257 --*/
258 PAL_ERROR
259 CorUnix::InternalCanonicalizeRealPath(LPCSTR lpUnixPath, PathCharString& lpBuffer)
260 {
261     PAL_ERROR palError = NO_ERROR;
262
263 #if !REALPATH_SUPPORTS_NONEXISTENT_FILES
264     StringHolder lpExistingPath;
265     LPSTR pchSeparator = NULL;
266     LPSTR lpFilename = NULL;
267     DWORD cchBuffer = 0;
268     DWORD cchFilename = 0;
269 #endif // !REALPATH_SUPPORTS_NONEXISTENT_FILES
270  
271     if (lpUnixPath == NULL) 
272     {
273         ERROR ("Invalid argument to InternalCanonicalizeRealPath\n");
274         palError = ERROR_INVALID_PARAMETER;
275         goto LExit;
276     }
277
278 #if REALPATH_SUPPORTS_NONEXISTENT_FILES
279     RealPathHelper(lpUnixPath, lpBuffer);
280 #else   // !REALPATH_SUPPORTS_NONEXISTENT_FILES
281
282     lpExistingPath = strdup(lpUnixPath);
283     if (lpExistingPath.IsNull())
284     {
285         ERROR ("strdup failed with error %d\n", errno);
286         palError = ERROR_NOT_ENOUGH_MEMORY;
287         goto LExit;
288     }
289
290     pchSeparator = strrchr(lpExistingPath, '/');
291     if (pchSeparator == NULL)
292     {
293         PathCharString pszCwdBuffer;
294
295         if (GetCurrentDirectoryA(pszCwdBuffer)== 0)
296         {
297             WARN("getcwd(NULL) failed with error %d\n", errno);
298             palError = DIRGetLastErrorFromErrno();
299             goto LExit;
300         }
301
302         if (! RealPathHelper(pszCwdBuffer, lpBuffer))
303         {
304             WARN("realpath() failed with error %d\n", errno);
305             palError = FILEGetLastErrorFromErrno();
306 #if defined(_AMD64_)
307             // If we are here, then we tried to invoke realpath
308             // against a directory.
309             //
310             // On Mac64, realpath implementation differs from Mac32
311             // by *not* supporting invalid filenames in the path (while
312             // Mac32 implementation does).
313             //
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)
319             {
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)
324                  {
325                      palError = ERROR_PATH_NOT_FOUND;
326                  }
327             }
328 #endif // defined(_AMD64_)
329             
330             goto LExit;
331         }
332         lpFilename = lpExistingPath;
333     }
334     else
335     {
336 #if defined(_AMD64_)
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:
341         //
342         // 1) Set the seperator to point to the NULL terminator of the specified
343         //    file/folder name.
344         //
345         // 2) Null terminate lpBuffer
346         //
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)
351         {
352             pchSeparator = lpExistingPath+strlen(lpExistingPath);
353
354             // Set the lpBuffer to NULL
355             lpBuffer.Clear();
356             lpFilename = NULL;
357             fSetFilename = false;
358         }
359         else
360 #endif // defined(_AMD64_)
361             *pchSeparator = '\0';
362             
363         if (!RealPathHelper(lpExistingPath, lpBuffer))
364         {
365             WARN("realpath() failed with error %d\n", errno);
366             palError = FILEGetLastErrorFromErrno();
367
368 #if defined(_AMD64_)
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.
372             //
373             // On Mac64, realpath implementation differs from Mac32
374             // by *not* supporting invalid filenames in the path (while
375             // Mac32 implementation does).
376             //
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)
382             {
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)
387                  {
388                      palError = ERROR_PATH_NOT_FOUND;
389                  }
390             }
391 #endif // defined(_AMD64_)
392
393             goto LExit;
394         }
395
396 #if defined(_AMD64_)
397         if (fSetFilename == true)
398 #endif // defined(_AMD64_)
399             lpFilename = pchSeparator + 1;
400     }
401
402 #if defined(_AMD64_)
403     if (lpFilename == NULL)
404         goto LExit;
405 #endif // _AMD64_
406
407     if (!lpBuffer.Append("/",1) || !lpBuffer.Append(lpFilename, strlen(lpFilename)))
408     {
409         ERROR ("Append failed!\n");
410         palError = ERROR_INSUFFICIENT_BUFFER;
411
412         // Doing a goto here since we want to exit now. This will work
413         // incase someone else adds another if clause below us.
414         goto LExit;
415     }
416
417 #endif // REALPATH_SUPPORTS_NONEXISTENT_FILES
418 LExit:
419
420     if ((palError == NO_ERROR) && lpBuffer.IsEmpty())
421     {
422         // convert all these into ERROR_PATH_NOT_FOUND
423         palError = ERROR_PATH_NOT_FOUND;
424     }
425
426     return palError;
427 }
428
429 PAL_ERROR
430 CorUnix::InternalCreateFile(
431     CPalThread *pThread,
432     LPCSTR lpFileName,
433     DWORD dwDesiredAccess,
434     DWORD dwShareMode,
435     LPSECURITY_ATTRIBUTES lpSecurityAttributes,
436     DWORD dwCreationDisposition,
437     DWORD dwFlagsAndAttributes,
438     HANDLE hTemplateFile,
439     HANDLE *phFile
440     )
441 {
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;
450
451     BOOL inheritable = FALSE;
452     PathCharString lpUnixPath;
453     int   filed = -1;
454     int   create_flags = (S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
455     int   open_flags = 0;
456     int   lock_mode = LOCK_SH;
457
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;
461
462     const char* szNonfilePrefix = "\\\\.\\";
463     PathCharString lpFullUnixPath;
464
465     /* for dwShareMode only three flags are accepted */
466     if ( dwShareMode & ~(FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE) )
467     {
468         ASSERT( "dwShareMode is invalid\n" );
469         palError = ERROR_INVALID_PARAMETER;
470         goto done;
471     }
472
473     if ( lpFileName == NULL )
474     {
475         ERROR("InternalCreateFile called with NULL filename\n");
476         palError = ERROR_PATH_NOT_FOUND;
477         goto done;
478     }
479
480     if ( strncmp(lpFileName, szNonfilePrefix, strlen(szNonfilePrefix)) == 0 )
481     {
482         ERROR("InternalCreateFile does not support paths beginning with %s\n", szNonfilePrefix);
483         palError = ERROR_INVALID_PARAMETER;
484         goto done;
485     }
486
487     if( !lpUnixPath.Set(lpFileName,strlen(lpFileName)))
488     {
489         ERROR("strdup() failed\n");
490         palError = ERROR_NOT_ENOUGH_MEMORY;
491         goto done;
492     }
493
494     FILEDosToUnixPathA( lpUnixPath );
495
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)
500     {
501         goto done;
502     }
503
504     lpUnixPath.Set(lpFullUnixPath);
505
506     switch( dwDesiredAccess )
507     {
508     case 0:
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 */
512         break;
513     case( GENERIC_READ ):
514         open_flags |= O_RDONLY;
515         break;
516     case( GENERIC_WRITE ):
517         open_flags |= O_WRONLY;
518         break;
519     case( GENERIC_READ | GENERIC_WRITE ):
520         open_flags |= O_RDWR;
521         break;
522     default:
523         ERROR("dwDesiredAccess value of %d is invalid\n", dwDesiredAccess);
524         palError = ERROR_INVALID_PARAMETER;
525         goto done;
526     }
527
528     TRACE("open flags are 0x%lx\n", open_flags);
529     
530     if ( lpSecurityAttributes )
531     {
532         if ( lpSecurityAttributes->nLength != sizeof( SECURITY_ATTRIBUTES ) ||
533              lpSecurityAttributes->lpSecurityDescriptor != NULL ||
534              !lpSecurityAttributes->bInheritHandle )
535         {
536             ASSERT("lpSecurityAttributes points to invalid values.\n");
537             palError = ERROR_INVALID_PARAMETER;
538             goto done;
539         }
540         inheritable = TRUE;
541     }
542
543     if ( (dwFlagsAndAttributes & PAL_LEGAL_FLAGS_ATTRIBS) !=
544           dwFlagsAndAttributes)
545     {
546         ASSERT("Bad dwFlagsAndAttributes\n");
547         palError = ERROR_INVALID_PARAMETER;
548         goto done;
549     } 
550     else if (dwFlagsAndAttributes & FILE_FLAG_BACKUP_SEMANTICS)
551     {
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;
557     } else {
558         struct stat st;
559
560         if (stat(lpUnixPath, &st) == 0 && (st.st_mode & S_IFDIR))
561         {
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;
566                 goto done;
567         }
568     }
569
570     if ( hTemplateFile )
571     {
572         ASSERT("hTemplateFile is not NULL, as it should be.\n");
573         palError = ERROR_INVALID_PARAMETER;
574         goto done;
575     }
576
577     //
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.
585     //
586
587     palError = g_pFileLockManager->GetLockControllerForFile(
588         pThread, 
589         lpUnixPath,
590         dwDesiredAccess,
591         dwShareMode,
592         &pLockController
593         );
594
595     if (NO_ERROR != palError)
596     {
597         goto done;
598     }
599
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.
603     */
604     switch( dwCreationDisposition )
605     {
606     case( CREATE_ALWAYS ):        
607         // check whether the file exists
608         if ( access( lpUnixPath, F_OK ) == 0 )
609         {
610             fFileExists = TRUE;
611         }
612         open_flags |= O_CREAT | O_TRUNC;
613         break;
614     case( CREATE_NEW ):
615         open_flags |= O_CREAT | O_EXCL;
616         break;
617     case( OPEN_EXISTING ):
618         /* don't need to do anything here */
619         break;
620     case( OPEN_ALWAYS ):
621         if ( access( lpUnixPath, F_OK ) == 0 )
622         {
623             fFileExists = TRUE;
624         }
625         open_flags |= O_CREAT;
626         break;
627     case( TRUNCATE_EXISTING ):
628         open_flags |= O_TRUNC;
629         break;
630     default:
631         ASSERT("dwCreationDisposition value of %d is not valid\n",
632               dwCreationDisposition);
633         palError = ERROR_INVALID_PARAMETER;
634         goto done;
635     }
636
637     if ( dwFlagsAndAttributes & FILE_FLAG_NO_BUFFERING )
638     {
639         TRACE("I/O will be unbuffered\n");
640 #ifdef O_DIRECT
641         open_flags |= O_DIRECT;
642 #endif
643     }
644     else
645     {
646         TRACE("I/O will be buffered\n");
647     }
648
649     filed = InternalOpen(lpUnixPath, open_flags, create_flags);
650     TRACE("Allocated file descriptor [%d]\n", filed);
651
652     if ( filed < 0 )
653     {
654         TRACE("open() failed; error is %s (%d)\n", strerror(errno), errno);
655         palError = FILEGetLastErrorFromErrnoAndFilename(lpUnixPath);
656         goto done;
657     }
658
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) &&
665         !fFileExists;
666
667
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;
674
675     if(flock(filed, lock_mode | LOCK_NB) != 0) 
676     {
677         TRACE("flock() failed; error is %s (%d)\n", strerror(errno), errno);
678         if (errno == EWOULDBLOCK) 
679         {
680             palError = ERROR_SHARING_VIOLATION;
681         }
682         else
683         {
684             palError = FILEGetLastErrorFromErrno();
685         }
686
687         goto done;
688     }
689
690 #ifndef O_DIRECT
691     if ( dwFlagsAndAttributes & FILE_FLAG_NO_BUFFERING )
692     {
693 #ifdef F_NOCACHE
694         if (-1 == fcntl(filed, F_NOCACHE, 1))
695         {
696             ASSERT("Can't set F_NOCACHE; fcntl() failed. errno is %d (%s)\n",
697                errno, strerror(errno));
698             palError = ERROR_INTERNAL_ERROR;
699             goto done;
700         }
701 #else
702 #error Insufficient support for uncached I/O on this platform
703 #endif
704     }
705 #endif
706     
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))
710     {
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;
714         goto done;
715     }
716
717     palError = g_pObjectManager->AllocateObject(
718         pThread,
719         &otFile,
720         &oaFile,
721         &pFileObject
722         );
723
724     if (NO_ERROR != palError)
725     {
726         goto done;
727     }
728
729     palError = pFileObject->GetProcessLocalData(
730         pThread,
731         WriteLock,
732         &pDataLock,
733         reinterpret_cast<void**>(&pLocalData)
734         );
735
736     if (NO_ERROR != palError)
737     {
738         goto done;
739     }
740
741     if (strcpy_s(pLocalData->unix_filename, sizeof(pLocalData->unix_filename), lpUnixPath) != SAFECRT_SUCCESS)
742     {
743         palError = ERROR_INSUFFICIENT_BUFFER;
744         TRACE("strcpy_s failed!\n");
745         goto done;
746     }
747
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);
753
754     //
755     // Transfer the lock controller reference from our local variable
756     // to the local file data
757     //
758
759     pLocalData->pLockController = pLockController;
760     pLockController = NULL;
761
762     //
763     // We've finished initializing our local data, so release that lock
764     //
765
766     pDataLock->ReleaseLock(pThread, TRUE);
767     pDataLock = NULL;
768
769     palError = g_pObjectManager->RegisterObject(
770         pThread,
771         pFileObject,
772         &aotFile, 
773         dwDesiredAccess,
774         phFile,
775         &pRegisteredFile
776         );
777
778     //
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
781     // it down the line.
782     //
783
784     pFileObject = NULL;
785
786 done:
787
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)
792     {
793         if (filed >= 0)
794         {
795             close(filed);
796         }
797         if (bFileCreated)
798         {
799             if (-1 == unlink(lpUnixPath))
800             {
801                 WARN("can't delete file; unlink() failed with errno %d (%s)\n",
802                      errno, strerror(errno));
803             }
804         }
805     }
806
807     if (NULL != pLockController)
808     {
809         pLockController->ReleaseController();
810     }
811
812     if (NULL != pDataLock)
813     {
814         pDataLock->ReleaseLock(pThread, TRUE);
815     }
816
817     if (NULL != pFileObject)
818     {
819         pFileObject->ReleaseReference(pThread);
820     }
821
822     if (NULL != pRegisteredFile)
823     {
824         pRegisteredFile->ReleaseReference(pThread);
825     }
826     
827     if (NO_ERROR == palError && fFileExists)
828     {
829         palError = ERROR_ALREADY_EXISTS;
830     }
831
832     return palError;
833 }
834
835 /*++
836 Function:
837   CreateFileA
838
839 Note:
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
843
844 See MSDN doc.
845 --*/
846 HANDLE
847 PALAPI
848 CreateFileA(
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
856         )
857 {
858     CPalThread *pThread;
859     PAL_ERROR palError = NO_ERROR;
860     HANDLE  hRet = INVALID_HANDLE_VALUE;
861
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);
868
869     pThread = InternalGetCurrentThread();
870
871     palError = InternalCreateFile(
872         pThread,
873         lpFileName,
874         dwDesiredAccess,
875         dwShareMode,
876         lpSecurityAttributes,
877         dwCreationDisposition,
878         dwFlagsAndAttributes,
879         hTemplateFile,
880         &hRet
881         );
882
883     //
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
888     //
889
890     pThread->SetLastError(palError);
891
892     LOGEXIT("CreateFileA returns HANDLE %p\n", hRet);
893     PERF_EXIT(CreateFileA);
894     return hRet;
895 }
896
897
898 /*++
899 Function:
900   CreateFileW
901
902 Note:
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
906
907 See MSDN doc.
908 --*/
909 HANDLE
910 PALAPI
911 CreateFileW(
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)
919 {
920     CPalThread *pThread;
921     PAL_ERROR palError = NO_ERROR;
922     PathCharString namePathString;
923     char * name;
924     int size;
925     int length = 0;
926     HANDLE  hRet = INVALID_HANDLE_VALUE;
927
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,
934           hTemplateFile);
935
936     pThread = InternalGetCurrentThread();
937
938     if (lpFileName != NULL)
939     {
940         length = (PAL_wcslen(lpFileName)+1) * MaxWCharToAcpLengthFactor;
941     }
942     
943     name = namePathString.OpenStringBuffer(length);
944     if (NULL == name)
945     {
946         palError = ERROR_NOT_ENOUGH_MEMORY;
947         goto done;
948     }
949     
950     size = WideCharToMultiByte( CP_ACP, 0, lpFileName, -1, name, length,
951                                 NULL, NULL );
952
953     if( size == 0 )
954     {
955         namePathString.CloseBuffer(0);    
956         DWORD dwLastError = GetLastError();
957         ASSERT("WideCharToMultiByte failure! error is %d\n", dwLastError);
958         palError = ERROR_INTERNAL_ERROR;
959         goto done;
960     }
961     
962     namePathString.CloseBuffer(size - 1);    
963
964     palError = InternalCreateFile(
965         pThread,
966         name,
967         dwDesiredAccess,
968         dwShareMode,
969         lpSecurityAttributes,
970         dwCreationDisposition,
971         dwFlagsAndAttributes,
972         hTemplateFile,
973         &hRet
974         );
975
976     //
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
981     //
982
983 done:
984         pThread->SetLastError(palError);
985     LOGEXIT( "CreateFileW returns HANDLE %p\n", hRet );
986     PERF_EXIT(CreateFileW);
987     return hRet;
988 }
989
990
991 /*++
992 Function:
993   CopyFileW
994
995 See MSDN doc.
996
997 Notes:
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.
1001 --*/
1002 BOOL
1003 PALAPI
1004 CopyFileW(
1005       IN LPCWSTR lpExistingFileName,
1006       IN LPCWSTR lpNewFileName,
1007       IN BOOL bFailIfExists)
1008 {
1009     CPalThread *pThread;
1010     PathCharString sourcePathString;
1011     PathCharString destPathString;
1012     char * source;
1013     char * dest;
1014     int src_size, dest_size, length = 0;
1015     BOOL bRet = FALSE;
1016
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);
1023
1024     pThread = InternalGetCurrentThread();
1025     if (lpExistingFileName != NULL)
1026     {
1027         length = (PAL_wcslen(lpExistingFileName)+1) * MaxWCharToAcpLengthFactor;
1028     }
1029     
1030     source = sourcePathString.OpenStringBuffer(length);
1031     if (NULL == source)
1032     {
1033         pThread->SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1034         goto done;
1035     }
1036
1037     src_size = WideCharToMultiByte( CP_ACP, 0, lpExistingFileName, -1, source, length,
1038                                 NULL, NULL );
1039     
1040     if( src_size == 0 )
1041     {
1042         sourcePathString.CloseBuffer(0);
1043         DWORD dwLastError = GetLastError();
1044         ASSERT("WideCharToMultiByte failure! error is %d\n", dwLastError);
1045         pThread->SetLastError(ERROR_INTERNAL_ERROR);
1046         goto done;
1047     }
1048     
1049     sourcePathString.CloseBuffer(src_size - 1);
1050     length = 0;
1051
1052     if (lpNewFileName != NULL)
1053     {
1054         length = (PAL_wcslen(lpNewFileName)+1) * MaxWCharToAcpLengthFactor;
1055     }
1056     
1057     dest = destPathString.OpenStringBuffer(length);
1058     if (NULL == dest)
1059     {
1060         pThread->SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1061         goto done;
1062     }
1063     dest_size = WideCharToMultiByte( CP_ACP, 0, lpNewFileName, -1, dest, length,
1064                                 NULL, NULL );
1065     
1066     if( dest_size == 0 )
1067     {
1068         destPathString.CloseBuffer(0);
1069         DWORD dwLastError = GetLastError();
1070         ASSERT("WideCharToMultiByte failure! error is %d\n", dwLastError);
1071         pThread->SetLastError(ERROR_INTERNAL_ERROR);
1072         goto done;
1073     }
1074
1075     destPathString.CloseBuffer(dest_size - 1);
1076     bRet = CopyFileA(source,dest,bFailIfExists);
1077
1078 done:
1079     LOGEXIT("CopyFileW returns BOOL %d\n", bRet);
1080     PERF_EXIT(CopyFileW);
1081     return bRet;
1082 }
1083
1084
1085 /*++
1086 Function:
1087   DeleteFileA
1088
1089 See MSDN doc.
1090 --*/
1091 BOOL
1092 PALAPI
1093 DeleteFileA(
1094         IN LPCSTR lpFileName)
1095 {
1096     PAL_ERROR palError = NO_ERROR;
1097     CPalThread *pThread;
1098     int     result;
1099     BOOL    bRet = FALSE;
1100     DWORD   dwLastError = 0;
1101     PathCharString lpunixFileName;
1102     PathCharString lpFullunixFileName;
1103
1104     PERF_ENTRY(DeleteFileA);
1105     ENTRY("DeleteFileA(lpFileName=%p (%s))\n", lpFileName?lpFileName:"NULL", lpFileName?lpFileName:"NULL");
1106
1107     pThread = InternalGetCurrentThread();
1108
1109     if( !lpunixFileName.Set(lpFileName, strlen(lpFileName)))
1110     {
1111         palError = ERROR_NOT_ENOUGH_MEMORY;
1112         goto done;
1113     }
1114     
1115     FILEDosToUnixPathA( lpunixFileName );
1116     
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)
1121     {
1122         if (!lpFullunixFileName.Set(lpunixFileName, strlen(lpunixFileName)))
1123         {
1124             palError = ERROR_NOT_ENOUGH_MEMORY;
1125             goto done;
1126         }
1127     }
1128
1129     result = unlink( lpFullunixFileName );
1130
1131     if (result < 0)
1132     {
1133         TRACE("unlink returns %d\n", result);
1134         dwLastError = FILEGetLastErrorFromErrnoAndFilename(lpFullunixFileName);
1135     }
1136     else
1137     {
1138         bRet = TRUE;
1139     }
1140
1141 done:
1142     if(dwLastError)
1143     {
1144         pThread->SetLastError( dwLastError );
1145     }
1146
1147     LOGEXIT("DeleteFileA returns BOOL %d\n", bRet);
1148     PERF_EXIT(DeleteFileA);
1149     return bRet;
1150 }
1151
1152 /*++
1153 Function:
1154   DeleteFileW
1155
1156 See MSDN doc.
1157 --*/
1158 BOOL
1159 PALAPI
1160 DeleteFileW(
1161         IN LPCWSTR lpFileName)
1162 {
1163     CPalThread *pThread;
1164     int  size;
1165     PathCharString namePS;
1166     char * name;
1167     int length = 0;
1168     BOOL bRet = FALSE;
1169
1170     PERF_ENTRY(DeleteFileW);
1171     ENTRY("DeleteFileW(lpFileName=%p (%S))\n",
1172       lpFileName?lpFileName:W16_NULLSTRING,
1173       lpFileName?lpFileName:W16_NULLSTRING);
1174
1175     pThread = InternalGetCurrentThread();
1176     
1177     if (lpFileName != NULL)
1178     {
1179         length = (PAL_wcslen(lpFileName)+1) * MaxWCharToAcpLengthFactor;
1180     }
1181     
1182     name = namePS.OpenStringBuffer(length);
1183     if (NULL == name)
1184     {
1185         pThread->SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1186         goto done;
1187     }
1188
1189     size = WideCharToMultiByte( CP_ACP, 0, lpFileName, -1, name, length,
1190                                 NULL, NULL );
1191     
1192     if( size == 0 )
1193     {
1194         namePS.CloseBuffer(0);
1195         DWORD dwLastError = GetLastError();
1196         ASSERT("WideCharToMultiByte failure! error is %d\n", dwLastError);
1197         pThread->SetLastError(ERROR_INTERNAL_ERROR);
1198         bRet = FALSE;
1199         goto done;
1200     }
1201
1202     namePS.CloseBuffer(size - 1);
1203     bRet = DeleteFileA( name );
1204
1205 done:
1206     LOGEXIT("DeleteFileW returns BOOL %d\n", bRet);
1207     PERF_EXIT(DeleteFileW);
1208     return bRet;
1209 }
1210
1211
1212 /*++
1213 Function:
1214   MoveFileA
1215
1216 See MSDN doc.
1217 --*/
1218 BOOL
1219 PALAPI
1220 MoveFileA(
1221      IN LPCSTR lpExistingFileName,
1222      IN LPCSTR lpNewFileName)
1223 {
1224     BOOL bRet;
1225
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");
1232
1233     bRet = MoveFileExA( lpExistingFileName,
1234             lpNewFileName,
1235             MOVEFILE_COPY_ALLOWED );
1236
1237     LOGEXIT("MoveFileA returns BOOL %d\n", bRet);
1238     PERF_EXIT(MoveFileA);
1239     return bRet;
1240 }
1241
1242
1243 /*++
1244 Function:
1245   MoveFileW
1246
1247 See MSDN doc.
1248 --*/
1249 BOOL
1250 PALAPI
1251 MoveFileW(
1252      IN LPCWSTR lpExistingFileName,
1253      IN LPCWSTR lpNewFileName)
1254 {
1255     BOOL bRet;
1256
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);
1263
1264     bRet = MoveFileExW( lpExistingFileName,
1265             lpNewFileName,
1266             MOVEFILE_COPY_ALLOWED );
1267
1268     LOGEXIT("MoveFileW returns BOOL %d\n", bRet);
1269     PERF_EXIT(MoveFileW);
1270     return bRet;
1271 }
1272
1273 /*++
1274 Function:
1275   MoveFileExA
1276
1277 See MSDN doc.
1278 --*/
1279 BOOL
1280 PALAPI
1281 MoveFileExA(
1282         IN LPCSTR lpExistingFileName,
1283         IN LPCSTR lpNewFileName,
1284         IN DWORD dwFlags)
1285 {
1286     CPalThread *pThread;
1287     int   result;
1288     PathCharString source;
1289     PathCharString dest;
1290     BOOL  bRet = TRUE;
1291     DWORD dwLastError = 0;
1292
1293     PERF_ENTRY(MoveFileExA);
1294     ENTRY("MoveFileExA(lpExistingFileName=%p (%S), lpNewFileName=%p (%S), "
1295           "dwFlags=%#x)\n",
1296           lpExistingFileName?lpExistingFileName:"NULL",
1297           lpExistingFileName?lpExistingFileName:"NULL",
1298           lpNewFileName?lpNewFileName:"NULL",
1299           lpNewFileName?lpNewFileName:"NULL", dwFlags);
1300
1301     pThread = InternalGetCurrentThread();
1302     /* only two flags are accepted */
1303     if ( dwFlags & ~(MOVEFILE_COPY_ALLOWED | MOVEFILE_REPLACE_EXISTING) )
1304     {
1305         ASSERT( "dwFlags is invalid\n" );
1306         dwLastError = ERROR_INVALID_PARAMETER;
1307         goto done;
1308     }
1309
1310     
1311     if( !source.Set(lpExistingFileName, strlen(lpExistingFileName)))
1312     {
1313         dwLastError = ERROR_NOT_ENOUGH_MEMORY;
1314         goto done;
1315     }
1316     
1317     FILEDosToUnixPathA( source );
1318
1319     if( !dest.Set(lpNewFileName, strlen(lpNewFileName)))
1320     {
1321         dwLastError = ERROR_NOT_ENOUGH_MEMORY;
1322         goto done;
1323     }
1324
1325     FILEDosToUnixPathA( dest );
1326
1327     if ( !(dwFlags & MOVEFILE_REPLACE_EXISTING) )
1328     {
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
1334         {
1335             // Let things proceed normally if source and
1336             // dest are the same.
1337             if ( access(dest, F_OK) == 0 )
1338             {
1339                 dwLastError = ERROR_ALREADY_EXISTS;
1340                 goto done;
1341             }
1342         }
1343     }
1344
1345     result = rename( source, dest );
1346     if ((result < 0) && (dwFlags & MOVEFILE_REPLACE_EXISTING) &&
1347         ((errno == ENOTDIR) || (errno == EEXIST)))
1348     {
1349         bRet = DeleteFileA( lpNewFileName );
1350         
1351         if ( bRet ) 
1352         {
1353             result = rename( source, dest );
1354         }
1355         else
1356         { 
1357             dwLastError = GetLastError();
1358         }
1359     } 
1360
1361     if ( result < 0 )
1362     {
1363         switch( errno )
1364         {
1365         case EXDEV: /* we tried to link across devices */
1366         
1367             if ( dwFlags & MOVEFILE_COPY_ALLOWED )
1368             {
1369                 BOOL bFailIfExists = !(dwFlags & MOVEFILE_REPLACE_EXISTING);
1370             
1371                 /* if CopyFile fails here, so should MoveFailEx */
1372                 bRet = CopyFileA( lpExistingFileName,
1373                           lpNewFileName,
1374                           bFailIfExists );
1375                 /* CopyFile should set the appropriate error */
1376                 if ( !bRet ) 
1377                 {
1378                     dwLastError = GetLastError();
1379                 }
1380                 else
1381                 {
1382                     if (!DeleteFileA(lpExistingFileName))
1383                     {
1384                         ERROR("Failed to delete the source file\n");
1385                         dwLastError = GetLastError();
1386                     
1387                         /* Delete the destination file if we're unable to delete 
1388                            the source file */
1389                         if (!DeleteFileA(lpNewFileName))
1390                         {
1391                             ERROR("Failed to delete the destination file\n");
1392                         }
1393                     }
1394                 }
1395             }
1396             else
1397             {
1398                 dwLastError = ERROR_ACCESS_DENIED;
1399             }
1400             break;
1401         case EINVAL: // tried to rename "." or ".."
1402             dwLastError = ERROR_SHARING_VIOLATION;
1403             break;
1404         case ENOENT:
1405             {
1406                 struct stat buf;
1407                 if (lstat(source, &buf) == -1)
1408                 {
1409                     FILEGetProperNotFoundError(source, &dwLastError);
1410                 }
1411                 else
1412                 {
1413                     dwLastError = ERROR_PATH_NOT_FOUND;
1414                 }
1415             }
1416             break;
1417         default:
1418             dwLastError = FILEGetLastErrorFromErrno();
1419             break;
1420         }
1421     }
1422
1423 done:
1424     if ( dwLastError )
1425     {
1426         pThread->SetLastError( dwLastError );
1427         bRet = FALSE;
1428     }
1429
1430     LOGEXIT( "MoveFileExA returns BOOL %d\n", bRet );
1431     PERF_EXIT(MoveFileExA);
1432     return bRet;
1433 }
1434
1435 /*++
1436 Function:
1437   MoveFileExW
1438
1439 See MSDN doc.
1440 --*/
1441 BOOL
1442 PALAPI
1443 MoveFileExW(
1444         IN LPCWSTR lpExistingFileName,
1445         IN LPCWSTR lpNewFileName,
1446         IN DWORD dwFlags)
1447 {
1448     CPalThread *pThread;
1449     PathCharString sourcePS;
1450     PathCharString destPS;
1451     char * source;
1452     char * dest;
1453     int length = 0;
1454     int     src_size,dest_size;
1455     BOOL        bRet = FALSE;
1456
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);
1463
1464     pThread = InternalGetCurrentThread();
1465     
1466     if (lpExistingFileName != NULL)
1467     {
1468         length = (PAL_wcslen(lpExistingFileName)+1) * MaxWCharToAcpLengthFactor;
1469     }
1470     
1471     source = sourcePS.OpenStringBuffer(length);
1472     if (NULL == source)
1473     {
1474         pThread->SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1475         goto done;
1476     }
1477     src_size = WideCharToMultiByte( CP_ACP, 0, lpExistingFileName, -1, source, length,
1478                                 NULL, NULL );
1479     if( src_size == 0 )
1480     {
1481         sourcePS.CloseBuffer(0);
1482         DWORD dwLastError = GetLastError();
1483         ASSERT("WideCharToMultiByte failure! error is %d\n", dwLastError);
1484         pThread->SetLastError(ERROR_INTERNAL_ERROR);
1485         goto done;
1486     }
1487
1488     sourcePS.CloseBuffer(src_size - 1);
1489     length = 0;
1490     if (lpNewFileName != NULL)
1491     {
1492         length = (PAL_wcslen(lpNewFileName)+1) * MaxWCharToAcpLengthFactor;
1493     }
1494     
1495     dest = destPS.OpenStringBuffer(length);
1496     if (NULL == dest)
1497     {
1498         pThread->SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1499         goto done;
1500     }
1501     dest_size = WideCharToMultiByte( CP_ACP, 0, lpNewFileName, -1, dest, length,
1502                                 NULL, NULL );
1503     
1504     if( dest_size == 0 )
1505     {
1506         destPS.CloseBuffer(0);
1507         DWORD dwLastError = GetLastError();
1508         ASSERT("WideCharToMultiByte failure! error is %d\n", dwLastError);
1509         pThread->SetLastError(ERROR_INTERNAL_ERROR);
1510         goto done;
1511     }
1512
1513     destPS.CloseBuffer(dest_size - 1);
1514     bRet = MoveFileExA(source,dest,dwFlags);
1515
1516 done:
1517     LOGEXIT("MoveFileExW returns BOOL %d\n", bRet);
1518     PERF_EXIT(MoveFileExW);
1519     return bRet;
1520 }
1521
1522 /*++
1523 Function:
1524   GetFileAttributesA
1525
1526 Note:
1527   Checking for directory and read-only file, according to Rotor spec.
1528
1529 Caveats:
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:
1532
1533 - fifo's, sockets, and symlinks will return -1, and GetLastError() will
1534   return ERROR_ACCESS_DENIED
1535
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.
1539
1540 - the following flags will never be returned:
1541
1542 FILE_ATTRIBUTE_SYSTEM
1543 FILE_ATTRIBUTE_ARCHIVE
1544 FILE_ATTRIBUTE_HIDDEN
1545
1546 --*/
1547 DWORD
1548 PALAPI
1549 GetFileAttributesA(
1550            IN LPCSTR lpFileName)
1551 {
1552     CPalThread *pThread;
1553     struct stat stat_data;
1554     DWORD dwAttr = 0;
1555     DWORD dwLastError = 0;
1556     PathCharString unixFileName;
1557
1558     PERF_ENTRY(GetFileAttributesA);
1559     ENTRY("GetFileAttributesA(lpFileName=%p (%s))\n", lpFileName?lpFileName:"NULL", lpFileName?lpFileName:"NULL");
1560
1561     pThread = InternalGetCurrentThread();
1562     if (lpFileName == NULL)
1563     {
1564         dwLastError = ERROR_PATH_NOT_FOUND;
1565         goto done;
1566     }
1567
1568     
1569     if( !unixFileName.Set(lpFileName, strlen(lpFileName)))
1570     {
1571         dwLastError = ERROR_NOT_ENOUGH_MEMORY;
1572         goto done;
1573     }
1574     
1575     FILEDosToUnixPathA( unixFileName );
1576
1577     if ( stat(unixFileName, &stat_data) != 0 )
1578     {
1579         dwLastError = FILEGetLastErrorFromErrnoAndFilename(unixFileName);
1580         goto done;
1581     }
1582
1583     if ( (stat_data.st_mode & S_IFMT) == S_IFDIR )
1584     {
1585         dwAttr |= FILE_ATTRIBUTE_DIRECTORY;
1586     }
1587     else if ( (stat_data.st_mode & S_IFMT) != S_IFREG )
1588     {
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;
1592         goto done;
1593     }
1594
1595     if ( UTIL_IsReadOnlyBitsSet( &stat_data ) )
1596     {
1597         dwAttr |= FILE_ATTRIBUTE_READONLY;
1598     }
1599
1600     /* finally, if nothing is set... */
1601     if ( dwAttr == 0 )
1602     {
1603         dwAttr = FILE_ATTRIBUTE_NORMAL;
1604     }
1605
1606 done:
1607     if (dwLastError)
1608     {
1609         pThread->SetLastError(dwLastError);
1610         dwAttr = INVALID_FILE_ATTRIBUTES;
1611     }
1612
1613     LOGEXIT("GetFileAttributesA returns DWORD %#x\n", dwAttr);
1614     PERF_EXIT(GetFileAttributesA);
1615     return dwAttr;
1616 }
1617
1618
1619
1620
1621 /*++
1622 Function:
1623   GetFileAttributesW
1624
1625 Note:
1626   Checking for directory and read-only file
1627
1628 See MSDN doc.
1629 --*/
1630 DWORD
1631 PALAPI
1632 GetFileAttributesW(
1633            IN LPCWSTR lpFileName)
1634 {
1635     CPalThread *pThread;
1636     int   size;
1637     PathCharString filenamePS;
1638     int length = 0;
1639     char * filename;
1640     DWORD dwRet = (DWORD) -1;
1641
1642     PERF_ENTRY(GetFileAttributesW);
1643     ENTRY("GetFileAttributesW(lpFileName=%p (%S))\n",
1644           lpFileName?lpFileName:W16_NULLSTRING,
1645           lpFileName?lpFileName:W16_NULLSTRING);
1646
1647     pThread = InternalGetCurrentThread();
1648     if (lpFileName == NULL) 
1649     {
1650         pThread->SetLastError(ERROR_PATH_NOT_FOUND);
1651         goto done;
1652     }
1653     
1654     length = (PAL_wcslen(lpFileName)+1) * MaxWCharToAcpLengthFactor;
1655     filename = filenamePS.OpenStringBuffer(length);
1656     if (NULL == filename)
1657     {
1658         pThread->SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1659         goto done;
1660     }
1661     size = WideCharToMultiByte( CP_ACP, 0, lpFileName, -1, filename, length,
1662                                 NULL, NULL );
1663     
1664     if( size == 0 )
1665     {
1666         filenamePS.CloseBuffer(0);
1667         DWORD dwLastError = GetLastError();
1668         ASSERT("WideCharToMultiByte failure! error is %d\n", dwLastError);
1669         pThread->SetLastError(ERROR_INTERNAL_ERROR);
1670     }
1671     else
1672     { 
1673         filenamePS.CloseBuffer(size - 1);
1674         dwRet = GetFileAttributesA( filename );
1675     }
1676
1677 done:
1678     LOGEXIT("GetFileAttributesW returns DWORD %#x\n", dwRet);
1679     PERF_EXIT(GetFileAttributesW);
1680     return dwRet;
1681 }
1682
1683
1684 /*++
1685 Function:
1686   GetFileAttributesExW
1687
1688 See MSDN doc, and notes for GetFileAttributesW.
1689 --*/
1690 BOOL
1691 PALAPI
1692 GetFileAttributesExW(
1693              IN LPCWSTR lpFileName,
1694              IN GET_FILEEX_INFO_LEVELS fInfoLevelId,
1695              OUT LPVOID lpFileInformation)
1696 {
1697     CPalThread *pThread;
1698     BOOL bRet = FALSE;
1699     DWORD dwLastError = 0;
1700     LPWIN32_FILE_ATTRIBUTE_DATA attr_data;
1701
1702     struct stat stat_data;
1703
1704     char * name;
1705     PathCharString namePS;
1706     int length = 0;
1707     int  size;
1708
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);
1713
1714     pThread = InternalGetCurrentThread();
1715     if ( fInfoLevelId != GetFileExInfoStandard )
1716     {
1717         ASSERT("Unrecognized value for fInfoLevelId=%d\n", fInfoLevelId);
1718         dwLastError = ERROR_INVALID_PARAMETER;
1719         goto done;
1720     }
1721
1722     if ( !lpFileInformation )
1723     {
1724         ASSERT("lpFileInformation is NULL\n");
1725         dwLastError = ERROR_INVALID_PARAMETER;
1726         goto done;
1727     }
1728
1729     if (lpFileName == NULL) 
1730     {
1731         dwLastError = ERROR_PATH_NOT_FOUND;
1732         goto done;
1733     }
1734     
1735     length = (PAL_wcslen(lpFileName)+1) * MaxWCharToAcpLengthFactor;
1736     name = namePS.OpenStringBuffer(length);
1737     if (NULL == name)
1738     {
1739         dwLastError = ERROR_NOT_ENOUGH_MEMORY;
1740         goto done;
1741     }
1742     size = WideCharToMultiByte( CP_ACP, 0, lpFileName, -1, name, length,
1743                                 NULL, NULL );
1744     
1745     if( size == 0 )
1746     {
1747         namePS.CloseBuffer(0);
1748         dwLastError = GetLastError();
1749         ASSERT("WideCharToMultiByte failure! error is %d\n", dwLastError);
1750         dwLastError = ERROR_INTERNAL_ERROR;
1751         goto done;
1752     }
1753
1754     namePS.CloseBuffer(size - 1);
1755     attr_data = (LPWIN32_FILE_ATTRIBUTE_DATA)lpFileInformation;
1756
1757     attr_data->dwFileAttributes = GetFileAttributesW(lpFileName);
1758     /* assume that GetFileAttributes will call SetLastError appropriately */
1759     if ( attr_data->dwFileAttributes == (DWORD)-1 )
1760     {
1761         goto done;
1762     }
1763
1764     FILEDosToUnixPathA(name);
1765     /* do the stat */
1766     if ( stat(name, &stat_data) != 0 )
1767     {
1768         ERROR("stat failed on %S\n", lpFileName);
1769         dwLastError = FILEGetLastErrorFromErrnoAndFilename(name);
1770         goto done;
1771     }
1772
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) );
1783
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);
1789 #else
1790     attr_data->nFileSizeHigh = 0;
1791 #endif
1792
1793     bRet = TRUE;
1794
1795 done:
1796     if (dwLastError) pThread->SetLastError(dwLastError);
1797
1798     LOGEXIT("GetFileAttributesExW returns BOOL %d\n", bRet);
1799     PERF_EXIT(GetFileAttributesExW);
1800     return bRet;
1801 }
1802
1803 /*++
1804 Function:
1805   SetFileAttributesW
1806
1807 Notes:
1808   Used for setting read-only attribute on file only.
1809
1810 --*/
1811 BOOL
1812 PALAPI
1813 SetFileAttributesW(
1814            IN LPCWSTR lpFileName,
1815            IN DWORD dwFileAttributes)
1816 {
1817     CPalThread *pThread;
1818     char * name;
1819     PathCharString namePS;
1820     int length = 0;
1821     int  size;
1822
1823     DWORD dwLastError = 0;
1824     BOOL  bRet = FALSE;
1825
1826     PERF_ENTRY(SetFileAttributesW);
1827     ENTRY("SetFileAttributesW(lpFileName=%p (%S), dwFileAttributes=%#x)\n",
1828         lpFileName?lpFileName:W16_NULLSTRING,
1829         lpFileName?lpFileName:W16_NULLSTRING, dwFileAttributes);
1830     
1831     pThread = InternalGetCurrentThread();
1832     if (lpFileName == NULL) 
1833     {
1834         dwLastError = ERROR_PATH_NOT_FOUND;
1835         goto done;
1836     }
1837     
1838     length = (PAL_wcslen(lpFileName)+1) * MaxWCharToAcpLengthFactor;
1839     name = namePS.OpenStringBuffer(length);
1840     if (NULL == name)
1841     {
1842         dwLastError = ERROR_NOT_ENOUGH_MEMORY;
1843         goto done;
1844     }
1845     size = WideCharToMultiByte( CP_ACP, 0, lpFileName, -1, name, length,
1846                                 NULL, NULL );
1847     
1848     if( size == 0 )
1849     {
1850         namePS.CloseBuffer(0);
1851         dwLastError = GetLastError();
1852         ASSERT("WideCharToMultiByte failure! error is %d\n", dwLastError);
1853         dwLastError = ERROR_INVALID_PARAMETER;
1854         goto done;
1855     }
1856     namePS.CloseBuffer(size - 1);
1857     bRet = SetFileAttributesA(name,dwFileAttributes);
1858
1859 done:
1860     if (dwLastError) pThread->SetLastError(dwLastError);
1861
1862     LOGEXIT("SetFileAttributes returns BOOL %d\n", bRet);
1863     PERF_EXIT(SetFileAttributesW);
1864     return bRet;
1865 }
1866
1867 PAL_ERROR
1868 CorUnix::InternalWriteFile(
1869     CPalThread *pThread,
1870     HANDLE hFile,
1871     LPCVOID lpBuffer,
1872     DWORD nNumberOfBytesToWrite,
1873     LPDWORD lpNumberOfBytesWritten,
1874     LPOVERLAPPED lpOverlapped
1875     )
1876 {
1877     PAL_ERROR palError = 0;
1878     IPalObject *pFileObject = NULL;
1879     CFileProcessLocalData *pLocalData = NULL;
1880     IDataLock *pLocalDataLock = NULL;
1881     IFileTransactionLock *pTransactionLock = NULL;
1882     int ifd;
1883
1884     LONG writeOffsetStartLow = 0, writeOffsetStartHigh = 0;
1885     int res;
1886
1887     if (NULL != lpNumberOfBytesWritten)
1888     {
1889         //
1890         // This must be set to 0 before any other error checking takes
1891         // place, per MSDN
1892         //
1893
1894         *lpNumberOfBytesWritten = 0;
1895     }
1896     else
1897     {
1898         ASSERT( "lpNumberOfBytesWritten is NULL\n" );
1899         palError = ERROR_INVALID_PARAMETER;
1900         goto done;
1901     }
1902
1903     // Win32 WriteFile disallows writing to STD_INPUT_HANDLE
1904     if (hFile == INVALID_HANDLE_VALUE || hFile == pStdIn)
1905     {
1906         palError = ERROR_INVALID_HANDLE;
1907         goto done;
1908     }
1909     else if ( lpOverlapped )
1910     {
1911         ASSERT( "lpOverlapped is not NULL, as it should be.\n" );
1912         palError = ERROR_INVALID_PARAMETER;
1913         goto done;
1914     }
1915
1916     palError = g_pObjectManager->ReferenceObjectByHandle(
1917         pThread,
1918         hFile,
1919         &aotFile,
1920         GENERIC_WRITE,
1921         &pFileObject
1922         );
1923
1924     if (NO_ERROR != palError)
1925     {
1926         goto done;
1927     }
1928     
1929     palError = pFileObject->GetProcessLocalData(
1930         pThread,
1931         ReadLock, 
1932         &pLocalDataLock,
1933         reinterpret_cast<void**>(&pLocalData)
1934         );
1935
1936     if (NO_ERROR != palError)
1937     {
1938         goto done;
1939     }
1940
1941     if (pLocalData->open_flags_deviceaccessonly == TRUE)
1942     {
1943         ERROR("File open for device access only\n");
1944         palError = ERROR_ACCESS_DENIED;
1945         goto done;
1946     }
1947
1948     ifd = pLocalData->unix_fd;
1949
1950     //
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.)
1953     //
1954     
1955     if (NULL != pLocalData->pLockController)
1956     {
1957         /* Get the current file position to calculate the region to lock */
1958         palError = InternalSetFilePointerForUnixFd(
1959             ifd,
1960             0,
1961             &writeOffsetStartHigh,
1962             FILE_CURRENT,
1963             &writeOffsetStartLow
1964             );
1965
1966         if (NO_ERROR != palError)
1967         {
1968             ASSERT("Failed to get the current file position\n");
1969             palError = ERROR_INTERNAL_ERROR;
1970             goto done;
1971         }
1972
1973         palError = pLocalData->pLockController->GetTransactionLock(
1974             pThread,
1975             IFileLockController::WriteLock,
1976             writeOffsetStartLow,
1977             writeOffsetStartHigh,
1978             nNumberOfBytesToWrite,
1979             0,
1980             &pTransactionLock
1981             );
1982
1983         if (NO_ERROR != palError)
1984         {
1985             ERROR("Unable to obtain write transaction lock");
1986             goto done;
1987         }
1988     }
1989
1990     //
1991     // Release the data lock before performing the (possibly blocking)
1992     // write call
1993     //
1994
1995     pLocalDataLock->ReleaseLock(pThread, FALSE);
1996     pLocalDataLock = NULL;
1997     pLocalData = NULL;
1998
1999 #if WRITE_0_BYTES_HANGS_TTY
2000     if( nNumberOfBytesToWrite == 0 && isatty(ifd) )
2001     {
2002         res = 0;
2003         *lpNumberOfBytesWritten = 0;
2004         goto done;
2005     }
2006 #endif
2007
2008     res = write( ifd, lpBuffer, nNumberOfBytesToWrite );  
2009     TRACE("write() returns %d\n", res);
2010
2011     if ( res >= 0 )
2012     {
2013         *lpNumberOfBytesWritten = res;
2014     }
2015     else
2016     {
2017         palError = FILEGetLastErrorFromErrno();
2018     }
2019     
2020 done:
2021     
2022     if (NULL != pTransactionLock)
2023     {
2024         pTransactionLock->ReleaseLock();
2025     }
2026
2027     if (NULL != pLocalDataLock)
2028     {
2029         pLocalDataLock->ReleaseLock(pThread, FALSE);
2030     }
2031
2032     if (NULL != pFileObject)
2033     {
2034         pFileObject->ReleaseReference(pThread);
2035     }
2036
2037     return palError;
2038 }
2039
2040
2041 /*++
2042 Function:
2043   WriteFileW
2044
2045 Note:
2046   lpOverlapped always NULL.
2047
2048 See MSDN doc.
2049 --*/
2050 BOOL
2051 PALAPI
2052 WriteFile(
2053       IN HANDLE hFile,
2054       IN LPCVOID lpBuffer,
2055       IN DWORD nNumberOfBytesToWrite,
2056       OUT LPDWORD lpNumberOfBytesWritten,
2057       IN LPOVERLAPPED lpOverlapped)
2058 {
2059     PAL_ERROR palError;
2060     CPalThread *pThread;
2061     
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);
2066
2067     pThread = InternalGetCurrentThread();
2068
2069     palError = InternalWriteFile(
2070         pThread,
2071         hFile,
2072         lpBuffer,
2073         nNumberOfBytesToWrite,
2074         lpNumberOfBytesWritten,
2075         lpOverlapped
2076         );
2077
2078     if (NO_ERROR != palError)
2079     {
2080         pThread->SetLastError(palError);
2081     }
2082
2083     LOGEXIT("WriteFile returns BOOL %d\n", NO_ERROR == palError);
2084     PERF_EXIT(WriteFile);
2085     return NO_ERROR == palError;
2086 }
2087
2088 PAL_ERROR
2089 CorUnix::InternalReadFile(
2090     CPalThread *pThread,
2091     HANDLE hFile,
2092     LPVOID lpBuffer,
2093     DWORD nNumberOfBytesToRead,
2094     LPDWORD lpNumberOfBytesRead,
2095     LPOVERLAPPED lpOverlapped
2096     )
2097 {
2098     PAL_ERROR palError = 0;
2099     IPalObject *pFileObject = NULL;
2100     CFileProcessLocalData *pLocalData = NULL;
2101     IDataLock *pLocalDataLock = NULL;
2102     IFileTransactionLock *pTransactionLock = NULL;
2103     int ifd;
2104     
2105     LONG readOffsetStartLow = 0, readOffsetStartHigh = 0;
2106     int res;
2107
2108     if (NULL != lpNumberOfBytesRead)
2109     {
2110         //
2111         // This must be set to 0 before any other error checking takes
2112         // place, per MSDN
2113         //
2114
2115         *lpNumberOfBytesRead = 0;        
2116     }
2117     else
2118     {
2119         ERROR( "lpNumberOfBytesRead is NULL\n" );
2120         palError = ERROR_INVALID_PARAMETER;
2121         goto done;
2122     }
2123
2124     if (INVALID_HANDLE_VALUE == hFile)
2125     {
2126         ERROR( "Invalid file handle\n" );
2127         palError = ERROR_INVALID_HANDLE;
2128         goto done;
2129     }
2130     else if (NULL != lpOverlapped)
2131     {
2132         ASSERT( "lpOverlapped is not NULL, as it should be.\n" );
2133         palError = ERROR_INVALID_PARAMETER;
2134         goto done;
2135     }
2136     else if (NULL == lpBuffer)
2137     {
2138         ERROR( "Invalid parameter. (lpBuffer:%p)\n", lpBuffer);
2139         palError = ERROR_NOACCESS;
2140         goto done;
2141     }
2142
2143     palError = g_pObjectManager->ReferenceObjectByHandle(
2144         pThread,
2145         hFile,
2146         &aotFile,
2147         GENERIC_READ,
2148         &pFileObject
2149         );
2150
2151     if (NO_ERROR != palError)
2152     {
2153         goto done;
2154     }
2155
2156     palError = pFileObject->GetProcessLocalData(
2157         pThread,
2158         ReadLock, 
2159         &pLocalDataLock,
2160         reinterpret_cast<void**>(&pLocalData)
2161         );
2162
2163     if (NO_ERROR != palError)
2164     {
2165         goto done;
2166     }
2167
2168     if (pLocalData->open_flags_deviceaccessonly == TRUE)
2169     {
2170         ERROR("File open for device access only\n");
2171         palError = ERROR_ACCESS_DENIED;
2172         goto done;
2173     }
2174
2175     ifd = pLocalData->unix_fd;
2176
2177     //
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.)
2180     //
2181     
2182     if (NULL != pLocalData->pLockController)
2183     {
2184         /* Get the current file position to calculate the region to lock */
2185         palError = InternalSetFilePointerForUnixFd(
2186             ifd,
2187             0,
2188             &readOffsetStartHigh,
2189             FILE_CURRENT,
2190             &readOffsetStartLow
2191             );
2192
2193         if (NO_ERROR != palError)
2194         {
2195             ASSERT("Failed to get the current file position\n");
2196             palError = ERROR_INTERNAL_ERROR;
2197             goto done;
2198         }
2199
2200         palError = pLocalData->pLockController->GetTransactionLock(
2201             pThread,
2202             IFileLockController::ReadLock,
2203             readOffsetStartLow,
2204             readOffsetStartHigh,
2205             nNumberOfBytesToRead,
2206             0,
2207             &pTransactionLock
2208             );
2209
2210         if (NO_ERROR != palError)
2211         {
2212             ERROR("Unable to obtain read transaction lock");
2213             goto done;
2214         }
2215     }
2216
2217     //
2218     // Release the data lock before performing the (possibly blocking)
2219     // read call
2220     //
2221
2222     pLocalDataLock->ReleaseLock(pThread, FALSE);
2223     pLocalDataLock = NULL;
2224     pLocalData = NULL;
2225
2226 Read:
2227     TRACE("Reading from file descriptor %d\n", ifd);
2228     res = read(ifd, lpBuffer, nNumberOfBytesToRead);
2229     TRACE("read() returns %d\n", res);
2230
2231     if (res >= 0)
2232     {
2233         *lpNumberOfBytesRead = res;
2234     }
2235     else if (errno == EINTR)
2236     {
2237         // Try to read again.
2238         goto Read;
2239     }
2240     else
2241     {
2242         palError = FILEGetLastErrorFromErrno();
2243     }
2244     
2245 done:
2246
2247     if (NULL != pTransactionLock)
2248     {
2249         pTransactionLock->ReleaseLock();
2250     }
2251
2252     if (NULL != pLocalDataLock)
2253     {
2254         pLocalDataLock->ReleaseLock(pThread, FALSE);
2255     }
2256
2257     if (NULL != pFileObject)
2258     {
2259         pFileObject->ReleaseReference(pThread);
2260     }
2261
2262     return palError;
2263 }
2264
2265 /*++
2266 Function:
2267   ReadFile
2268
2269 Note:
2270   lpOverlapped always NULL.
2271
2272 See MSDN doc.
2273 --*/
2274 BOOL
2275 PALAPI
2276 ReadFile(
2277      IN HANDLE hFile,
2278      OUT LPVOID lpBuffer,
2279      IN DWORD nNumberOfBytesToRead,
2280      OUT LPDWORD lpNumberOfBytesRead,
2281      IN LPOVERLAPPED lpOverlapped)
2282 {
2283     PAL_ERROR palError;
2284     CPalThread *pThread;
2285     
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);
2291
2292     pThread = InternalGetCurrentThread();
2293
2294     palError = InternalReadFile(
2295         pThread,
2296         hFile,
2297         lpBuffer,
2298         nNumberOfBytesToRead,
2299         lpNumberOfBytesRead,
2300         lpOverlapped
2301         );
2302
2303     if (NO_ERROR != palError)
2304     {
2305         pThread->SetLastError(palError);
2306     }
2307
2308     LOGEXIT("ReadFile returns BOOL %d\n", NO_ERROR == palError);
2309     PERF_EXIT(ReadFile);
2310     return NO_ERROR == palError;
2311 }
2312
2313
2314 /*++
2315 Function:
2316   GetStdHandle
2317
2318 See MSDN doc.
2319 --*/
2320 HANDLE
2321 PALAPI
2322 GetStdHandle(
2323          IN DWORD nStdHandle)
2324 {
2325     CPalThread *pThread;
2326     HANDLE hRet = INVALID_HANDLE_VALUE;
2327
2328     PERF_ENTRY(GetStdHandle);
2329     ENTRY("GetStdHandle(nStdHandle=%#x)\n", nStdHandle);
2330
2331     pThread = InternalGetCurrentThread();
2332     switch( nStdHandle )
2333     {
2334     case STD_INPUT_HANDLE:
2335         hRet = pStdIn;
2336         break;
2337     case STD_OUTPUT_HANDLE:
2338         hRet = pStdOut;
2339         break;
2340     case STD_ERROR_HANDLE:
2341         hRet = pStdErr; 
2342         break;
2343     default:
2344         ERROR("nStdHandle is invalid\n");
2345         pThread->SetLastError(ERROR_INVALID_PARAMETER);
2346         break;
2347     }
2348
2349     LOGEXIT("GetStdHandle returns HANDLE %p\n", hRet);
2350     PERF_EXIT(GetStdHandle);
2351     return hRet;
2352 }
2353
2354 PAL_ERROR
2355 CorUnix::InternalSetEndOfFile(
2356     CPalThread *pThread,
2357     HANDLE hFile
2358     )
2359 {
2360     PAL_ERROR palError = 0;
2361     IPalObject *pFileObject = NULL;
2362     CFileProcessLocalData *pLocalData = NULL;
2363     IDataLock *pLocalDataLock = NULL;
2364
2365     off_t curr = 0;
2366
2367     if (INVALID_HANDLE_VALUE == hFile)
2368     {
2369         ERROR( "Invalid file handle\n" );
2370         palError = ERROR_INVALID_HANDLE;
2371         goto InternalSetEndOfFileExit;
2372     }
2373
2374     palError = g_pObjectManager->ReferenceObjectByHandle(
2375         pThread,
2376         hFile,
2377         &aotFile,
2378         GENERIC_WRITE,
2379         &pFileObject
2380         );
2381
2382     if (NO_ERROR != palError)
2383     {
2384         goto InternalSetEndOfFileExit;
2385     }
2386
2387     palError = pFileObject->GetProcessLocalData(
2388         pThread,
2389         ReadLock, 
2390         &pLocalDataLock,
2391         reinterpret_cast<void**>(&pLocalData)
2392         );
2393
2394     if (NO_ERROR != palError)
2395     {
2396         goto InternalSetEndOfFileExit;
2397     }
2398
2399     if (pLocalData->open_flags_deviceaccessonly == TRUE)
2400     {
2401         ERROR("File open for device access only\n");
2402         palError = ERROR_ACCESS_DENIED;
2403         goto InternalSetEndOfFileExit;
2404     }
2405     
2406     curr = lseek(pLocalData->unix_fd, 0, SEEK_CUR);
2407
2408     TRACE("current file pointer offset is %u\n", curr);
2409     if ( curr < 0 )
2410     {
2411         ERROR("lseek returned %ld\n", curr);
2412         palError = FILEGetLastErrorFromErrno();
2413         goto InternalSetEndOfFileExit;
2414     }
2415
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)
2423     {
2424         ERROR("Skipping ftruncate because the offset is too large\n");
2425         palError = ERROR_INVALID_PARAMETER;
2426         goto InternalSetEndOfFileExit;
2427     }
2428 #endif  // !HAVE_FTRUNCATE_LARGE_LENGTH_SUPPORT
2429 #endif  // SIZEOF_OFF_T
2430
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.
2435     // 
2436     struct statfs sFileSystemStats;
2437     off_t cbFreeSpace;
2438     if (fstatfs(pLocalData->unix_fd, &sFileSystemStats) != 0)
2439     {
2440         ERROR("fstatfs failed\n");
2441         palError = FILEGetLastErrorFromErrno();
2442         goto InternalSetEndOfFileExit;
2443     } 
2444
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;
2447
2448     if (curr > cbFreeSpace)
2449     {
2450         ERROR("Not enough disk space for ftruncate\n");
2451         palError = ERROR_DISK_FULL;
2452         goto InternalSetEndOfFileExit;
2453     }
2454 #endif // HAS_FTRUNCATE_LENGTH_ISSUE
2455
2456     if ( ftruncate(pLocalData->unix_fd, curr) != 0 )
2457     {
2458         ERROR("ftruncate failed\n");
2459         if ( errno == EACCES )
2460         {
2461             ERROR("file may not be writable\n");
2462         }
2463         palError = FILEGetLastErrorFromErrno();
2464         goto InternalSetEndOfFileExit;
2465     }
2466
2467
2468 InternalSetEndOfFileExit:
2469
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;
2478
2479     if (NULL != pLocalDataLock)
2480     {
2481         pLocalDataLock->ReleaseLock(pThread, FALSE);
2482     }
2483
2484     if (NULL != pFileObject)
2485     {
2486         pFileObject->ReleaseReference(pThread);
2487     }
2488
2489     return palError;
2490 }
2491
2492
2493
2494 /*++
2495 Function:
2496   SetEndOfFile
2497
2498 See MSDN doc.
2499 --*/
2500 BOOL
2501 PALAPI
2502 SetEndOfFile(
2503          IN HANDLE hFile)
2504 {
2505     PAL_ERROR palError = NO_ERROR;
2506     CPalThread *pThread;;
2507
2508     PERF_ENTRY(SetEndOfFile);
2509     ENTRY("SetEndOfFile(hFile=%p)\n", hFile);
2510
2511     pThread = InternalGetCurrentThread();
2512
2513     palError = InternalSetEndOfFile(
2514         pThread,
2515         hFile
2516         );
2517
2518     if (NO_ERROR != palError)
2519     {
2520         pThread->SetLastError(palError);
2521     }
2522
2523     LOGEXIT("SetEndOfFile returns BOOL %d\n", NO_ERROR == palError);
2524     PERF_EXIT(SetEndOfFile);
2525     return NO_ERROR == palError;
2526 }
2527
2528 //
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.
2536 //
2537
2538 PAL_ERROR
2539 InternalSetFilePointerForUnixFd(
2540     int iUnixFd,
2541     LONG lDistanceToMove,
2542     PLONG lpDistanceToMoveHigh,
2543     DWORD dwMoveMethod,
2544     PLONG lpNewFilePointerLow
2545     )
2546 {
2547     PAL_ERROR palError = NO_ERROR;
2548     int     seek_whence = 0;
2549     __int64 seek_offset = 0LL;
2550     __int64 seek_res = 0LL;
2551     off_t old_offset;
2552
2553     switch( dwMoveMethod )
2554     {
2555     case FILE_BEGIN:
2556         seek_whence = SEEK_SET; 
2557         break;
2558     case FILE_CURRENT:
2559         seek_whence = SEEK_CUR; 
2560         break;
2561     case FILE_END:
2562         seek_whence = SEEK_END; 
2563         break;
2564     default:
2565         ERROR("dwMoveMethod = %d is invalid\n", dwMoveMethod);
2566         palError = ERROR_INVALID_PARAMETER;
2567         goto done;
2568     }
2569
2570     //
2571     // According to MSDN, if lpDistanceToMoveHigh is not null, 
2572     // lDistanceToMove is treated as unsigned; 
2573     // it is treated as signed otherwise
2574     //
2575     
2576     if ( lpDistanceToMoveHigh )
2577     {
2578         /* set the high 32 bits of the offset */
2579         seek_offset = ((__int64)*lpDistanceToMoveHigh << 32);
2580         
2581         /* set the low 32 bits */
2582         /* cast to unsigned long to avoid sign extension */
2583         seek_offset |= (ULONG) lDistanceToMove;
2584     }
2585     else
2586     {
2587         seek_offset |= lDistanceToMove;
2588     }
2589
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)
2594     {
2595         ERROR("lseek(fd,0,SEEK_CUR) failed errno:%d (%s)\n", 
2596               errno, strerror(errno));
2597         palError = ERROR_ACCESS_DENIED;
2598         goto done;
2599     }
2600     
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,
2603     // this is simple.
2604     if ((seek_whence == SEEK_SET && seek_offset < 0) ||
2605         (seek_whence == SEEK_CUR && seek_offset + old_offset < 0))
2606     {
2607         palError = ERROR_NEGATIVE_SEEK;
2608         goto done;
2609     }
2610     else if (seek_whence == SEEK_END && seek_offset < 0)
2611     {
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
2615         // do that.
2616         struct stat fileData;
2617         int result;
2618         
2619         result = fstat(iUnixFd, &fileData);
2620         if (result == -1)
2621         {
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;
2626             goto done;
2627         }
2628         if (fileData.st_size < -seek_offset)
2629         {
2630             // Seeking past the beginning.
2631             palError = ERROR_NEGATIVE_SEEK;
2632             goto done;
2633         }
2634     }
2635
2636     seek_res = (__int64)lseek( iUnixFd,
2637                                seek_offset,
2638                                seek_whence );
2639     if ( seek_res < 0 )
2640     {
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
2644            is an error. */
2645         ERROR("lseek failed errno:%d (%s)\n", errno, strerror(errno));
2646         lseek(iUnixFd, old_offset, SEEK_SET);
2647         palError = ERROR_ACCESS_DENIED;
2648     }
2649     else
2650     {
2651         /* store high-order DWORD */
2652         if ( lpDistanceToMoveHigh )
2653             *lpDistanceToMoveHigh = (DWORD)(seek_res >> 32);
2654     
2655         /* return low-order DWORD of seek result */
2656         *lpNewFilePointerLow = (DWORD)seek_res;
2657     }
2658
2659 done:
2660
2661     return palError;
2662 }
2663
2664 PAL_ERROR
2665 CorUnix::InternalSetFilePointer(
2666     CPalThread *pThread,
2667     HANDLE hFile,
2668     LONG lDistanceToMove,
2669     PLONG lpDistanceToMoveHigh,
2670     DWORD dwMoveMethod,
2671     PLONG lpNewFilePointerLow
2672     )
2673 {
2674     PAL_ERROR palError = NO_ERROR;
2675     IPalObject *pFileObject = NULL;
2676     CFileProcessLocalData *pLocalData = NULL;
2677     IDataLock *pLocalDataLock = NULL;
2678
2679     if (INVALID_HANDLE_VALUE == hFile)
2680     {
2681         ERROR( "Invalid file handle\n" );
2682         palError = ERROR_INVALID_HANDLE;
2683         goto InternalSetFilePointerExit;
2684     }
2685
2686     palError = g_pObjectManager->ReferenceObjectByHandle(
2687         pThread,
2688         hFile,
2689         &aotFile,
2690         GENERIC_READ,
2691         &pFileObject
2692         );
2693
2694     if (NO_ERROR != palError)
2695     {
2696         goto InternalSetFilePointerExit;
2697     }
2698
2699     palError = pFileObject->GetProcessLocalData(
2700         pThread,
2701         ReadLock, 
2702         &pLocalDataLock,
2703         reinterpret_cast<void**>(&pLocalData)
2704         );
2705
2706     if (NO_ERROR != palError)
2707     {
2708         goto InternalSetFilePointerExit;
2709     }
2710
2711     palError = InternalSetFilePointerForUnixFd(
2712         pLocalData->unix_fd,
2713         lDistanceToMove,
2714         lpDistanceToMoveHigh,
2715         dwMoveMethod,
2716         lpNewFilePointerLow
2717         );
2718     
2719 InternalSetFilePointerExit:
2720
2721     if (NULL != pLocalDataLock)
2722     {
2723         pLocalDataLock->ReleaseLock(pThread, FALSE);
2724     }
2725
2726     if (NULL != pFileObject)
2727     {
2728         pFileObject->ReleaseReference(pThread);
2729     }
2730
2731     return palError;
2732 }
2733
2734 /*++
2735 Function:
2736   SetFilePointer
2737
2738 See MSDN doc.
2739 --*/
2740 DWORD
2741 PALAPI
2742 SetFilePointer(
2743            IN HANDLE hFile,
2744            IN LONG lDistanceToMove,
2745            IN PLONG lpDistanceToMoveHigh,
2746            IN DWORD dwMoveMethod)
2747 {
2748     PAL_ERROR palError = NO_ERROR;
2749     CPalThread *pThread;
2750     LONG lNewFilePointerLow = 0;
2751
2752     PERF_ENTRY(SetFilePointer);
2753     ENTRY("SetFilePointer(hFile=%p, lDistance=%d, lpDistanceHigh=%p, "
2754           "dwMoveMethod=%#x)\n", hFile, lDistanceToMove,
2755           lpDistanceToMoveHigh, dwMoveMethod);
2756
2757     pThread = InternalGetCurrentThread();
2758
2759     palError = InternalSetFilePointer(
2760         pThread,
2761         hFile,
2762         lDistanceToMove,
2763         lpDistanceToMoveHigh,
2764         dwMoveMethod,
2765         &lNewFilePointerLow
2766         );
2767
2768     if (NO_ERROR != palError)
2769     {
2770         lNewFilePointerLow = INVALID_SET_FILE_POINTER;
2771     }
2772
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 
2784        that it failed. */
2785     pThread->SetLastError(palError);
2786     
2787     LOGEXIT("SetFilePointer returns DWORD %#x\n", lNewFilePointerLow);
2788     PERF_EXIT(SetFilePointer);
2789     return lNewFilePointerLow;
2790 }
2791
2792 /*++
2793 Function:
2794   SetFilePointerEx
2795
2796 See MSDN doc.
2797 --*/
2798 BOOL
2799 PALAPI
2800 SetFilePointerEx(
2801            IN HANDLE hFile,
2802            IN LARGE_INTEGER liDistanceToMove,
2803            OUT PLARGE_INTEGER lpNewFilePointer,
2804            IN DWORD dwMoveMethod)
2805 {
2806     PAL_ERROR palError = NO_ERROR;
2807     CPalThread *pThread;
2808     BOOL Ret = FALSE;
2809
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);
2815
2816     LONG lDistanceToMove;
2817     lDistanceToMove = (LONG)liDistanceToMove.u.LowPart;
2818     LONG lDistanceToMoveHigh;
2819     lDistanceToMoveHigh = liDistanceToMove.u.HighPart;
2820
2821     LONG lNewFilePointerLow = 0;
2822
2823     pThread = InternalGetCurrentThread();
2824
2825     palError = InternalSetFilePointer(
2826         pThread,
2827         hFile,
2828         lDistanceToMove,
2829         &lDistanceToMoveHigh,
2830         dwMoveMethod,
2831         &lNewFilePointerLow
2832         );
2833
2834     if (NO_ERROR != palError)
2835     {
2836         pThread->SetLastError(palError);
2837     }
2838     else
2839     {
2840         if (lpNewFilePointer != NULL)
2841         {
2842             lpNewFilePointer->u.LowPart = (DWORD)lNewFilePointerLow;
2843             lpNewFilePointer->u.HighPart = (DWORD)lDistanceToMoveHigh;
2844         }
2845         Ret = TRUE;
2846     }
2847     
2848     LOGEXIT("SetFilePointerEx returns BOOL %d\n", Ret);
2849     PERF_EXIT(SetFilePointerEx);
2850     return Ret;
2851 }
2852
2853 PAL_ERROR
2854 CorUnix::InternalGetFileSize(
2855     CPalThread *pThread,
2856     HANDLE hFile,
2857     DWORD *pdwFileSizeLow,
2858     DWORD *pdwFileSizeHigh
2859     )
2860 {
2861     PAL_ERROR palError = NO_ERROR;
2862     IPalObject *pFileObject = NULL;
2863     CFileProcessLocalData *pLocalData = NULL;
2864     IDataLock *pLocalDataLock = NULL;
2865
2866     struct stat stat_data;
2867
2868     if (INVALID_HANDLE_VALUE == hFile)
2869     {
2870         ERROR( "Invalid file handle\n" );
2871         palError = ERROR_INVALID_HANDLE;
2872         goto InternalGetFileSizeExit;
2873     }
2874
2875     palError = g_pObjectManager->ReferenceObjectByHandle(
2876         pThread,
2877         hFile,
2878         &aotFile,
2879         GENERIC_READ,
2880         &pFileObject
2881         );
2882
2883     if (NO_ERROR != palError)
2884     {
2885         goto InternalGetFileSizeExit;
2886     }
2887
2888     palError = pFileObject->GetProcessLocalData(
2889         pThread,
2890         ReadLock, 
2891         &pLocalDataLock,
2892         reinterpret_cast<void**>(&pLocalData)
2893         );
2894
2895     if (NO_ERROR != palError)
2896     {
2897         goto InternalGetFileSizeExit;
2898     }
2899
2900     if (fstat(pLocalData->unix_fd, &stat_data) != 0)
2901     {
2902         ERROR("fstat failed of file descriptor %d\n", pLocalData->unix_fd);
2903         palError = FILEGetLastErrorFromErrno();
2904         goto InternalGetFileSizeExit;
2905     }
2906
2907     *pdwFileSizeLow = (DWORD)stat_data.st_size;
2908     
2909     if (NULL != pdwFileSizeHigh)
2910     {
2911 #if SIZEOF_OFF_T > 4
2912         *pdwFileSizeHigh = (DWORD)(stat_data.st_size >> 32);
2913 #else
2914         *pdwFileSizeHigh = 0;
2915 #endif
2916     }
2917
2918 InternalGetFileSizeExit:
2919
2920     if (NULL != pLocalDataLock)
2921     {
2922         pLocalDataLock->ReleaseLock(pThread, FALSE);
2923     }
2924
2925     if (NULL != pFileObject)
2926     {
2927         pFileObject->ReleaseReference(pThread);
2928     }
2929
2930     return palError;
2931 }
2932
2933 /*++
2934 Function:
2935   GetFileSize
2936
2937 See MSDN doc.
2938 --*/
2939 DWORD
2940 PALAPI
2941 GetFileSize(
2942         IN HANDLE hFile,
2943         OUT LPDWORD lpFileSizeHigh)
2944 {
2945     PAL_ERROR palError = NO_ERROR;
2946     CPalThread *pThread;
2947     DWORD dwFileSizeLow;
2948
2949     PERF_ENTRY(GetFileSize);
2950     ENTRY("GetFileSize(hFile=%p, lpFileSizeHigh=%p)\n", hFile, lpFileSizeHigh);
2951
2952     pThread = InternalGetCurrentThread();
2953
2954     palError = InternalGetFileSize(
2955         pThread,
2956         hFile, 
2957         &dwFileSizeLow,
2958         lpFileSizeHigh
2959         );
2960
2961     if (NO_ERROR != palError)
2962     {
2963         pThread->SetLastError(palError);
2964         dwFileSizeLow = INVALID_FILE_SIZE;
2965     }
2966
2967     LOGEXIT("GetFileSize returns DWORD %u\n", dwFileSizeLow);
2968     PERF_EXIT(GetFileSize);
2969     return dwFileSizeLow;
2970 }
2971
2972 /*++
2973 Function:
2974 GetFileSizeEx
2975
2976 See MSDN doc.
2977 --*/
2978 BOOL
2979 PALAPI GetFileSizeEx(
2980 IN   HANDLE hFile,
2981 OUT  PLARGE_INTEGER lpFileSize)
2982 {
2983     PAL_ERROR palError = NO_ERROR;
2984     CPalThread *pThread;
2985     DWORD dwFileSizeHigh;
2986     DWORD dwFileSizeLow;
2987
2988     PERF_ENTRY(GetFileSizeEx);
2989     ENTRY("GetFileSizeEx(hFile=%p, lpFileSize=%p)\n", hFile, lpFileSize);
2990
2991     pThread = InternalGetCurrentThread();
2992
2993     if (lpFileSize != NULL)
2994     {
2995         palError = InternalGetFileSize(
2996             pThread,
2997             hFile,
2998             &dwFileSizeLow,
2999             &dwFileSizeHigh
3000             );
3001
3002         lpFileSize->u.LowPart = dwFileSizeLow;
3003         lpFileSize->u.HighPart = dwFileSizeHigh;
3004     }
3005     else
3006     {
3007         palError = ERROR_INVALID_PARAMETER;
3008     }
3009
3010     if (NO_ERROR != palError)
3011     {
3012         pThread->SetLastError(palError);
3013     }
3014
3015     LOGEXIT("GetFileSizeEx returns BOOL %d\n", NO_ERROR == palError);
3016     PERF_EXIT(GetFileSizeEx);
3017     return NO_ERROR == palError;
3018 }
3019
3020 PAL_ERROR
3021 CorUnix::InternalFlushFileBuffers(
3022     CPalThread *pThread,
3023     HANDLE hFile
3024     )
3025 {
3026     PAL_ERROR palError = NO_ERROR;
3027     IPalObject *pFileObject = NULL;
3028     CFileProcessLocalData *pLocalData = NULL;
3029     IDataLock *pLocalDataLock = NULL;
3030
3031     if (INVALID_HANDLE_VALUE == hFile)
3032     {
3033         ERROR( "Invalid file handle\n" );
3034         palError = ERROR_INVALID_HANDLE;
3035         goto InternalFlushFileBuffersExit;
3036     }
3037
3038     palError = g_pObjectManager->ReferenceObjectByHandle(
3039         pThread,
3040         hFile,
3041         &aotFile,
3042         GENERIC_WRITE,
3043         &pFileObject
3044         );
3045
3046     if (NO_ERROR != palError)
3047     {
3048         goto InternalFlushFileBuffersExit;
3049     }
3050     
3051     palError = pFileObject->GetProcessLocalData(
3052         pThread,
3053         ReadLock, 
3054         &pLocalDataLock,
3055         reinterpret_cast<void**>(&pLocalData)
3056         );
3057
3058     if (NO_ERROR != palError)
3059     {
3060         goto InternalFlushFileBuffersExit;
3061     }
3062
3063     if (pLocalData->open_flags_deviceaccessonly == TRUE)
3064     {
3065         ERROR("File open for device access only\n");
3066         palError = ERROR_ACCESS_DENIED;
3067         goto InternalFlushFileBuffersExit;
3068     }
3069
3070 #if HAVE_FSYNC || defined(__APPLE__)
3071     do
3072     {
3073
3074 #if defined(__APPLE__)
3075         if (fcntl(pLocalData->unix_fd, F_FULLFSYNC) != -1)
3076             break;
3077 #else // __APPLE__
3078         if (fsync(pLocalData->unix_fd) == 0)
3079             break;
3080 #endif // __APPLE__
3081             
3082         switch (errno)
3083         {
3084         case EINTR:
3085             // Execution was interrupted by a signal, so restart.
3086             TRACE("fsync(%d) was interrupted. Restarting\n", pLocalData->unix_fd);
3087             break;
3088             
3089         default:
3090             palError = FILEGetLastErrorFromErrno();
3091             WARN("fsync(%d) failed with error %d\n", pLocalData->unix_fd, errno);
3092             break;
3093         }
3094     } while (NO_ERROR == palError);    
3095 #else // HAVE_FSYNC
3096     /* flush all buffers out to disk - there is no way to flush
3097        an individual file descriptor's buffers out. */
3098     sync();
3099 #endif // HAVE_FSYNC else
3100     
3101
3102 InternalFlushFileBuffersExit:
3103
3104     if (NULL != pLocalDataLock)
3105     {
3106         pLocalDataLock->ReleaseLock(pThread, FALSE);
3107     }
3108
3109     if (NULL != pFileObject)
3110     {
3111         pFileObject->ReleaseReference(pThread);
3112     }
3113
3114     return palError;
3115 }
3116
3117
3118 /*++
3119 Function:
3120   FlushFileBuffers
3121
3122 See MSDN doc.
3123 --*/
3124 BOOL
3125 PALAPI
3126 FlushFileBuffers(
3127          IN HANDLE hFile)
3128 {
3129     PAL_ERROR palError = NO_ERROR;
3130     CPalThread *pThread;
3131
3132     PERF_ENTRY(FlushFileBuffers);
3133     ENTRY("FlushFileBuffers(hFile=%p)\n", hFile);
3134
3135     pThread = InternalGetCurrentThread();
3136
3137     palError = InternalFlushFileBuffers(
3138         pThread,
3139         hFile
3140         );
3141
3142     if (NO_ERROR != palError)
3143     {
3144         pThread->SetLastError(palError);
3145     }
3146
3147     LOGEXIT("FlushFileBuffers returns BOOL %d\n", NO_ERROR == palError);
3148     PERF_EXIT(FlushFileBuffers);
3149     return NO_ERROR == palError;
3150 }
3151
3152 PAL_ERROR
3153 CorUnix::InternalGetFileType(
3154     CPalThread *pThread,
3155     HANDLE hFile,
3156     DWORD *pdwFileType
3157     )
3158 {
3159     PAL_ERROR palError = NO_ERROR;
3160     IPalObject *pFileObject = NULL;
3161     CFileProcessLocalData *pLocalData = NULL;
3162     IDataLock *pLocalDataLock = NULL;
3163
3164     struct stat stat_data;
3165
3166     if (INVALID_HANDLE_VALUE == hFile)
3167     {
3168         ERROR( "Invalid file handle\n" );
3169         palError = ERROR_INVALID_HANDLE;
3170         goto InternalGetFileTypeExit;
3171     }
3172
3173     palError = g_pObjectManager->ReferenceObjectByHandle(
3174         pThread,
3175         hFile,
3176         &aotFile,
3177         GENERIC_READ,
3178         &pFileObject
3179         );
3180
3181     if (NO_ERROR != palError)
3182     {
3183         goto InternalGetFileTypeExit;
3184     }
3185     
3186     palError = pFileObject->GetProcessLocalData(
3187         pThread,
3188         ReadLock, 
3189         &pLocalDataLock,
3190         reinterpret_cast<void**>(&pLocalData)
3191         );
3192
3193     if (NO_ERROR != palError)
3194     {
3195         goto InternalGetFileTypeExit;
3196     }
3197
3198     if (pLocalData->open_flags_deviceaccessonly == TRUE)
3199     {
3200         ERROR("File open for device access only\n");
3201         palError = ERROR_ACCESS_DENIED;
3202         goto InternalGetFileTypeExit;
3203     }
3204
3205     if (fstat(pLocalData->unix_fd, &stat_data) != 0)
3206     {
3207         ERROR("fstat failed of file descriptor %d\n", pLocalData->unix_fd);
3208         palError = FILEGetLastErrorFromErrno();
3209         goto InternalGetFileTypeExit;
3210     }
3211
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))
3214     {
3215         *pdwFileType = FILE_TYPE_DISK;
3216     }
3217     else if (S_ISCHR(stat_data.st_mode))
3218     {
3219         *pdwFileType = FILE_TYPE_CHAR;
3220     }
3221     else if (S_ISFIFO(stat_data.st_mode))
3222     {
3223         *pdwFileType = FILE_TYPE_PIPE;
3224     }
3225     else
3226     {
3227         *pdwFileType = FILE_TYPE_UNKNOWN;
3228     }
3229     
3230
3231 InternalGetFileTypeExit:
3232
3233     if (NULL != pLocalDataLock)
3234     {
3235         pLocalDataLock->ReleaseLock(pThread, FALSE);
3236     }
3237
3238     if (NULL != pFileObject)
3239     {
3240         pFileObject->ReleaseReference(pThread);
3241     }
3242
3243     return palError;
3244
3245 }
3246
3247
3248 /*++
3249 Function:
3250   GetFileType
3251
3252 See MSDN doc.
3253
3254 --*/
3255 DWORD
3256 PALAPI
3257 GetFileType(
3258         IN HANDLE hFile)
3259 {
3260     PAL_ERROR palError = NO_ERROR;
3261     CPalThread *pThread;
3262     DWORD dwFileType;
3263
3264     PERF_ENTRY(GetFileType);
3265     ENTRY("GetFileType(hFile=%p)\n", hFile);
3266
3267     pThread = InternalGetCurrentThread();
3268
3269     palError = InternalGetFileType(
3270         pThread,
3271         hFile,
3272         &dwFileType
3273         );
3274
3275     if (NO_ERROR != palError)
3276     {
3277         dwFileType = FILE_TYPE_UNKNOWN;
3278         pThread->SetLastError(palError);
3279     }
3280     else if (FILE_TYPE_UNKNOWN == dwFileType)
3281     {
3282         pThread->SetLastError(palError);
3283     }
3284
3285
3286     LOGEXIT("GetFileType returns DWORD %#x\n", dwFileType);
3287     PERF_EXIT(GetFileType);
3288     return dwFileType;
3289 }
3290
3291 #define ENSURE_UNIQUE_NOT_ZERO \
3292     if ( uUniqueSeed == 0 ) \
3293     {\
3294         uUniqueSeed++;\
3295     }
3296
3297 /*++
3298  Function:
3299    GetTempFileNameA
3300
3301 uUnique is always 0.
3302  --*/
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;
3308
3309 UINT
3310 PALAPI
3311 GetTempFileNameA(
3312                  IN LPCSTR lpPathName,
3313                  IN LPCSTR lpPrefixString,
3314                  IN UINT   uUnique,
3315                  OUT LPSTR lpTempFileName)
3316 {
3317     CPalThread *pThread;
3318     CHAR * full_name;
3319     PathCharString full_namePS;
3320     int length;
3321     CHAR * file_template;
3322     PathCharString file_templatePS;
3323     CHAR    chLastPathNameChar;
3324  
3325     HANDLE  hTempFile;
3326     UINT    uRet = 0;
3327     DWORD   dwError;
3328     USHORT  uLoopCounter = 0;
3329
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");
3336
3337     pThread = InternalGetCurrentThread();
3338     if ( !IsInitialized )
3339     {
3340         uUniqueSeed = (USHORT)( time( NULL ) );
3341     
3342         /* On the off chance 0 is returned.
3343         0 being the error return code.  */
3344         ENSURE_UNIQUE_NOT_ZERO
3345         IsInitialized = TRUE;
3346     }
3347
3348     if ( !lpPathName || *lpPathName == '\0' )
3349     {
3350        pThread->SetLastError( ERROR_DIRECTORY );
3351        goto done;
3352     }
3353
3354     if ( NULL == lpTempFileName )  
3355     {
3356         ERROR( "lpTempFileName cannot be NULL\n" );
3357         pThread->SetLastError( ERROR_INVALID_PARAMETER );
3358         goto done;
3359     }
3360
3361     if ( strlen( lpPathName ) + MAX_SEEDSIZE + MAX_PREFIX >= MAX_LONGPATH ) 
3362     {
3363         WARN( "File names larger than MAX_LONGPATH (%d)!\n", MAX_LONGPATH );
3364         pThread->SetLastError( ERROR_FILENAME_EXCED_RANGE );
3365         goto done;
3366     }
3367
3368     length = strlen(lpPathName) + MAX_SEEDSIZE + MAX_PREFIX + 10;
3369     file_template = file_templatePS.OpenStringBuffer(length);
3370     if (NULL == file_template)
3371     {
3372         pThread->SetLastError(ERROR_NOT_ENOUGH_MEMORY);
3373         goto done;
3374     }
3375     *file_template = '\0';
3376     strcat_s( file_template, file_templatePS.GetSizeOf(), lpPathName );
3377     file_templatePS.CloseBuffer(length);
3378
3379     chLastPathNameChar = file_template[strlen(file_template)-1];
3380     if (chLastPathNameChar != '\\' && chLastPathNameChar != '/')
3381     {
3382         strcat_s( file_template, file_templatePS.GetSizeOf(), "\\" );
3383     }
3384     
3385     if ( lpPrefixString )
3386     {
3387         strncat_s( file_template, file_templatePS.GetSizeOf(), lpPrefixString, MAX_PREFIX );
3388     }
3389     FILEDosToUnixPathA( file_template );
3390     strncat_s( file_template, file_templatePS.GetSizeOf(), "%.4x.TMP", MAX_SEEDSIZE );
3391
3392     /* Create the file. */
3393     dwError = GetLastError();
3394     pThread->SetLastError( NOERROR );
3395
3396     length = strlen(file_template) + MAX_SEEDSIZE + MAX_PREFIX;
3397     full_name = full_namePS.OpenStringBuffer(length);
3398     if (NULL == full_name)
3399     {
3400         pThread->SetLastError(ERROR_NOT_ENOUGH_MEMORY);
3401         goto done;
3402     }
3403     sprintf_s( full_name, full_namePS.GetSizeOf(), file_template, (0 == uUnique) ? uUniqueSeed : uUnique);
3404     full_namePS.CloseBuffer(length);
3405     
3406     hTempFile = CreateFileA( full_name, GENERIC_WRITE, 
3407                              FILE_SHARE_READ, NULL, CREATE_NEW, 0, NULL );
3408     
3409     if (uUnique == 0)
3410     {
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 )
3418         {
3419             uUniqueSeed++;
3420             ENSURE_UNIQUE_NOT_ZERO;
3421
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 );
3426             uLoopCounter++;
3427         
3428         }
3429     }
3430
3431     /* Reset the error code.*/
3432     if ( NOERROR == GetLastError() )
3433     {
3434         pThread->SetLastError( dwError );
3435     }
3436
3437     /* Windows sets ERROR_FILE_EXISTS,if there
3438     are no available temp files. */
3439     if ( INVALID_HANDLE_VALUE != hTempFile )
3440     {
3441         if (0 == uUnique)
3442         {
3443             uRet = uUniqueSeed;
3444             uUniqueSeed++;
3445             ENSURE_UNIQUE_NOT_ZERO;
3446         }
3447         else
3448         {
3449             uRet = uUnique;
3450         }
3451         
3452         if ( CloseHandle( hTempFile ) )
3453         {
3454             if (strcpy_s( lpTempFileName, MAX_LONGPATH, full_name ) != SAFECRT_SUCCESS)
3455             {
3456                 ERROR( "strcpy_s failed!\n");
3457                 pThread->SetLastError( ERROR_FILENAME_EXCED_RANGE );
3458                 *lpTempFileName = '\0';
3459                 uRet = 0;
3460             }
3461         }
3462         else  
3463         {
3464             ASSERT( "Unable to close the handle %p\n", hTempFile );
3465             pThread->SetLastError( ERROR_INTERNAL_ERROR );
3466             *lpTempFileName = '\0';
3467             uRet = 0;
3468         }
3469     }
3470     else if ( INVALID_HANDLE_VALUE == hTempFile && uLoopCounter < 0xFFFF )
3471     {
3472         ERROR( "Unable to create temp file. \n" );
3473         uRet = 0;
3474         
3475         if ( ERROR_PATH_NOT_FOUND == GetLastError() )
3476         {
3477             /* CreateFile failed because it could not 
3478             find the path. */
3479             pThread->SetLastError( ERROR_DIRECTORY );
3480         } /* else use the lasterror value from CreateFileA */
3481     }
3482     else
3483     {
3484         TRACE( "65535 files already exist in the directory. "
3485                "No temp files available for creation.\n" );
3486         pThread->SetLastError( ERROR_FILE_EXISTS );
3487     }
3488
3489 done:
3490     LOGEXIT("GetTempFileNameA returns UINT %u\n", uRet);
3491     PERF_EXIT(GetTempFileNameA);
3492     return uRet;
3493        
3494 }
3495         
3496 /*++
3497 Function:
3498   GetTempFileNameW
3499
3500 uUnique is always 0.
3501 --*/
3502 UINT
3503 PALAPI
3504 GetTempFileNameW(
3505          IN LPCWSTR lpPathName,
3506          IN LPCWSTR lpPrefixString,
3507          IN UINT uUnique,
3508          OUT LPWSTR lpTempFileName)
3509 {
3510     CPalThread *pThread;
3511     INT path_size = 0;
3512     INT prefix_size = 0;
3513     CHAR * full_name;
3514     CHAR * prefix_string;
3515     CHAR * tempfile_name;
3516     PathCharString full_namePS, prefix_stringPS;
3517     INT length = 0;
3518     UINT   uRet;
3519
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);
3525
3526     pThread = InternalGetCurrentThread();
3527     /* Sanity checks. */
3528     if ( !lpPathName || *lpPathName == '\0' )
3529     {
3530         pThread->SetLastError( ERROR_DIRECTORY );
3531         uRet = 0;
3532         goto done;
3533     }
3534
3535     length = (PAL_wcslen(lpPathName)+1) * MaxWCharToAcpLengthFactor;
3536     full_name = full_namePS.OpenStringBuffer(length);
3537     if (NULL == full_name)
3538     {
3539         pThread->SetLastError(ERROR_NOT_ENOUGH_MEMORY);
3540         uRet = 0;
3541         goto done;
3542     }
3543     path_size = WideCharToMultiByte( CP_ACP, 0, lpPathName, -1, full_name,
3544                                      length, NULL, NULL );
3545                                      
3546     if( path_size == 0 )
3547     {
3548         full_namePS.CloseBuffer(0);
3549         DWORD dwLastError = GetLastError();
3550         ASSERT("WideCharToMultiByte failure! error is %d\n", dwLastError);
3551         pThread->SetLastError(ERROR_INTERNAL_ERROR);
3552         uRet = 0;
3553         goto done;
3554     }
3555     
3556     full_namePS.CloseBuffer(path_size - 1);
3557     
3558     if (lpPrefixString != NULL) 
3559     {
3560         length = (PAL_wcslen(lpPrefixString)+1) * MaxWCharToAcpLengthFactor;
3561         prefix_string = prefix_stringPS.OpenStringBuffer(length);
3562         if (NULL == prefix_string)
3563         {
3564             pThread->SetLastError(ERROR_NOT_ENOUGH_MEMORY);
3565             uRet = 0;
3566             goto done;
3567         }
3568         prefix_size = WideCharToMultiByte( CP_ACP, 0, lpPrefixString, -1, 
3569                                            prefix_string,
3570                                            MAX_LONGPATH - path_size - MAX_SEEDSIZE, 
3571                                            NULL, NULL );
3572         
3573         if( prefix_size == 0 )
3574         {
3575             prefix_stringPS.CloseBuffer(0);
3576             DWORD dwLastError = GetLastError();
3577             ASSERT("WideCharToMultiByte failure! error is %d\n", dwLastError);
3578             pThread->SetLastError(ERROR_INTERNAL_ERROR);
3579             uRet = 0;
3580             goto done;
3581         }
3582         prefix_stringPS.CloseBuffer(prefix_size - 1);
3583     }
3584     
3585     tempfile_name = (char*)InternalMalloc(MAX_LONGPATH);
3586     if (tempfile_name == NULL)
3587     {
3588         pThread->SetLastError(ERROR_NOT_ENOUGH_MEMORY);
3589         uRet = 0;
3590         goto done;
3591     }
3592     
3593     uRet = GetTempFileNameA(full_name, 
3594                             (lpPrefixString == NULL) ? NULL : prefix_string,
3595                             0, tempfile_name);
3596     if (uRet)
3597     {                    
3598         path_size = MultiByteToWideChar( CP_ACP, 0, tempfile_name, -1, 
3599                                            lpTempFileName, MAX_LONGPATH );
3600
3601         free(tempfile_name);
3602         tempfile_name = NULL;
3603         if (!path_size)
3604         {
3605             DWORD dwLastError = GetLastError();
3606             if (dwLastError == ERROR_INSUFFICIENT_BUFFER)
3607             {
3608                 WARN("File names larger than MAX_PATH_FNAME (%d)! \n", MAX_LONGPATH);
3609                 dwLastError = ERROR_FILENAME_EXCED_RANGE;
3610             }
3611             else
3612             {
3613                 ASSERT("MultiByteToWideChar failure! error is %d", dwLastError);     
3614                 dwLastError = ERROR_INTERNAL_ERROR;
3615             }
3616             pThread->SetLastError(dwLastError);
3617             uRet = 0;
3618         }
3619     }
3620
3621 done:
3622     LOGEXIT("GetTempFileNameW returns UINT %u\n", uRet);
3623     PERF_EXIT(GetTempFileNameW);
3624     return uRet;
3625 }
3626
3627 /*++
3628 Function:
3629   FILEGetLastErrorFromErrno
3630
3631 Convert errno into the appropriate win32 error and return it.
3632 --*/
3633 DWORD FILEGetLastErrorFromErrno( void )
3634 {
3635     DWORD dwRet;
3636
3637     switch(errno)
3638     {
3639     case 0:
3640         dwRet = ERROR_SUCCESS; 
3641         break;
3642     case ENAMETOOLONG:
3643         dwRet = ERROR_FILENAME_EXCED_RANGE;
3644         break;
3645     case ENOTDIR:
3646         dwRet = ERROR_PATH_NOT_FOUND; 
3647         break;
3648     case ENOENT:
3649         dwRet = ERROR_FILE_NOT_FOUND; 
3650         break;
3651     case EACCES:
3652     case EPERM:
3653     case EROFS:
3654     case EISDIR:
3655         dwRet = ERROR_ACCESS_DENIED; 
3656         break;
3657     case EEXIST:
3658         dwRet = ERROR_ALREADY_EXISTS; 
3659         break;
3660 #if !defined(_AIX)
3661     // ENOTEMPTY is the same as EEXIST on AIX. Meaningful when involving directory operations
3662     case ENOTEMPTY:
3663         dwRet = ERROR_DIR_NOT_EMPTY; 
3664         break;
3665 #endif
3666     case EBADF:
3667         dwRet = ERROR_INVALID_HANDLE; 
3668         break;
3669     case ENOMEM:
3670         dwRet = ERROR_NOT_ENOUGH_MEMORY; 
3671         break;
3672     case EBUSY:
3673         dwRet = ERROR_BUSY;
3674         break;
3675     case ENOSPC:
3676     case EDQUOT:
3677         dwRet = ERROR_DISK_FULL;
3678         break;
3679     case ELOOP:
3680         dwRet = ERROR_BAD_PATHNAME;
3681         break;
3682     case EIO:
3683         dwRet = ERROR_WRITE_FAULT;
3684         break;
3685     case ERANGE:
3686         dwRet = ERROR_BAD_PATHNAME;
3687         break;
3688     default:
3689         ERROR("unexpected errno %d (%s); returning ERROR_GEN_FAILURE\n",
3690               errno, strerror(errno));
3691         dwRet = ERROR_GEN_FAILURE;
3692     }
3693
3694     TRACE("errno = %d (%s), LastError = %d\n", errno, strerror(errno), dwRet);
3695
3696     return dwRet;
3697 }
3698
3699 /*++
3700 Function:
3701   DIRGetLastErrorFromErrno
3702
3703 Convert errno into the appropriate win32 error and return it.
3704 --*/
3705 DWORD DIRGetLastErrorFromErrno( void )
3706 {
3707     if (errno == ENOENT)
3708         return ERROR_PATH_NOT_FOUND;
3709     else
3710         return FILEGetLastErrorFromErrno();
3711 }
3712
3713
3714 /*++
3715 Function:
3716   CopyFileA
3717
3718 See MSDN doc.
3719
3720 Notes:
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.
3724 --*/
3725 BOOL
3726 PALAPI
3727 CopyFileA(
3728       IN LPCSTR lpExistingFileName,
3729       IN LPCSTR lpNewFileName,
3730       IN BOOL bFailIfExists)
3731 {
3732     CPalThread *pThread;
3733     HANDLE       hSource = INVALID_HANDLE_VALUE;
3734     HANDLE       hDest = INVALID_HANDLE_VALUE;
3735     DWORD        dwDestCreationMode;
3736     BOOL         bGood = FALSE;
3737     DWORD        dwSrcFileAttributes;
3738     struct stat  SrcFileStats;
3739     
3740     LPSTR lpUnixPath = NULL;
3741     const int    buffer_size = 16*1024;
3742     char        *buffer = (char*)alloca(buffer_size);
3743     DWORD        bytes_read;
3744     DWORD        bytes_written;
3745     int          permissions;
3746
3747
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);
3754
3755     pThread = InternalGetCurrentThread();
3756     if ( bFailIfExists )
3757     {
3758         dwDestCreationMode = CREATE_NEW;
3759     }
3760     else
3761     {
3762         dwDestCreationMode = CREATE_ALWAYS;
3763     }
3764     
3765     hSource = CreateFileA( lpExistingFileName,
3766                GENERIC_READ,
3767                FILE_SHARE_READ,
3768                NULL,
3769                OPEN_EXISTING,
3770                0,
3771                NULL );
3772
3773     if ( hSource == INVALID_HANDLE_VALUE )
3774     {
3775         ERROR("CreateFileA failed for %s\n", lpExistingFileName);
3776         goto done;
3777     }
3778
3779     /* Need to preserve the file attributes */
3780     dwSrcFileAttributes = GetFileAttributes(lpExistingFileName);
3781     if (dwSrcFileAttributes == 0xffffffff)
3782     {
3783         ERROR("GetFileAttributes failed for %s\n", lpExistingFileName);
3784         goto done;
3785     }
3786
3787     /* Need to preserve the owner/group and chmod() flags */
3788     lpUnixPath = strdup(lpExistingFileName);
3789     if ( lpUnixPath == NULL )
3790     {
3791         ERROR("strdup() failed\n");
3792         pThread->SetLastError(FILEGetLastErrorFromErrno());
3793         goto done;
3794     }
3795     FILEDosToUnixPathA(lpUnixPath);
3796     if (stat (lpUnixPath, &SrcFileStats) == -1)
3797     {
3798         ERROR("stat() failed for %s\n", lpExistingFileName);
3799         pThread->SetLastError(FILEGetLastErrorFromErrnoAndFilename(lpUnixPath));
3800         goto done;
3801     }
3802
3803     hDest = CreateFileA( lpNewFileName,
3804              GENERIC_WRITE,
3805              FILE_SHARE_READ,
3806              NULL,
3807              dwDestCreationMode,
3808              0,
3809              NULL );
3810
3811     if ( hDest == INVALID_HANDLE_VALUE )
3812     {
3813         ERROR("CreateFileA failed for %s\n", lpNewFileName);    
3814         goto done;
3815     }
3816
3817     free(lpUnixPath);
3818     lpUnixPath = strdup(lpNewFileName);
3819     if ( lpUnixPath == NULL )
3820     {
3821         ERROR("strdup() failed\n");
3822         pThread->SetLastError(FILEGetLastErrorFromErrno());
3823         goto done;
3824     }
3825     FILEDosToUnixPathA( lpUnixPath );
3826     
3827  
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
3830     // here.
3831     permissions = (S_IRWXU | S_IRWXG | S_IRWXO);
3832     if ((dwSrcFileAttributes & FILE_ATTRIBUTE_READONLY) != 0)
3833     {
3834         permissions &= ~(S_IWUSR | S_IWGRP | S_IWOTH);
3835     }
3836
3837     /* Make sure the new file has the same chmod() flags. */
3838     if (chmod(lpUnixPath, SrcFileStats.st_mode & permissions) == -1)
3839     {
3840         WARN ("chmod() failed to set mode 0x%x on new file\n",
3841               SrcFileStats.st_mode & permissions);
3842         pThread->SetLastError(FILEGetLastErrorFromErrnoAndFilename(lpUnixPath));
3843         goto done;
3844     }
3845
3846     while( (bGood = ReadFile( hSource, buffer, buffer_size, &bytes_read, NULL ))
3847            && bytes_read > 0 )
3848     {
3849         bGood = ( WriteFile( hDest, buffer, bytes_read, &bytes_written, NULL )
3850           && bytes_written == bytes_read);
3851         if (!bGood) break;
3852     }
3853
3854     if (!bGood)
3855     {
3856         ERROR("Copy failed\n");
3857
3858         if ( !CloseHandle(hDest) ||
3859              !DeleteFileA(lpNewFileName) )
3860         {
3861             ERROR("Unable to clean up partial copy\n");
3862         }
3863         hDest = INVALID_HANDLE_VALUE;
3864
3865         goto done;
3866     }
3867     
3868 done:
3869
3870     if ( hSource != INVALID_HANDLE_VALUE ) 
3871     {
3872         CloseHandle( hSource );
3873     }
3874     if ( hDest != INVALID_HANDLE_VALUE )
3875     {
3876         CloseHandle( hDest );
3877     }
3878     if (lpUnixPath) 
3879     {
3880         free(lpUnixPath);
3881     }
3882
3883     LOGEXIT("CopyFileA returns BOOL %d\n", bGood);
3884     PERF_EXIT(CopyFileA);
3885     return bGood;
3886 }
3887
3888
3889 /*++
3890 Function:
3891   SetFileAttributesA
3892
3893 Notes:
3894   Used for setting read-only attribute on file only.
3895
3896 --*/
3897 BOOL
3898 PALAPI
3899 SetFileAttributesA(
3900            IN LPCSTR lpFileName,
3901            IN DWORD dwFileAttributes)
3902 {
3903     CPalThread *pThread;
3904     struct stat stat_data;
3905     mode_t new_mode;
3906
3907     DWORD dwLastError = 0;
3908     BOOL  bRet = FALSE;
3909     LPSTR unixFileName = NULL;
3910
3911     PERF_ENTRY(SetFileAttributesA);
3912     ENTRY("SetFileAttributesA(lpFileName=%p (%s), dwFileAttributes=%#x)\n",
3913         lpFileName?lpFileName:"NULL",
3914         lpFileName?lpFileName:"NULL", dwFileAttributes);
3915
3916     pThread = InternalGetCurrentThread();
3917
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. */
3923
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)) )
3927     {
3928         dwFileAttributes = FILE_ATTRIBUTE_NORMAL;
3929         WARN("dwFileAttributes(%#x) contains attributes that are either not supported "
3930             "or cannot be set via SetFileAttributes.\n");
3931     }
3932      
3933     if ( (dwFileAttributes & FILE_ATTRIBUTE_NORMAL) &&
3934          (dwFileAttributes != FILE_ATTRIBUTE_NORMAL) )
3935     {
3936         WARN("Ignoring FILE_ATTRIBUTE_NORMAL -- it must be used alone\n");
3937     }
3938
3939     if (lpFileName == NULL)
3940     {
3941         dwLastError = ERROR_FILE_NOT_FOUND;
3942         goto done;
3943     }
3944
3945     if ((unixFileName = strdup(lpFileName)) == NULL)
3946     {
3947         ERROR("strdup() failed\n");
3948         dwLastError = ERROR_NOT_ENOUGH_MEMORY;
3949         goto done;
3950     }
3951
3952     FILEDosToUnixPathA( unixFileName );
3953     if ( stat(unixFileName, &stat_data) != 0 )
3954     {
3955         TRACE("stat failed on %s; errno is %d (%s)\n", 
3956              unixFileName, errno, strerror(errno));
3957         dwLastError = FILEGetLastErrorFromErrnoAndFilename(unixFileName);
3958         goto done;
3959     }
3960
3961     new_mode = stat_data.st_mode;
3962     TRACE("st_mode is %#x\n", new_mode);
3963
3964     /* if we can't do GetFileAttributes on it, don't do SetFileAttributes */
3965     if ( !(new_mode & S_IFREG) && !(new_mode & S_IFDIR) )
3966     {
3967         ERROR("Not a regular file or directory, S_IFMT is %#x\n",
3968               new_mode & S_IFMT);
3969         dwLastError = ERROR_ACCESS_DENIED;
3970         goto done;    
3971     }
3972
3973     /* set or unset the "read-only" attribute */
3974     if (dwFileAttributes & FILE_ATTRIBUTE_READONLY)
3975     {
3976         /* remove the write bit from everybody */
3977         new_mode &= ~(S_IWUSR | S_IWGRP | S_IWOTH);
3978     }
3979     else
3980     {
3981         /* give write permission to the owner if the owner
3982          * already has read permission */
3983         if ( new_mode & S_IRUSR )
3984         {
3985             new_mode |= S_IWUSR;
3986         }
3987     }
3988     TRACE("new mode is %#x\n", new_mode);
3989
3990     bRet = TRUE;
3991     if ( new_mode != stat_data.st_mode )
3992     {
3993         if ( chmod(unixFileName, new_mode) != 0 )
3994         {
3995             ERROR("chmod(%s, %#x) failed\n", unixFileName, new_mode);
3996             dwLastError = FILEGetLastErrorFromErrnoAndFilename(unixFileName);
3997             bRet = FALSE;
3998         }
3999     }
4000
4001 done:
4002     if (dwLastError)
4003     {
4004         pThread->SetLastError(dwLastError);
4005     }
4006     
4007     free(unixFileName);
4008
4009     LOGEXIT("SetFileAttributesA returns BOOL %d\n", bRet);
4010     PERF_EXIT(SetFileAttributesA);
4011     return bRet;
4012 }
4013
4014 PAL_ERROR
4015 CorUnix::InternalCreatePipe(
4016     CPalThread *pThread,
4017     HANDLE *phReadPipe,
4018     HANDLE *phWritePipe,
4019     LPSECURITY_ATTRIBUTES lpPipeAttributes,
4020     DWORD nSize
4021     )
4022 {
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);
4031         
4032     int readWritePipeDes[2] = {-1, -1};
4033
4034     if ((phReadPipe == NULL) || (phWritePipe == NULL))
4035     {
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;
4039     }
4040
4041     if ((lpPipeAttributes == NULL) || 
4042         (lpPipeAttributes->bInheritHandle == FALSE) ||
4043         (lpPipeAttributes->lpSecurityDescriptor != NULL))
4044     {
4045         ASSERT("invalid security attributes!\n");
4046         palError = ERROR_INVALID_PARAMETER;
4047         goto InternalCreatePipeExit;
4048     }
4049
4050     if (pipe(readWritePipeDes) == -1)
4051     {
4052         ERROR("pipe() call failed errno:%d (%s) \n", errno, strerror(errno));
4053         palError = ERROR_INTERNAL_ERROR;
4054         goto InternalCreatePipeExit;
4055     }
4056
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))
4060     {
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;
4065     }
4066     if(-1 == fcntl(readWritePipeDes[1],F_SETFD,1))
4067     {
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;
4072     }
4073
4074     //
4075     // Setup the object for the read end of the pipe
4076     //
4077
4078     palError = g_pObjectManager->AllocateObject(
4079         pThread,
4080         &otFile,
4081         &oaFile,
4082         &pReadFileObject
4083         );
4084
4085     if (NO_ERROR != palError)
4086     {
4087         goto InternalCreatePipeExit;
4088     }
4089
4090     palError = pReadFileObject->GetProcessLocalData(
4091         pThread,
4092         WriteLock,
4093         &pDataLock,
4094         reinterpret_cast<void**>(&pLocalData)
4095         );
4096
4097     if (NO_ERROR != palError)
4098     {
4099         goto InternalCreatePipeExit;
4100     }
4101
4102     pLocalData->inheritable = TRUE;
4103     pLocalData->open_flags = O_RDONLY;
4104
4105     //
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.
4109     //
4110
4111     pLocalData->unix_fd = readWritePipeDes[0];
4112     readWritePipeDes[0] = -1;
4113
4114     pDataLock->ReleaseLock(pThread, TRUE);
4115     pDataLock = NULL;
4116
4117     //
4118     // Setup the object for the write end of the pipe
4119     //
4120
4121     palError = g_pObjectManager->AllocateObject(
4122         pThread,
4123         &otFile,
4124         &oaFile,
4125         &pWriteFileObject
4126         );
4127
4128     if (NO_ERROR != palError)
4129     {
4130         goto InternalCreatePipeExit;
4131     }
4132
4133     palError = pWriteFileObject->GetProcessLocalData(
4134         pThread,
4135         WriteLock,
4136         &pDataLock,
4137         reinterpret_cast<void**>(&pLocalData)
4138         );
4139
4140     if (NO_ERROR != palError)
4141     {
4142         goto InternalCreatePipeExit;
4143     }
4144
4145     pLocalData->inheritable = TRUE;
4146     pLocalData->open_flags = O_WRONLY;
4147
4148     //
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.
4152     //
4153
4154     pLocalData->unix_fd = readWritePipeDes[1];
4155     readWritePipeDes[1] = -1;
4156
4157     pDataLock->ReleaseLock(pThread, TRUE);
4158     pDataLock = NULL;
4159
4160     //
4161     // Register the pipe objects
4162     //
4163
4164     palError = g_pObjectManager->RegisterObject(
4165         pThread,
4166         pReadFileObject,
4167         &aotFile,
4168         GENERIC_READ,
4169         phReadPipe,
4170         &pReadRegisteredFile
4171         );
4172
4173     //
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.
4177     //
4178
4179     pReadFileObject = NULL;
4180
4181     if (NO_ERROR != palError)
4182     {
4183         goto InternalCreatePipeExit;
4184     }
4185
4186     palError = g_pObjectManager->RegisterObject(
4187         pThread,
4188         pWriteFileObject,
4189         &aotFile,
4190         GENERIC_WRITE,
4191         phWritePipe,
4192         &pWriteRegisteredFile
4193         );
4194
4195     //
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.
4199     //
4200
4201     pWriteFileObject = NULL;
4202     
4203 InternalCreatePipeExit:
4204
4205     if (NO_ERROR != palError)
4206     {
4207         if (-1 != readWritePipeDes[0])
4208         {
4209             close(readWritePipeDes[0]);
4210         }
4211
4212         if (-1 != readWritePipeDes[1])
4213         {
4214             close(readWritePipeDes[1]);
4215         }
4216     }
4217
4218     if (NULL != pReadFileObject)
4219     {
4220         pReadFileObject->ReleaseReference(pThread);
4221     }
4222
4223     if (NULL != pReadRegisteredFile)
4224     {
4225         pReadRegisteredFile->ReleaseReference(pThread);
4226     }
4227
4228     if (NULL != pWriteFileObject)
4229     {
4230         pWriteFileObject->ReleaseReference(pThread);
4231     }
4232
4233     if (NULL != pWriteRegisteredFile)
4234     {
4235         pWriteRegisteredFile->ReleaseReference(pThread);
4236     }
4237
4238     return palError;
4239 }
4240
4241 /*++
4242 Function:
4243   CreatePipe
4244
4245 See MSDN doc.
4246 --*/
4247 PALIMPORT
4248 BOOL
4249 PALAPI
4250 CreatePipe(
4251         OUT PHANDLE hReadPipe,
4252         OUT PHANDLE hWritePipe,
4253         IN LPSECURITY_ATTRIBUTES lpPipeAttributes,
4254         IN DWORD nSize)
4255 {
4256     PAL_ERROR palError;
4257     CPalThread *pThread;
4258
4259     PERF_ENTRY(CreatePipe);
4260     ENTRY("CreatePipe(hReadPipe:%p, hWritePipe:%p, lpPipeAttributes:%p, nSize:%d\n",
4261           hReadPipe, hWritePipe, lpPipeAttributes, nSize);
4262
4263     pThread = InternalGetCurrentThread();
4264
4265     palError = InternalCreatePipe(
4266         pThread,
4267         hReadPipe,
4268         hWritePipe,
4269         lpPipeAttributes,
4270         nSize
4271         );
4272
4273     if (NO_ERROR != palError)
4274     {
4275         pThread->SetLastError(palError);
4276     }
4277
4278     LOGEXIT("CreatePipe return %s\n", NO_ERROR == palError ? "TRUE":"FALSE");
4279     PERF_EXIT(CreatePipe);
4280     return NO_ERROR == palError;
4281 }
4282
4283 PAL_ERROR
4284 CorUnix::InternalLockFile(
4285     CPalThread *pThread,
4286     HANDLE hFile,
4287     DWORD dwFileOffsetLow,
4288     DWORD dwFileOffsetHigh,
4289     DWORD nNumberOfBytesToLockLow,
4290     DWORD nNumberOfBytesToLockHigh
4291     )
4292 {
4293     PAL_ERROR palError = NO_ERROR;
4294     IPalObject *pFileObject = NULL;
4295     CFileProcessLocalData *pLocalData = NULL;
4296     IDataLock *pLocalDataLock = NULL;
4297
4298     if (INVALID_HANDLE_VALUE == hFile)
4299     {
4300         ERROR( "Invalid file handle\n" );
4301         palError = ERROR_INVALID_HANDLE;
4302         goto InternalLockFileExit;
4303     }
4304
4305     palError = g_pObjectManager->ReferenceObjectByHandle(
4306         pThread,
4307         hFile,
4308         &aotFile,
4309         GENERIC_READ,
4310         &pFileObject
4311         );
4312
4313     if (NO_ERROR != palError)
4314     {
4315         goto InternalLockFileExit;
4316     }
4317
4318     palError = pFileObject->GetProcessLocalData(
4319         pThread,
4320         ReadLock, 
4321         &pLocalDataLock,
4322         reinterpret_cast<void**>(&pLocalData)
4323         );
4324
4325     if (NO_ERROR != palError)
4326     {
4327         goto InternalLockFileExit;
4328     }
4329     
4330     if (NULL != pLocalData->pLockController)
4331     {
4332         palError = pLocalData->pLockController->CreateFileLock(
4333             pThread,
4334             dwFileOffsetLow,
4335             dwFileOffsetHigh,
4336             nNumberOfBytesToLockLow,
4337             nNumberOfBytesToLockHigh,
4338             IFileLockController::ExclusiveFileLock,
4339             IFileLockController::FailImmediately
4340             );
4341     }
4342     else
4343     {
4344         //
4345         // This isn't a lockable file (e.g., it may be a pipe)
4346         //
4347         
4348         palError = ERROR_ACCESS_DENIED;
4349         goto InternalLockFileExit;
4350     }
4351
4352 InternalLockFileExit:
4353
4354     if (NULL != pLocalDataLock)
4355     {
4356         pLocalDataLock->ReleaseLock(pThread, FALSE);
4357     }
4358
4359     if (NULL != pFileObject)
4360     {
4361         pFileObject->ReleaseReference(pThread);
4362     }
4363
4364     return palError;
4365 }
4366
4367
4368 /*++
4369 Function:
4370   LockFile
4371
4372 See MSDN doc.
4373 --*/
4374 PALIMPORT
4375 BOOL
4376 PALAPI
4377 LockFile(HANDLE hFile,
4378          DWORD dwFileOffsetLow,
4379          DWORD dwFileOffsetHigh,
4380          DWORD nNumberOfBytesToLockLow,
4381          DWORD nNumberOfBytesToLockHigh)
4382 {
4383     CPalThread *pThread;
4384     PAL_ERROR palError = NO_ERROR;
4385
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);
4390
4391     pThread = InternalGetCurrentThread();
4392
4393     palError = InternalLockFile(
4394         pThread,
4395         hFile,
4396         dwFileOffsetLow,
4397         dwFileOffsetHigh,
4398         nNumberOfBytesToLockLow,
4399         nNumberOfBytesToLockHigh
4400         );
4401
4402     if (NO_ERROR != palError)
4403     {
4404         pThread->SetLastError(palError);
4405     }
4406
4407     LOGEXIT("LockFile returns %s\n", NO_ERROR == palError ? "TRUE":"FALSE");
4408     PERF_EXIT(LockFile);
4409     return NO_ERROR == palError;
4410 }
4411
4412 PAL_ERROR
4413 CorUnix::InternalUnlockFile(
4414     CPalThread *pThread,
4415     HANDLE hFile,
4416     DWORD dwFileOffsetLow,
4417     DWORD dwFileOffsetHigh,
4418     DWORD nNumberOfBytesToUnlockLow,
4419     DWORD nNumberOfBytesToUnlockHigh
4420     )
4421 {
4422     PAL_ERROR palError = NO_ERROR;
4423     IPalObject *pFileObject = NULL;
4424     CFileProcessLocalData *pLocalData = NULL;
4425     IDataLock *pLocalDataLock = NULL;
4426
4427     if (INVALID_HANDLE_VALUE == hFile)
4428     {
4429         ERROR( "Invalid file handle\n" );
4430         palError = ERROR_INVALID_HANDLE;
4431         goto InternalUnlockFileExit;
4432     }
4433
4434     palError = g_pObjectManager->ReferenceObjectByHandle(
4435         pThread,
4436         hFile,
4437         &aotFile,
4438         GENERIC_READ,
4439         &pFileObject
4440         );
4441
4442     if (NO_ERROR != palError)
4443     {
4444         goto InternalUnlockFileExit;
4445     }
4446
4447     palError = pFileObject->GetProcessLocalData(
4448         pThread,
4449         ReadLock, 
4450         &pLocalDataLock,
4451         reinterpret_cast<void**>(&pLocalData)
4452         );
4453
4454     if (NO_ERROR != palError)
4455     {
4456         goto InternalUnlockFileExit;
4457     }
4458     
4459     if (NULL != pLocalData->pLockController)
4460     {
4461         palError = pLocalData->pLockController->ReleaseFileLock(
4462             pThread,
4463             dwFileOffsetLow,
4464             dwFileOffsetHigh,
4465             nNumberOfBytesToUnlockLow,
4466             nNumberOfBytesToUnlockHigh
4467             );
4468     }
4469     else
4470     {
4471         //
4472         // This isn't a lockable file (e.g., it may be a pipe)
4473         //
4474         
4475         palError = ERROR_ACCESS_DENIED;
4476         goto InternalUnlockFileExit;
4477     }
4478
4479 InternalUnlockFileExit:
4480
4481     if (NULL != pLocalDataLock)
4482     {
4483         pLocalDataLock->ReleaseLock(pThread, FALSE);
4484     }
4485
4486     if (NULL != pFileObject)
4487     {
4488         pFileObject->ReleaseReference(pThread);
4489     }
4490
4491     return palError;
4492 }
4493
4494 /*++
4495 Function:
4496   UnlockFile
4497
4498 See MSDN doc.
4499 --*/
4500 PALIMPORT
4501 BOOL
4502 PALAPI
4503 UnlockFile(HANDLE hFile,
4504            DWORD dwFileOffsetLow,
4505            DWORD dwFileOffsetHigh,
4506            DWORD nNumberOfBytesToUnlockLow,
4507            DWORD nNumberOfBytesToUnlockHigh)
4508 {
4509     CPalThread *pThread;
4510     PAL_ERROR palError = NO_ERROR;
4511
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);
4516
4517     pThread = InternalGetCurrentThread();
4518
4519     palError = InternalUnlockFile(
4520         pThread,
4521         hFile,
4522         dwFileOffsetLow,
4523         dwFileOffsetHigh,
4524         nNumberOfBytesToUnlockLow,
4525         nNumberOfBytesToUnlockHigh
4526         );
4527
4528     if (NO_ERROR != palError)
4529     {
4530         pThread->SetLastError(palError);
4531     }
4532
4533     LOGEXIT("UnlockFile returns %s\n", NO_ERROR == palError ? "TRUE" : "FALSE");
4534     PERF_EXIT(UnlockFile);
4535     return NO_ERROR == palError;
4536 }
4537
4538 /*++
4539 init_std_handle [static]
4540
4541 utility function for FILEInitStdHandles. do the work that is common to all 
4542 three standard handles
4543
4544 Parameters:
4545     HANDLE pStd : Defines which standard handle to assign
4546     FILE *stream        : file stream to associate to handle
4547
4548 Return value:
4549     handle for specified stream, or INVALID_HANDLE_VALUE on failure
4550 --*/
4551 static HANDLE init_std_handle(HANDLE * pStd, FILE *stream)
4552 {
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;
4561
4562     HANDLE hFile = INVALID_HANDLE_VALUE;
4563     int new_fd = -1;
4564
4565     /* duplicate the FILE *, so that we can fclose() in FILECloseHandle without
4566        closing the original */
4567     new_fd = dup(fileno(stream));
4568     if(-1 == new_fd)
4569     {
4570         ERROR("dup() failed; errno is %d (%s)\n", errno, strerror(errno));
4571         goto done;
4572     }
4573
4574     palError = g_pObjectManager->AllocateObject(
4575         pThread,
4576         &otFile,
4577         &oa,
4578         &pFileObject
4579         );
4580
4581     if (NO_ERROR != palError)
4582     {
4583         goto done;
4584     }
4585
4586     palError = pFileObject->GetProcessLocalData(
4587         pThread,
4588         WriteLock,
4589         &pDataLock,
4590         reinterpret_cast<void**>(&pLocalData)
4591         );
4592
4593     if (NO_ERROR != palError)
4594     {
4595         goto done;
4596     }
4597
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;
4603
4604     //
4605     // Transfer the lock controller reference from our local variable
4606     // to the local file data
4607     //
4608
4609     pLocalData->pLockController = pLockController;
4610     pLockController = NULL;
4611
4612     //
4613     // We've finished initializing our local data, so release that lock
4614     //
4615
4616     pDataLock->ReleaseLock(pThread, TRUE);
4617     pDataLock = NULL;
4618
4619     palError = g_pObjectManager->RegisterObject(
4620         pThread,
4621         pFileObject,
4622         &aotFile, 
4623         0,
4624         &hFile,
4625         &pRegisteredFile
4626         );
4627
4628     //
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.
4632     //
4633
4634     pFileObject = NULL;
4635
4636 done:
4637
4638     if (NULL != pLockController)
4639     {
4640         pLockController->ReleaseController();
4641     }
4642
4643     if (NULL != pDataLock)
4644     {
4645         pDataLock->ReleaseLock(pThread, TRUE);
4646     }
4647
4648     if (NULL != pFileObject)
4649     {
4650         pFileObject->ReleaseReference(pThread);
4651     }
4652
4653     if (NULL != pRegisteredFile)
4654     {
4655         pRegisteredFile->ReleaseReference(pThread);
4656     }
4657
4658     if (NO_ERROR == palError)
4659     {
4660         *pStd = hFile;
4661     }
4662     else if (-1 != new_fd)
4663     {
4664         close(new_fd);
4665     }
4666
4667     return hFile;
4668 }
4669
4670
4671 /*++
4672 FILEInitStdHandles
4673
4674 Create handle objects for stdin, stdout and stderr
4675
4676 (no parameters)
4677
4678 Return value:
4679     TRUE on success, FALSE on failure
4680 --*/
4681 BOOL FILEInitStdHandles(void)
4682 {
4683     HANDLE stdin_handle;
4684     HANDLE stdout_handle;
4685     HANDLE stderr_handle;
4686
4687     TRACE("creating handle objects for stdin, stdout, stderr\n");
4688
4689     stdin_handle = init_std_handle(&pStdIn, stdin);
4690     if(INVALID_HANDLE_VALUE == stdin_handle)
4691     {
4692         ERROR("failed to create stdin handle\n");
4693         goto fail;
4694     }
4695
4696     stdout_handle = init_std_handle(&pStdOut, stdout);
4697     if(INVALID_HANDLE_VALUE == stdout_handle)
4698     {
4699         ERROR("failed to create stdout handle\n");
4700         CloseHandle(stdin_handle);
4701         goto fail;
4702     }
4703
4704     stderr_handle = init_std_handle(&pStdErr, stderr);
4705     if(INVALID_HANDLE_VALUE == stderr_handle)
4706     {
4707         ERROR("failed to create stderr handle\n");
4708         CloseHandle(stdin_handle);
4709         CloseHandle(stdout_handle);
4710         goto fail;
4711     }
4712     return TRUE;
4713
4714 fail:
4715     pStdIn = INVALID_HANDLE_VALUE;
4716     pStdOut = INVALID_HANDLE_VALUE;
4717     pStdErr = INVALID_HANDLE_VALUE;
4718     return FALSE;
4719 }
4720
4721 /*++
4722 FILECleanupStdHandles
4723
4724 Remove all regions, locked by a file pointer, from shared memory
4725
4726 (no parameters)
4727
4728 --*/
4729 void FILECleanupStdHandles(void)
4730 {
4731     HANDLE stdin_handle;
4732     HANDLE stdout_handle;
4733     HANDLE stderr_handle;
4734
4735     TRACE("closing standard handles\n");
4736     stdin_handle = pStdIn;
4737     stdout_handle = pStdOut;
4738     stderr_handle = pStdErr;
4739
4740     pStdIn = INVALID_HANDLE_VALUE;
4741     pStdOut = INVALID_HANDLE_VALUE;
4742     pStdErr = INVALID_HANDLE_VALUE;
4743
4744     if (stdin_handle != INVALID_HANDLE_VALUE)
4745     {
4746         CloseHandle(stdin_handle);
4747     }
4748
4749     if (stdout_handle != INVALID_HANDLE_VALUE)
4750     {
4751         CloseHandle(stdout_handle);
4752     }
4753
4754     if (stderr_handle != INVALID_HANDLE_VALUE)
4755     {
4756         CloseHandle(stderr_handle);
4757     }
4758 }
4759
4760 /*++
4761 Function:
4762   GetFileInformationByHandle
4763
4764 See MSDN doc.
4765 --*/
4766 BOOL
4767 PALAPI
4768 GetFileInformationByHandle(
4769              IN HANDLE hFile,
4770              OUT LPBY_HANDLE_FILE_INFORMATION lpFileInformation)
4771 {
4772     CPalThread *pThread;
4773     BOOL bRet = FALSE;
4774     DWORD dwLastError = 0;
4775
4776     IPalObject *pFileObject = NULL;
4777     CFileProcessLocalData *pLocalData = NULL;
4778     IDataLock *pLocalDataLock = NULL;
4779
4780     DWORD dwAttr = 0;
4781     struct stat stat_data;
4782
4783     PERF_ENTRY(GetFileInformationByHandle);
4784     ENTRY("GetFileInformationByHandle(hFile=%p, lpFileInformation=%p)\n",
4785           hFile, lpFileInformation);
4786
4787     pThread = InternalGetCurrentThread();
4788
4789     if (INVALID_HANDLE_VALUE == hFile)
4790     {
4791         ERROR( "Invalid file handle\n" );
4792         dwLastError = ERROR_INVALID_HANDLE;
4793         goto done;
4794     }
4795
4796     dwLastError = g_pObjectManager->ReferenceObjectByHandle(
4797         pThread,
4798         hFile,
4799         &aotFile,
4800         GENERIC_READ,
4801         &pFileObject
4802         );
4803
4804     if (NO_ERROR != dwLastError)
4805     {
4806         goto done;
4807     }
4808     
4809     dwLastError = pFileObject->GetProcessLocalData(
4810         pThread,
4811         ReadLock, 
4812         &pLocalDataLock,
4813         reinterpret_cast<void**>(&pLocalData)
4814         );
4815
4816     if (NO_ERROR != dwLastError)
4817     {
4818         goto done;
4819     }
4820
4821     if ( fstat(pLocalData->unix_fd, &stat_data) != 0 )
4822     {
4823         if ((dwLastError = FILEGetLastErrorFromErrno()) == ERROR_INTERNAL_ERROR)
4824         {
4825             ASSERT("fstat() not expected to fail with errno:%d (%s)\n",
4826                    errno, strerror(errno));
4827         }
4828         goto done;
4829     }
4830
4831     if ( (stat_data.st_mode & S_IFMT) == S_IFDIR )
4832     {
4833         dwAttr |= FILE_ATTRIBUTE_DIRECTORY;
4834     }
4835     else if ( (stat_data.st_mode & S_IFMT) != S_IFREG )
4836     {
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;
4840         goto done;
4841     }
4842
4843     if ( UTIL_IsReadOnlyBitsSet( &stat_data ) )
4844     {
4845         dwAttr |= FILE_ATTRIBUTE_READONLY;
4846     }
4847
4848     /* finally, if nothing is set... */
4849     if ( dwAttr == 0 )
4850     {
4851         dwAttr = FILE_ATTRIBUTE_NORMAL;
4852     }
4853
4854     lpFileInformation->dwFileAttributes = dwAttr;
4855
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) );
4866
4867     lpFileInformation->dwVolumeSerialNumber = stat_data.st_dev;
4868
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);
4874 #else
4875     lpFileInformation->nFileSizeHigh = 0;
4876 #endif
4877
4878     lpFileInformation->nNumberOfLinks = stat_data.st_nlink;
4879     lpFileInformation->nFileIndexHigh = 0;
4880     lpFileInformation->nFileIndexLow = stat_data.st_ino;
4881
4882     bRet = TRUE;
4883
4884 done:
4885     if (NULL != pLocalDataLock)
4886     {
4887         pLocalDataLock->ReleaseLock(pThread, FALSE);
4888     }
4889
4890     if (NULL != pFileObject)
4891     {
4892         pFileObject->ReleaseReference(pThread);
4893     }
4894
4895     if (dwLastError) pThread->SetLastError(dwLastError);
4896
4897     LOGEXIT("GetFileInformationByHandle returns BOOL %d\n", bRet);
4898     PERF_EXIT(GetFileInformationByHandle);
4899     return bRet;
4900 }