Use the standard CreateThread routine to create 16-bit tasks instead
[wine.git] / files / file.c
blob38d455bf9cb9d06ef305294e270f0fdaacf5895c
1 /*
2 * File handling functions
4 * Copyright 1993 John Burton
5 * Copyright 1996 Alexandre Julliard
7 * TODO:
8 * Fix the CopyFileEx methods to implement the "extended" functionality.
9 * Right now, they simply call the CopyFile method.
12 #include "config.h"
14 #include <assert.h>
15 #include <ctype.h>
16 #include <errno.h>
17 #include <fcntl.h>
18 #include <stdlib.h>
19 #include <stdio.h>
20 #include <string.h>
21 #ifdef HAVE_SYS_ERRNO_H
22 #include <sys/errno.h>
23 #endif
24 #include <sys/types.h>
25 #include <sys/stat.h>
26 #ifdef HAVE_SYS_MMAN_H
27 #include <sys/mman.h>
28 #endif
29 #include <sys/time.h>
30 #include <time.h>
31 #include <unistd.h>
32 #include <utime.h>
34 #include "winerror.h"
35 #include "windef.h"
36 #include "winbase.h"
37 #include "wine/winbase16.h"
38 #include "wine/port.h"
39 #include "drive.h"
40 #include "file.h"
41 #include "heap.h"
42 #include "msdos.h"
43 #include "wincon.h"
44 #include "debugtools.h"
46 #include "server.h"
48 DEFAULT_DEBUG_CHANNEL(file);
50 #if defined(MAP_ANONYMOUS) && !defined(MAP_ANON)
51 #define MAP_ANON MAP_ANONYMOUS
52 #endif
54 /* Size of per-process table of DOS handles */
55 #define DOS_TABLE_SIZE 256
57 static HANDLE dos_handles[DOS_TABLE_SIZE];
60 /***********************************************************************
61 * FILE_ConvertOFMode
63 * Convert OF_* mode into flags for CreateFile.
65 static void FILE_ConvertOFMode( INT mode, DWORD *access, DWORD *sharing )
67 switch(mode & 0x03)
69 case OF_READ: *access = GENERIC_READ; break;
70 case OF_WRITE: *access = GENERIC_WRITE; break;
71 case OF_READWRITE: *access = GENERIC_READ | GENERIC_WRITE; break;
72 default: *access = 0; break;
74 switch(mode & 0x70)
76 case OF_SHARE_EXCLUSIVE: *sharing = 0; break;
77 case OF_SHARE_DENY_WRITE: *sharing = FILE_SHARE_READ; break;
78 case OF_SHARE_DENY_READ: *sharing = FILE_SHARE_WRITE; break;
79 case OF_SHARE_DENY_NONE:
80 case OF_SHARE_COMPAT:
81 default: *sharing = FILE_SHARE_READ | FILE_SHARE_WRITE; break;
86 /***********************************************************************
87 * FILE_strcasecmp
89 * locale-independent case conversion for file I/O
91 int FILE_strcasecmp( const char *str1, const char *str2 )
93 for (;;)
95 int ret = FILE_toupper(*str1) - FILE_toupper(*str2);
96 if (ret || !*str1) return ret;
97 str1++;
98 str2++;
103 /***********************************************************************
104 * FILE_strncasecmp
106 * locale-independent case conversion for file I/O
108 int FILE_strncasecmp( const char *str1, const char *str2, int len )
110 int ret = 0;
111 for ( ; len > 0; len--, str1++, str2++)
112 if ((ret = FILE_toupper(*str1) - FILE_toupper(*str2)) || !*str1) break;
113 return ret;
117 /***********************************************************************
118 * FILE_SetDosError
120 * Set the DOS error code from errno.
122 void FILE_SetDosError(void)
124 int save_errno = errno; /* errno gets overwritten by printf */
126 TRACE("errno = %d %s\n", errno, strerror(errno));
127 switch (save_errno)
129 case EAGAIN:
130 SetLastError( ERROR_SHARING_VIOLATION );
131 break;
132 case EBADF:
133 SetLastError( ERROR_INVALID_HANDLE );
134 break;
135 case ENOSPC:
136 SetLastError( ERROR_HANDLE_DISK_FULL );
137 break;
138 case EACCES:
139 case EPERM:
140 case EROFS:
141 SetLastError( ERROR_ACCESS_DENIED );
142 break;
143 case EBUSY:
144 SetLastError( ERROR_LOCK_VIOLATION );
145 break;
146 case ENOENT:
147 SetLastError( ERROR_FILE_NOT_FOUND );
148 break;
149 case EISDIR:
150 SetLastError( ERROR_CANNOT_MAKE );
151 break;
152 case ENFILE:
153 case EMFILE:
154 SetLastError( ERROR_NO_MORE_FILES );
155 break;
156 case EEXIST:
157 SetLastError( ERROR_FILE_EXISTS );
158 break;
159 case EINVAL:
160 case ESPIPE:
161 SetLastError( ERROR_SEEK );
162 break;
163 case ENOTEMPTY:
164 SetLastError( ERROR_DIR_NOT_EMPTY );
165 break;
166 case ENOEXEC:
167 SetLastError( ERROR_BAD_FORMAT );
168 break;
169 default:
170 WARN("unknown file error: %s\n", strerror(save_errno) );
171 SetLastError( ERROR_GEN_FAILURE );
172 break;
174 errno = save_errno;
178 /***********************************************************************
179 * FILE_DupUnixHandle
181 * Duplicate a Unix handle into a task handle.
182 * Returns 0 on failure.
184 HANDLE FILE_DupUnixHandle( int fd, DWORD access )
186 HANDLE ret;
187 SERVER_START_REQ( alloc_file_handle )
189 req->access = access;
190 SERVER_CALL_FD( fd );
191 ret = req->handle;
193 SERVER_END_REQ;
194 return ret;
198 /***********************************************************************
199 * FILE_GetUnixHandle
201 * Retrieve the Unix handle corresponding to a file handle.
202 * Returns -1 on failure.
204 int FILE_GetUnixHandle( HANDLE handle, DWORD access )
206 int ret, fd = -1;
207 SERVER_START_REQ( get_handle_fd )
209 req->handle = handle;
210 req->access = access;
211 if (!(ret = SERVER_CALL_ERR())) fd = req->fd;
213 SERVER_END_REQ;
214 if (!ret)
216 if (fd == -1) return wine_server_recv_fd( handle, 1 );
217 fd = dup(fd);
219 return fd;
223 /*************************************************************************
224 * FILE_OpenConsole
226 * Open a handle to the current process console.
227 * Returns 0 on failure.
229 static HANDLE FILE_OpenConsole( BOOL output, DWORD access, LPSECURITY_ATTRIBUTES sa )
231 HANDLE ret;
233 SERVER_START_REQ( open_console )
235 req->output = output;
236 req->access = access;
237 req->inherit = (sa && (sa->nLength>=sizeof(*sa)) && sa->bInheritHandle);
238 SetLastError(0);
239 SERVER_CALL_ERR();
240 ret = req->handle;
242 SERVER_END_REQ;
243 return ret;
247 /***********************************************************************
248 * FILE_CreateFile
250 * Implementation of CreateFile. Takes a Unix path name.
251 * Returns 0 on failure.
253 HANDLE FILE_CreateFile( LPCSTR filename, DWORD access, DWORD sharing,
254 LPSECURITY_ATTRIBUTES sa, DWORD creation,
255 DWORD attributes, HANDLE template, BOOL fail_read_only )
257 DWORD err;
258 HANDLE ret;
259 size_t len = strlen(filename);
261 if (len > REQUEST_MAX_VAR_SIZE)
263 FIXME("filename '%s' too long\n", filename );
264 SetLastError( ERROR_INVALID_PARAMETER );
265 return 0;
268 restart:
269 SERVER_START_VAR_REQ( create_file, len )
271 req->access = access;
272 req->inherit = (sa && (sa->nLength>=sizeof(*sa)) && sa->bInheritHandle);
273 req->sharing = sharing;
274 req->create = creation;
275 req->attrs = attributes;
276 memcpy( server_data_ptr(req), filename, len );
277 SetLastError(0);
278 err = SERVER_CALL();
279 ret = req->handle;
281 SERVER_END_VAR_REQ;
283 /* If write access failed, retry without GENERIC_WRITE */
285 if (!ret && !fail_read_only && (access & GENERIC_WRITE))
287 if ((err == STATUS_MEDIA_WRITE_PROTECTED) || (err == STATUS_ACCESS_DENIED))
289 TRACE("Write access failed for file '%s', trying without "
290 "write access\n", filename);
291 access &= ~GENERIC_WRITE;
292 goto restart;
296 if (err) SetLastError( RtlNtStatusToDosError(err) );
298 if (!ret)
299 WARN("Unable to create file '%s' (GLE %ld)\n", filename, GetLastError());
301 return ret;
305 /***********************************************************************
306 * FILE_CreateDevice
308 * Same as FILE_CreateFile but for a device
309 * Returns 0 on failure.
311 HANDLE FILE_CreateDevice( int client_id, DWORD access, LPSECURITY_ATTRIBUTES sa )
313 HANDLE ret;
314 SERVER_START_REQ( create_device )
316 req->access = access;
317 req->inherit = (sa && (sa->nLength>=sizeof(*sa)) && sa->bInheritHandle);
318 req->id = client_id;
319 SetLastError(0);
320 SERVER_CALL_ERR();
321 ret = req->handle;
323 SERVER_END_REQ;
324 return ret;
328 /*************************************************************************
329 * CreateFileA [KERNEL32.45] Creates or opens a file or other object
331 * Creates or opens an object, and returns a handle that can be used to
332 * access that object.
334 * PARAMS
336 * filename [in] pointer to filename to be accessed
337 * access [in] access mode requested
338 * sharing [in] share mode
339 * sa [in] pointer to security attributes
340 * creation [in] how to create the file
341 * attributes [in] attributes for newly created file
342 * template [in] handle to file with extended attributes to copy
344 * RETURNS
345 * Success: Open handle to specified file
346 * Failure: INVALID_HANDLE_VALUE
348 * NOTES
349 * Should call SetLastError() on failure.
351 * BUGS
353 * Doesn't support character devices, pipes, template files, or a
354 * lot of the 'attributes' flags yet.
356 HANDLE WINAPI CreateFileA( LPCSTR filename, DWORD access, DWORD sharing,
357 LPSECURITY_ATTRIBUTES sa, DWORD creation,
358 DWORD attributes, HANDLE template )
360 DOS_FULL_NAME full_name;
361 HANDLE ret;
363 if (!filename)
365 SetLastError( ERROR_INVALID_PARAMETER );
366 return INVALID_HANDLE_VALUE;
368 TRACE("%s %s%s%s%s%s%s%s\n",filename,
369 ((access & GENERIC_READ)==GENERIC_READ)?"GENERIC_READ ":"",
370 ((access & GENERIC_WRITE)==GENERIC_WRITE)?"GENERIC_WRITE ":"",
371 (!access)?"QUERY_ACCESS ":"",
372 ((sharing & FILE_SHARE_READ)==FILE_SHARE_READ)?"FILE_SHARE_READ ":"",
373 ((sharing & FILE_SHARE_WRITE)==FILE_SHARE_WRITE)?"FILE_SHARE_WRITE ":"",
374 ((sharing & FILE_SHARE_DELETE)==FILE_SHARE_DELETE)?"FILE_SHARE_DELETE ":"",
375 (creation ==CREATE_NEW)?"CREATE_NEW":
376 (creation ==CREATE_ALWAYS)?"CREATE_ALWAYS ":
377 (creation ==OPEN_EXISTING)?"OPEN_EXISTING ":
378 (creation ==OPEN_ALWAYS)?"OPEN_ALWAYS ":
379 (creation ==TRUNCATE_EXISTING)?"TRUNCATE_EXISTING ":"");
381 /* If the name starts with '\\?\', ignore the first 4 chars. */
382 if (!strncmp(filename, "\\\\?\\", 4))
384 filename += 4;
385 if (!strncmp(filename, "UNC\\", 4))
387 FIXME("UNC name (%s) not supported.\n", filename );
388 SetLastError( ERROR_PATH_NOT_FOUND );
389 return INVALID_HANDLE_VALUE;
393 if (!strncmp(filename, "\\\\.\\", 4)) {
394 if (!DOSFS_GetDevice( filename ))
396 ret = DEVICE_Open( filename+4, access, sa );
397 goto done;
399 else
400 filename+=4; /* fall into DOSFS_Device case below */
403 /* If the name still starts with '\\', it's a UNC name. */
404 if (!strncmp(filename, "\\\\", 2))
406 FIXME("UNC name (%s) not supported.\n", filename );
407 SetLastError( ERROR_PATH_NOT_FOUND );
408 return INVALID_HANDLE_VALUE;
411 /* If the name contains a DOS wild card (* or ?), do no create a file */
412 if(strchr(filename,'*') || strchr(filename,'?'))
413 return INVALID_HANDLE_VALUE;
415 /* Open a console for CONIN$ or CONOUT$ */
416 if (!strcasecmp(filename, "CONIN$"))
418 ret = FILE_OpenConsole( FALSE, access, sa );
419 goto done;
421 if (!strcasecmp(filename, "CONOUT$"))
423 ret = FILE_OpenConsole( TRUE, access, sa );
424 goto done;
427 if (DOSFS_GetDevice( filename ))
429 TRACE("opening device '%s'\n", filename );
431 if (!(ret = DOSFS_OpenDevice( filename, access )))
433 /* Do not silence this please. It is a critical error. -MM */
434 ERR("Couldn't open device '%s'!\n",filename);
435 SetLastError( ERROR_FILE_NOT_FOUND );
437 goto done;
440 /* check for filename, don't check for last entry if creating */
441 if (!DOSFS_GetFullName( filename,
442 (creation == OPEN_EXISTING) ||
443 (creation == TRUNCATE_EXISTING),
444 &full_name )) {
445 WARN("Unable to get full filename from '%s' (GLE %ld)\n",
446 filename, GetLastError());
447 return INVALID_HANDLE_VALUE;
450 ret = FILE_CreateFile( full_name.long_name, access, sharing,
451 sa, creation, attributes, template,
452 DRIVE_GetFlags(full_name.drive) & DRIVE_FAIL_READ_ONLY );
453 done:
454 if (!ret) ret = INVALID_HANDLE_VALUE;
455 return ret;
460 /*************************************************************************
461 * CreateFileW (KERNEL32.48)
463 HANDLE WINAPI CreateFileW( LPCWSTR filename, DWORD access, DWORD sharing,
464 LPSECURITY_ATTRIBUTES sa, DWORD creation,
465 DWORD attributes, HANDLE template)
467 LPSTR afn = HEAP_strdupWtoA( GetProcessHeap(), 0, filename );
468 HANDLE res = CreateFileA( afn, access, sharing, sa, creation, attributes, template );
469 HeapFree( GetProcessHeap(), 0, afn );
470 return res;
474 /***********************************************************************
475 * FILE_FillInfo
477 * Fill a file information from a struct stat.
479 static void FILE_FillInfo( struct stat *st, BY_HANDLE_FILE_INFORMATION *info )
481 if (S_ISDIR(st->st_mode))
482 info->dwFileAttributes = FILE_ATTRIBUTE_DIRECTORY;
483 else
484 info->dwFileAttributes = FILE_ATTRIBUTE_ARCHIVE;
485 if (!(st->st_mode & S_IWUSR))
486 info->dwFileAttributes |= FILE_ATTRIBUTE_READONLY;
488 RtlSecondsSince1970ToTime( st->st_mtime, &info->ftCreationTime );
489 RtlSecondsSince1970ToTime( st->st_mtime, &info->ftLastWriteTime );
490 RtlSecondsSince1970ToTime( st->st_atime, &info->ftLastAccessTime );
492 info->dwVolumeSerialNumber = 0; /* FIXME */
493 info->nFileSizeHigh = 0;
494 info->nFileSizeLow = S_ISDIR(st->st_mode) ? 0 : st->st_size;
495 info->nNumberOfLinks = st->st_nlink;
496 info->nFileIndexHigh = 0;
497 info->nFileIndexLow = st->st_ino;
501 /***********************************************************************
502 * FILE_Stat
504 * Stat a Unix path name. Return TRUE if OK.
506 BOOL FILE_Stat( LPCSTR unixName, BY_HANDLE_FILE_INFORMATION *info )
508 struct stat st;
510 if (lstat( unixName, &st ) == -1)
512 FILE_SetDosError();
513 return FALSE;
515 if (!S_ISLNK(st.st_mode)) FILE_FillInfo( &st, info );
516 else
518 /* do a "real" stat to find out
519 about the type of the symlink destination */
520 if (stat( unixName, &st ) == -1)
522 FILE_SetDosError();
523 return FALSE;
525 FILE_FillInfo( &st, info );
526 info->dwFileAttributes |= FILE_ATTRIBUTE_SYMLINK;
528 return TRUE;
532 /***********************************************************************
533 * GetFileInformationByHandle (KERNEL32.219)
535 DWORD WINAPI GetFileInformationByHandle( HANDLE hFile,
536 BY_HANDLE_FILE_INFORMATION *info )
538 DWORD ret;
539 if (!info) return 0;
541 SERVER_START_REQ( get_file_info )
543 req->handle = hFile;
544 if ((ret = !SERVER_CALL_ERR()))
546 RtlSecondsSince1970ToTime( req->write_time, &info->ftCreationTime );
547 RtlSecondsSince1970ToTime( req->write_time, &info->ftLastWriteTime );
548 RtlSecondsSince1970ToTime( req->access_time, &info->ftLastAccessTime );
549 info->dwFileAttributes = req->attr;
550 info->dwVolumeSerialNumber = req->serial;
551 info->nFileSizeHigh = req->size_high;
552 info->nFileSizeLow = req->size_low;
553 info->nNumberOfLinks = req->links;
554 info->nFileIndexHigh = req->index_high;
555 info->nFileIndexLow = req->index_low;
558 SERVER_END_REQ;
559 return ret;
563 /**************************************************************************
564 * GetFileAttributes16 (KERNEL.420)
566 DWORD WINAPI GetFileAttributes16( LPCSTR name )
568 return GetFileAttributesA( name );
572 /**************************************************************************
573 * GetFileAttributesA (KERNEL32.217)
575 DWORD WINAPI GetFileAttributesA( LPCSTR name )
577 DOS_FULL_NAME full_name;
578 BY_HANDLE_FILE_INFORMATION info;
580 if (name == NULL)
582 SetLastError( ERROR_INVALID_PARAMETER );
583 return -1;
585 if (!DOSFS_GetFullName( name, TRUE, &full_name) )
586 return -1;
587 if (!FILE_Stat( full_name.long_name, &info )) return -1;
588 return info.dwFileAttributes;
592 /**************************************************************************
593 * GetFileAttributesW (KERNEL32.218)
595 DWORD WINAPI GetFileAttributesW( LPCWSTR name )
597 LPSTR nameA = HEAP_strdupWtoA( GetProcessHeap(), 0, name );
598 DWORD res = GetFileAttributesA( nameA );
599 HeapFree( GetProcessHeap(), 0, nameA );
600 return res;
604 /***********************************************************************
605 * GetFileSize (KERNEL32.220)
607 DWORD WINAPI GetFileSize( HANDLE hFile, LPDWORD filesizehigh )
609 BY_HANDLE_FILE_INFORMATION info;
610 if (!GetFileInformationByHandle( hFile, &info )) return 0;
611 if (filesizehigh) *filesizehigh = info.nFileSizeHigh;
612 return info.nFileSizeLow;
616 /***********************************************************************
617 * GetFileTime (KERNEL32.221)
619 BOOL WINAPI GetFileTime( HANDLE hFile, FILETIME *lpCreationTime,
620 FILETIME *lpLastAccessTime,
621 FILETIME *lpLastWriteTime )
623 BY_HANDLE_FILE_INFORMATION info;
624 if (!GetFileInformationByHandle( hFile, &info )) return FALSE;
625 if (lpCreationTime) *lpCreationTime = info.ftCreationTime;
626 if (lpLastAccessTime) *lpLastAccessTime = info.ftLastAccessTime;
627 if (lpLastWriteTime) *lpLastWriteTime = info.ftLastWriteTime;
628 return TRUE;
631 /***********************************************************************
632 * CompareFileTime (KERNEL32.28)
634 INT WINAPI CompareFileTime( LPFILETIME x, LPFILETIME y )
636 if (!x || !y) return -1;
638 if (x->dwHighDateTime > y->dwHighDateTime)
639 return 1;
640 if (x->dwHighDateTime < y->dwHighDateTime)
641 return -1;
642 if (x->dwLowDateTime > y->dwLowDateTime)
643 return 1;
644 if (x->dwLowDateTime < y->dwLowDateTime)
645 return -1;
646 return 0;
649 /***********************************************************************
650 * FILE_GetTempFileName : utility for GetTempFileName
652 static UINT FILE_GetTempFileName( LPCSTR path, LPCSTR prefix, UINT unique,
653 LPSTR buffer, BOOL isWin16 )
655 static UINT unique_temp;
656 DOS_FULL_NAME full_name;
657 int i;
658 LPSTR p;
659 UINT num;
661 if ( !path || !prefix || !buffer ) return 0;
663 if (!unique_temp) unique_temp = time(NULL) & 0xffff;
664 num = unique ? (unique & 0xffff) : (unique_temp++ & 0xffff);
666 strcpy( buffer, path );
667 p = buffer + strlen(buffer);
669 /* add a \, if there isn't one and path is more than just the drive letter ... */
670 if ( !((strlen(buffer) == 2) && (buffer[1] == ':'))
671 && ((p == buffer) || (p[-1] != '\\'))) *p++ = '\\';
673 if (isWin16) *p++ = '~';
674 for (i = 3; (i > 0) && (*prefix); i--) *p++ = *prefix++;
675 sprintf( p, "%04x.tmp", num );
677 /* Now try to create it */
679 if (!unique)
683 HFILE handle = CreateFileA( buffer, GENERIC_WRITE, 0, NULL,
684 CREATE_NEW, FILE_ATTRIBUTE_NORMAL, 0 );
685 if (handle != INVALID_HANDLE_VALUE)
686 { /* We created it */
687 TRACE("created %s\n",
688 buffer);
689 CloseHandle( handle );
690 break;
692 if (GetLastError() != ERROR_FILE_EXISTS)
693 break; /* No need to go on */
694 num++;
695 sprintf( p, "%04x.tmp", num );
696 } while (num != (unique & 0xffff));
699 /* Get the full path name */
701 if (DOSFS_GetFullName( buffer, FALSE, &full_name ))
703 /* Check if we have write access in the directory */
704 if ((p = strrchr( full_name.long_name, '/' ))) *p = '\0';
705 if (access( full_name.long_name, W_OK ) == -1)
706 WARN("returns '%s', which doesn't seem to be writeable.\n",
707 buffer);
709 TRACE("returning %s\n", buffer );
710 return unique ? unique : num;
714 /***********************************************************************
715 * GetTempFileNameA (KERNEL32.290)
717 UINT WINAPI GetTempFileNameA( LPCSTR path, LPCSTR prefix, UINT unique,
718 LPSTR buffer)
720 return FILE_GetTempFileName(path, prefix, unique, buffer, FALSE);
723 /***********************************************************************
724 * GetTempFileNameW (KERNEL32.291)
726 UINT WINAPI GetTempFileNameW( LPCWSTR path, LPCWSTR prefix, UINT unique,
727 LPWSTR buffer )
729 LPSTR patha,prefixa;
730 char buffera[144];
731 UINT ret;
733 if (!path) return 0;
734 patha = HEAP_strdupWtoA( GetProcessHeap(), 0, path );
735 prefixa = HEAP_strdupWtoA( GetProcessHeap(), 0, prefix );
736 ret = FILE_GetTempFileName( patha, prefixa, unique, buffera, FALSE );
737 MultiByteToWideChar( CP_ACP, 0, buffera, -1, buffer, MAX_PATH );
738 HeapFree( GetProcessHeap(), 0, patha );
739 HeapFree( GetProcessHeap(), 0, prefixa );
740 return ret;
744 /***********************************************************************
745 * GetTempFileName16 (KERNEL.97)
747 UINT16 WINAPI GetTempFileName16( BYTE drive, LPCSTR prefix, UINT16 unique,
748 LPSTR buffer )
750 char temppath[144];
752 if (!(drive & ~TF_FORCEDRIVE)) /* drive 0 means current default drive */
753 drive |= DRIVE_GetCurrentDrive() + 'A';
755 if ((drive & TF_FORCEDRIVE) &&
756 !DRIVE_IsValid( toupper(drive & ~TF_FORCEDRIVE) - 'A' ))
758 drive &= ~TF_FORCEDRIVE;
759 WARN("invalid drive %d specified\n", drive );
762 if (drive & TF_FORCEDRIVE)
763 sprintf(temppath,"%c:", drive & ~TF_FORCEDRIVE );
764 else
765 GetTempPathA( 132, temppath );
766 return (UINT16)FILE_GetTempFileName( temppath, prefix, unique, buffer, TRUE );
769 /***********************************************************************
770 * FILE_DoOpenFile
772 * Implementation of OpenFile16() and OpenFile32().
774 static HFILE FILE_DoOpenFile( LPCSTR name, OFSTRUCT *ofs, UINT mode,
775 BOOL win32 )
777 HFILE hFileRet;
778 FILETIME filetime;
779 WORD filedatetime[2];
780 DOS_FULL_NAME full_name;
781 DWORD access, sharing;
782 char *p;
784 if (!ofs) return HFILE_ERROR;
786 TRACE("%s %s %s %s%s%s%s%s%s%s%s%s\n",name,
787 ((mode & 0x3 )==OF_READ)?"OF_READ":
788 ((mode & 0x3 )==OF_WRITE)?"OF_WRITE":
789 ((mode & 0x3 )==OF_READWRITE)?"OF_READWRITE":"unknown",
790 ((mode & 0x70 )==OF_SHARE_COMPAT)?"OF_SHARE_COMPAT":
791 ((mode & 0x70 )==OF_SHARE_DENY_NONE)?"OF_SHARE_DENY_NONE":
792 ((mode & 0x70 )==OF_SHARE_DENY_READ)?"OF_SHARE_DENY_READ":
793 ((mode & 0x70 )==OF_SHARE_DENY_WRITE)?"OF_SHARE_DENY_WRITE":
794 ((mode & 0x70 )==OF_SHARE_EXCLUSIVE)?"OF_SHARE_EXCLUSIVE":"unknown",
795 ((mode & OF_PARSE )==OF_PARSE)?"OF_PARSE ":"",
796 ((mode & OF_DELETE )==OF_DELETE)?"OF_DELETE ":"",
797 ((mode & OF_VERIFY )==OF_VERIFY)?"OF_VERIFY ":"",
798 ((mode & OF_SEARCH )==OF_SEARCH)?"OF_SEARCH ":"",
799 ((mode & OF_CANCEL )==OF_CANCEL)?"OF_CANCEL ":"",
800 ((mode & OF_CREATE )==OF_CREATE)?"OF_CREATE ":"",
801 ((mode & OF_PROMPT )==OF_PROMPT)?"OF_PROMPT ":"",
802 ((mode & OF_EXIST )==OF_EXIST)?"OF_EXIST ":"",
803 ((mode & OF_REOPEN )==OF_REOPEN)?"OF_REOPEN ":""
807 ofs->cBytes = sizeof(OFSTRUCT);
808 ofs->nErrCode = 0;
809 if (mode & OF_REOPEN) name = ofs->szPathName;
811 if (!name) {
812 ERR("called with `name' set to NULL ! Please debug.\n");
813 return HFILE_ERROR;
816 TRACE("%s %04x\n", name, mode );
818 /* the watcom 10.6 IDE relies on a valid path returned in ofs->szPathName
819 Are there any cases where getting the path here is wrong?
820 Uwe Bonnes 1997 Apr 2 */
821 if (!GetFullPathNameA( name, sizeof(ofs->szPathName),
822 ofs->szPathName, NULL )) goto error;
823 FILE_ConvertOFMode( mode, &access, &sharing );
825 /* OF_PARSE simply fills the structure */
827 if (mode & OF_PARSE)
829 ofs->fFixedDisk = (GetDriveType16( ofs->szPathName[0]-'A' )
830 != DRIVE_REMOVABLE);
831 TRACE("(%s): OF_PARSE, res = '%s'\n",
832 name, ofs->szPathName );
833 return 0;
836 /* OF_CREATE is completely different from all other options, so
837 handle it first */
839 if (mode & OF_CREATE)
841 if ((hFileRet = CreateFileA( name, GENERIC_READ | GENERIC_WRITE,
842 sharing, NULL, CREATE_ALWAYS,
843 FILE_ATTRIBUTE_NORMAL, 0 ))== INVALID_HANDLE_VALUE)
844 goto error;
845 goto success;
848 /* If OF_SEARCH is set, ignore the given path */
850 if ((mode & OF_SEARCH) && !(mode & OF_REOPEN))
852 /* First try the file name as is */
853 if (DOSFS_GetFullName( name, TRUE, &full_name )) goto found;
854 /* Now remove the path */
855 if (name[0] && (name[1] == ':')) name += 2;
856 if ((p = strrchr( name, '\\' ))) name = p + 1;
857 if ((p = strrchr( name, '/' ))) name = p + 1;
858 if (!name[0]) goto not_found;
861 /* Now look for the file */
863 if (!DIR_SearchPath( NULL, name, NULL, &full_name, win32 )) goto not_found;
865 found:
866 TRACE("found %s = %s\n",
867 full_name.long_name, full_name.short_name );
868 lstrcpynA( ofs->szPathName, full_name.short_name,
869 sizeof(ofs->szPathName) );
871 if (mode & OF_SHARE_EXCLUSIVE)
872 /* Some InstallShield version uses OF_SHARE_EXCLUSIVE
873 on the file <tempdir>/_ins0432._mp to determine how
874 far installation has proceeded.
875 _ins0432._mp is an executable and while running the
876 application expects the open with OF_SHARE_ to fail*/
877 /* Probable FIXME:
878 As our loader closes the files after loading the executable,
879 we can't find the running executable with FILE_InUse.
880 The loader should keep the file open, as Windows does that, too.
883 char *last = strrchr(full_name.long_name,'/');
884 if (!last)
885 last = full_name.long_name - 1;
886 if (GetModuleHandle16(last+1))
888 TRACE("Denying shared open for %s\n",full_name.long_name);
889 return HFILE_ERROR;
893 if (mode & OF_DELETE)
895 if (unlink( full_name.long_name ) == -1) goto not_found;
896 TRACE("(%s): OF_DELETE return = OK\n", name);
897 return 1;
900 hFileRet = FILE_CreateFile( full_name.long_name, access, sharing,
901 NULL, OPEN_EXISTING, 0, 0,
902 DRIVE_GetFlags(full_name.drive) & DRIVE_FAIL_READ_ONLY );
903 if (!hFileRet) goto not_found;
905 GetFileTime( hFileRet, NULL, NULL, &filetime );
906 FileTimeToDosDateTime( &filetime, &filedatetime[0], &filedatetime[1] );
907 if ((mode & OF_VERIFY) && (mode & OF_REOPEN))
909 if (memcmp( ofs->reserved, filedatetime, sizeof(ofs->reserved) ))
911 CloseHandle( hFileRet );
912 WARN("(%s): OF_VERIFY failed\n", name );
913 /* FIXME: what error here? */
914 SetLastError( ERROR_FILE_NOT_FOUND );
915 goto error;
918 memcpy( ofs->reserved, filedatetime, sizeof(ofs->reserved) );
920 success: /* We get here if the open was successful */
921 TRACE("(%s): OK, return = %d\n", name, hFileRet );
922 if (win32)
924 if (mode & OF_EXIST) /* Return the handle, but close it first */
925 CloseHandle( hFileRet );
927 else
929 hFileRet = Win32HandleToDosFileHandle( hFileRet );
930 if (hFileRet == HFILE_ERROR16) goto error;
931 if (mode & OF_EXIST) /* Return the handle, but close it first */
932 _lclose16( hFileRet );
934 return hFileRet;
936 not_found: /* We get here if the file does not exist */
937 WARN("'%s' not found or sharing violation\n", name );
938 SetLastError( ERROR_FILE_NOT_FOUND );
939 /* fall through */
941 error: /* We get here if there was an error opening the file */
942 ofs->nErrCode = GetLastError();
943 WARN("(%s): return = HFILE_ERROR error= %d\n",
944 name,ofs->nErrCode );
945 return HFILE_ERROR;
949 /***********************************************************************
950 * OpenFile16 (KERNEL.74)
952 HFILE16 WINAPI OpenFile16( LPCSTR name, OFSTRUCT *ofs, UINT16 mode )
954 return FILE_DoOpenFile( name, ofs, mode, FALSE );
958 /***********************************************************************
959 * OpenFile (KERNEL32.396)
961 HFILE WINAPI OpenFile( LPCSTR name, OFSTRUCT *ofs, UINT mode )
963 return FILE_DoOpenFile( name, ofs, mode, TRUE );
967 /***********************************************************************
968 * FILE_InitProcessDosHandles
970 * Allocates the default DOS handles for a process. Called either by
971 * Win32HandleToDosFileHandle below or by the DOSVM stuff.
973 static void FILE_InitProcessDosHandles( void )
975 dos_handles[0] = GetStdHandle(STD_INPUT_HANDLE);
976 dos_handles[1] = GetStdHandle(STD_OUTPUT_HANDLE);
977 dos_handles[2] = GetStdHandle(STD_ERROR_HANDLE);
978 dos_handles[3] = GetStdHandle(STD_ERROR_HANDLE);
979 dos_handles[4] = GetStdHandle(STD_ERROR_HANDLE);
982 /***********************************************************************
983 * Win32HandleToDosFileHandle (KERNEL32.21)
985 * Allocate a DOS handle for a Win32 handle. The Win32 handle is no
986 * longer valid after this function (even on failure).
988 * Note: this is not exactly right, since on Win95 the Win32 handles
989 * are on top of DOS handles and we do it the other way
990 * around. Should be good enough though.
992 HFILE WINAPI Win32HandleToDosFileHandle( HANDLE handle )
994 int i;
996 if (!handle || (handle == INVALID_HANDLE_VALUE))
997 return HFILE_ERROR;
999 for (i = 5; i < DOS_TABLE_SIZE; i++)
1000 if (!dos_handles[i])
1002 dos_handles[i] = handle;
1003 TRACE("Got %d for h32 %d\n", i, handle );
1004 return (HFILE)i;
1006 CloseHandle( handle );
1007 SetLastError( ERROR_TOO_MANY_OPEN_FILES );
1008 return HFILE_ERROR;
1012 /***********************************************************************
1013 * DosFileHandleToWin32Handle (KERNEL32.20)
1015 * Return the Win32 handle for a DOS handle.
1017 * Note: this is not exactly right, since on Win95 the Win32 handles
1018 * are on top of DOS handles and we do it the other way
1019 * around. Should be good enough though.
1021 HANDLE WINAPI DosFileHandleToWin32Handle( HFILE handle )
1023 HFILE16 hfile = (HFILE16)handle;
1024 if (hfile < 5 && !dos_handles[hfile]) FILE_InitProcessDosHandles();
1025 if ((hfile >= DOS_TABLE_SIZE) || !dos_handles[hfile])
1027 SetLastError( ERROR_INVALID_HANDLE );
1028 return INVALID_HANDLE_VALUE;
1030 return dos_handles[hfile];
1034 /***********************************************************************
1035 * DisposeLZ32Handle (KERNEL32.22)
1037 * Note: this is not entirely correct, we should only close the
1038 * 32-bit handle and not the 16-bit one, but we cannot do
1039 * this because of the way our DOS handles are implemented.
1040 * It shouldn't break anything though.
1042 void WINAPI DisposeLZ32Handle( HANDLE handle )
1044 int i;
1046 if (!handle || (handle == INVALID_HANDLE_VALUE)) return;
1048 for (i = 5; i < DOS_TABLE_SIZE; i++)
1049 if (dos_handles[i] == handle)
1051 dos_handles[i] = 0;
1052 CloseHandle( handle );
1053 break;
1058 /***********************************************************************
1059 * FILE_Dup2
1061 * dup2() function for DOS handles.
1063 HFILE16 FILE_Dup2( HFILE16 hFile1, HFILE16 hFile2 )
1065 HANDLE new_handle;
1067 if (hFile1 < 5 && !dos_handles[hFile1]) FILE_InitProcessDosHandles();
1069 if ((hFile1 >= DOS_TABLE_SIZE) || (hFile2 >= DOS_TABLE_SIZE) || !dos_handles[hFile1])
1071 SetLastError( ERROR_INVALID_HANDLE );
1072 return HFILE_ERROR16;
1074 if (hFile2 < 5)
1076 FIXME("stdio handle closed, need proper conversion\n" );
1077 SetLastError( ERROR_INVALID_HANDLE );
1078 return HFILE_ERROR16;
1080 if (!DuplicateHandle( GetCurrentProcess(), dos_handles[hFile1],
1081 GetCurrentProcess(), &new_handle,
1082 0, FALSE, DUPLICATE_SAME_ACCESS ))
1083 return HFILE_ERROR16;
1084 if (dos_handles[hFile2]) CloseHandle( dos_handles[hFile2] );
1085 dos_handles[hFile2] = new_handle;
1086 return hFile2;
1090 /***********************************************************************
1091 * _lclose16 (KERNEL.81)
1093 HFILE16 WINAPI _lclose16( HFILE16 hFile )
1095 if (hFile < 5)
1097 FIXME("stdio handle closed, need proper conversion\n" );
1098 SetLastError( ERROR_INVALID_HANDLE );
1099 return HFILE_ERROR16;
1101 if ((hFile >= DOS_TABLE_SIZE) || !dos_handles[hFile])
1103 SetLastError( ERROR_INVALID_HANDLE );
1104 return HFILE_ERROR16;
1106 TRACE("%d (handle32=%d)\n", hFile, dos_handles[hFile] );
1107 CloseHandle( dos_handles[hFile] );
1108 dos_handles[hFile] = 0;
1109 return 0;
1113 /***********************************************************************
1114 * _lclose (KERNEL32.592)
1116 HFILE WINAPI _lclose( HFILE hFile )
1118 TRACE("handle %d\n", hFile );
1119 return CloseHandle( hFile ) ? 0 : HFILE_ERROR;
1122 /***********************************************************************
1123 * GetOverlappedResult (KERNEL32.360)
1125 * Check the result of an Asynchronous data transfer from a file.
1127 * RETURNS
1128 * TRUE on success
1129 * FALSE on failure
1131 * If successful (and relevant) lpTransfered will hold the number of
1132 * bytes transfered during the async operation.
1134 * BUGS
1136 * Currently only works for WaitCommEvent, ReadFile, WriteFile
1137 * with communications ports.
1140 BOOL WINAPI GetOverlappedResult(
1141 HANDLE hFile, /* [in] handle of file to check on */
1142 LPOVERLAPPED lpOverlapped, /* [in/out] pointer to overlapped */
1143 LPDWORD lpTransferred, /* [in/out] number of bytes transfered */
1144 BOOL bWait /* [in] wait for the transfer to complete ? */
1146 DWORD r;
1148 TRACE("(%d %p %p %x)\n", hFile, lpOverlapped, lpTransferred, bWait);
1150 if(lpOverlapped==NULL)
1152 ERR("lpOverlapped was null\n");
1153 return FALSE;
1155 if(!lpOverlapped->hEvent)
1157 ERR("lpOverlapped->hEvent was null\n");
1158 return FALSE;
1161 do {
1162 TRACE("waiting on %p\n",lpOverlapped);
1163 r = WaitForSingleObjectEx(lpOverlapped->hEvent, bWait?INFINITE:0, TRUE);
1164 TRACE("wait on %p returned %ld\n",lpOverlapped,r);
1165 } while (r==STATUS_USER_APC);
1167 if(lpTransferred)
1168 *lpTransferred = lpOverlapped->InternalHigh;
1170 SetLastError(lpOverlapped->Internal);
1172 return (r==WAIT_OBJECT_0);
1175 /***********************************************************************
1176 * FILE_AsyncResult (INTERNAL)
1178 static int FILE_AsyncResult(HANDLE hAsync, int result)
1180 int r;
1182 SERVER_START_REQ( async_result )
1184 req->ov_handle = hAsync;
1185 req->result = result;
1186 r = SERVER_CALL_ERR();
1188 SERVER_END_REQ;
1189 return !r;
1192 /***********************************************************************
1193 * FILE_AsyncReadService (INTERNAL)
1195 static void FILE_AsyncReadService(void **args)
1197 LPOVERLAPPED lpOverlapped = (LPOVERLAPPED)args[0];
1198 LPDWORD buffer = (LPDWORD)args[1];
1199 DWORD events = (DWORD)args[2];
1200 int fd, result, r;
1202 TRACE("%p %p %08lx\n", lpOverlapped, buffer, events );
1204 /* if there are no events, it must be a timeout */
1205 if(events==0)
1207 TRACE("read timed out\n");
1208 /* r = STATUS_TIMEOUT; */
1209 r = STATUS_SUCCESS;
1210 goto async_end;
1213 fd = FILE_GetUnixHandle(lpOverlapped->Offset, GENERIC_READ);
1214 if(fd<0)
1216 TRACE("FILE_GetUnixHandle(%ld) failed \n",lpOverlapped->Offset);
1217 r = STATUS_UNSUCCESSFUL;
1218 goto async_end;
1221 /* check to see if the data is ready (non-blocking) */
1222 result = read(fd, &buffer[lpOverlapped->InternalHigh],
1223 lpOverlapped->OffsetHigh - lpOverlapped->InternalHigh);
1224 close(fd);
1226 if ( (result<0) && ((errno == EAGAIN) || (errno == EINTR)))
1228 TRACE("Deferred read %d\n",errno);
1229 r = STATUS_PENDING;
1230 goto async_end;
1233 /* check to see if the transfer is complete */
1234 if(result<0)
1236 TRACE("read returned errno %d\n",errno);
1237 r = STATUS_UNSUCCESSFUL;
1238 goto async_end;
1241 lpOverlapped->InternalHigh += result;
1242 TRACE("read %d more bytes %ld/%ld so far\n",result,lpOverlapped->InternalHigh,lpOverlapped->OffsetHigh);
1244 if(lpOverlapped->InternalHigh < lpOverlapped->OffsetHigh)
1245 r = STATUS_PENDING;
1246 else
1247 r = STATUS_SUCCESS;
1249 async_end:
1250 lpOverlapped->Internal = r;
1251 if ( (r!=STATUS_PENDING)
1252 || (!FILE_AsyncResult( lpOverlapped->InternalHigh, r)))
1254 /* close the handle to the async operation */
1255 if(lpOverlapped->Offset)
1256 CloseHandle(lpOverlapped->Offset);
1257 lpOverlapped->Offset = 0;
1259 NtSetEvent( lpOverlapped->hEvent, NULL );
1260 TRACE("set event flag\n");
1264 /***********************************************************************
1265 * FILE_StartAsyncRead (INTERNAL)
1267 static BOOL FILE_StartAsyncRead( HANDLE hFile, LPOVERLAPPED overlapped, LPVOID buffer, DWORD count)
1269 int r;
1271 SERVER_START_REQ( create_async )
1273 req->file_handle = hFile;
1274 req->overlapped = overlapped;
1275 req->buffer = buffer;
1276 req->count = count;
1277 req->func = FILE_AsyncReadService;
1278 req->type = ASYNC_TYPE_READ;
1280 r=SERVER_CALL_ERR();
1282 overlapped->Offset = req->ov_handle;
1284 SERVER_END_REQ;
1286 if(!r)
1288 TRACE("ov=%ld IO is pending!!!\n",overlapped->Offset);
1289 SetLastError(ERROR_IO_PENDING);
1292 return !r;
1295 /***********************************************************************
1296 * ReadFile (KERNEL32.577)
1298 BOOL WINAPI ReadFile( HANDLE hFile, LPVOID buffer, DWORD bytesToRead,
1299 LPDWORD bytesRead, LPOVERLAPPED overlapped )
1301 int unix_handle, result;
1303 TRACE("%d %p %ld %p %p\n", hFile, buffer, bytesToRead,
1304 bytesRead, overlapped );
1306 if (bytesRead) *bytesRead = 0; /* Do this before anything else */
1307 if (!bytesToRead) return TRUE;
1309 /* this will only have impact if the overlapped structure is specified */
1310 if ( overlapped )
1312 /* if overlapped, check that there is an event flag */
1313 if ( (overlapped->hEvent == 0) ||
1314 (overlapped->hEvent == INVALID_HANDLE_VALUE) )
1316 return FALSE;
1319 overlapped->Offset = 0;
1320 overlapped->OffsetHigh = bytesToRead;
1321 overlapped->Internal = 0;
1322 overlapped->InternalHigh = 0;
1324 NtResetEvent( overlapped->hEvent, NULL );
1326 if(FILE_StartAsyncRead(hFile, overlapped, buffer, bytesToRead))
1328 overlapped->Internal = STATUS_PENDING;
1331 /* always fail on return, either ERROR_IO_PENDING or other error */
1332 return FALSE;
1335 unix_handle = FILE_GetUnixHandle( hFile, GENERIC_READ );
1336 if (unix_handle == -1) return FALSE;
1338 /* code for synchronous reads */
1339 while ((result = read( unix_handle, buffer, bytesToRead )) == -1)
1341 if ((errno == EAGAIN) || (errno == EINTR)) continue;
1342 if ((errno == EFAULT) && !IsBadWritePtr( buffer, bytesToRead )) continue;
1343 FILE_SetDosError();
1344 break;
1346 close( unix_handle );
1347 if (result == -1) return FALSE;
1348 if (bytesRead) *bytesRead = result;
1349 return TRUE;
1352 /***********************************************************************
1353 * FILE_AsyncWriteService (INTERNAL)
1355 static void FILE_AsyncWriteService(void **args)
1357 LPOVERLAPPED lpOverlapped = (LPOVERLAPPED)args[0];
1358 LPDWORD buffer = (LPDWORD)args[1];
1359 DWORD events = (DWORD)args[2];
1360 int fd, result, r;
1362 TRACE("(%p %p %lx)\n",lpOverlapped,buffer,events);
1364 /* if there are no events, it must be a timeout */
1365 if(events==0)
1367 TRACE("write timed out\n");
1368 r = STATUS_TIMEOUT;
1369 goto async_end;
1372 fd = FILE_GetUnixHandle(lpOverlapped->Offset, GENERIC_WRITE);
1373 if(fd<0)
1375 ERR("FILE_GetUnixHandle(%ld) failed \n",lpOverlapped->Offset);
1376 r = STATUS_UNSUCCESSFUL;
1377 goto async_end;
1380 /* write some data (non-blocking) */
1381 result = write(fd, &buffer[lpOverlapped->InternalHigh],
1382 lpOverlapped->OffsetHigh-lpOverlapped->InternalHigh);
1383 close(fd);
1385 if ( (result<0) && ((errno == EAGAIN) || (errno == EINTR)))
1387 r = STATUS_PENDING;
1388 goto async_end;
1391 /* check to see if the transfer is complete */
1392 if(result<0)
1394 r = STATUS_UNSUCCESSFUL;
1395 goto async_end;
1398 lpOverlapped->InternalHigh += result;
1400 if(lpOverlapped->InternalHigh < lpOverlapped->OffsetHigh)
1401 r = STATUS_PENDING;
1402 else
1403 r = STATUS_SUCCESS;
1405 async_end:
1406 lpOverlapped->Internal = r;
1407 if ( (r!=STATUS_PENDING)
1408 || (!FILE_AsyncResult( lpOverlapped->Offset, r)))
1410 /* close the handle to the async operation */
1411 CloseHandle(lpOverlapped->Offset);
1412 lpOverlapped->Offset = 0;
1414 NtSetEvent( lpOverlapped->hEvent, NULL );
1418 /***********************************************************************
1419 * FILE_StartAsyncWrite (INTERNAL)
1421 static BOOL FILE_StartAsyncWrite(HANDLE hFile, LPOVERLAPPED overlapped, LPCVOID buffer,DWORD count)
1423 int r;
1425 SERVER_START_REQ( create_async )
1427 req->file_handle = hFile;
1428 req->buffer = (LPVOID)buffer;
1429 req->overlapped = overlapped;
1430 req->count = 0;
1431 req->func = FILE_AsyncWriteService;
1432 req->type = ASYNC_TYPE_WRITE;
1434 r = SERVER_CALL_ERR();
1436 overlapped->Offset = req->ov_handle;
1438 SERVER_END_REQ;
1440 if(!r)
1442 SetLastError(ERROR_IO_PENDING);
1445 return !r;
1448 /***********************************************************************
1449 * WriteFile (KERNEL32.738)
1451 BOOL WINAPI WriteFile( HANDLE hFile, LPCVOID buffer, DWORD bytesToWrite,
1452 LPDWORD bytesWritten, LPOVERLAPPED overlapped )
1454 int unix_handle, result;
1456 TRACE("%d %p %ld %p %p\n", hFile, buffer, bytesToWrite,
1457 bytesWritten, overlapped );
1459 if (bytesWritten) *bytesWritten = 0; /* Do this before anything else */
1460 if (!bytesToWrite) return TRUE;
1462 /* this will only have impact if the overlappd structure is specified */
1463 if ( overlapped )
1465 if ( (overlapped->hEvent == 0) ||
1466 (overlapped->hEvent == INVALID_HANDLE_VALUE) )
1467 return FALSE;
1469 overlapped->Offset = 0;
1470 overlapped->OffsetHigh = bytesToWrite;
1471 overlapped->Internal = 0;
1472 overlapped->InternalHigh = 0;
1474 NtResetEvent( overlapped->hEvent, NULL );
1476 if (FILE_StartAsyncWrite(hFile, overlapped, buffer, bytesToWrite))
1478 overlapped->Internal = STATUS_PENDING;
1481 /* always fail on return, either ERROR_IO_PENDING or other error */
1482 return FALSE;
1485 unix_handle = FILE_GetUnixHandle( hFile, GENERIC_WRITE );
1486 if (unix_handle == -1) return FALSE;
1488 /* synchronous file write */
1489 while ((result = write( unix_handle, buffer, bytesToWrite )) == -1)
1491 if ((errno == EAGAIN) || (errno == EINTR)) continue;
1492 if ((errno == EFAULT) && !IsBadReadPtr( buffer, bytesToWrite )) continue;
1493 if (errno == ENOSPC)
1494 SetLastError( ERROR_DISK_FULL );
1495 else
1496 FILE_SetDosError();
1497 break;
1499 close( unix_handle );
1500 if (result == -1) return FALSE;
1501 if (bytesWritten) *bytesWritten = result;
1502 return TRUE;
1506 /***********************************************************************
1507 * WIN16_hread
1509 LONG WINAPI WIN16_hread( HFILE16 hFile, SEGPTR buffer, LONG count )
1511 LONG maxlen;
1513 TRACE("%d %08lx %ld\n",
1514 hFile, (DWORD)buffer, count );
1516 /* Some programs pass a count larger than the allocated buffer */
1517 maxlen = GetSelectorLimit16( SELECTOROF(buffer) ) - OFFSETOF(buffer) + 1;
1518 if (count > maxlen) count = maxlen;
1519 return _lread(DosFileHandleToWin32Handle(hFile), MapSL(buffer), count );
1523 /***********************************************************************
1524 * WIN16_lread
1526 UINT16 WINAPI WIN16_lread( HFILE16 hFile, SEGPTR buffer, UINT16 count )
1528 return (UINT16)WIN16_hread( hFile, buffer, (LONG)count );
1532 /***********************************************************************
1533 * _lread (KERNEL32.596)
1535 UINT WINAPI _lread( HFILE handle, LPVOID buffer, UINT count )
1537 DWORD result;
1538 if (!ReadFile( handle, buffer, count, &result, NULL )) return -1;
1539 return result;
1543 /***********************************************************************
1544 * _lread16 (KERNEL.82)
1546 UINT16 WINAPI _lread16( HFILE16 hFile, LPVOID buffer, UINT16 count )
1548 return (UINT16)_lread(DosFileHandleToWin32Handle(hFile), buffer, (LONG)count );
1552 /***********************************************************************
1553 * _lcreat16 (KERNEL.83)
1555 HFILE16 WINAPI _lcreat16( LPCSTR path, INT16 attr )
1557 return Win32HandleToDosFileHandle( _lcreat( path, attr ) );
1561 /***********************************************************************
1562 * _lcreat (KERNEL32.593)
1564 HFILE WINAPI _lcreat( LPCSTR path, INT attr )
1566 /* Mask off all flags not explicitly allowed by the doc */
1567 attr &= FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM;
1568 TRACE("%s %02x\n", path, attr );
1569 return CreateFileA( path, GENERIC_READ | GENERIC_WRITE,
1570 FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
1571 CREATE_ALWAYS, attr, 0 );
1575 /***********************************************************************
1576 * SetFilePointer (KERNEL32.492)
1578 DWORD WINAPI SetFilePointer( HANDLE hFile, LONG distance, LONG *highword,
1579 DWORD method )
1581 DWORD ret = 0xffffffff;
1583 if (highword &&
1584 ((distance >= 0 && *highword != 0) || (distance < 0 && *highword != -1)))
1586 FIXME("64-bit offsets not supported yet\n"
1587 "SetFilePointer(%08x,%08lx,%08lx,%08lx)\n",
1588 hFile,distance,*highword,method);
1589 SetLastError( ERROR_INVALID_PARAMETER );
1590 return ret;
1592 TRACE("handle %d offset %ld origin %ld\n",
1593 hFile, distance, method );
1595 SERVER_START_REQ( set_file_pointer )
1597 req->handle = hFile;
1598 req->low = distance;
1599 req->high = highword ? *highword : (distance >= 0) ? 0 : -1;
1600 /* FIXME: assumes 1:1 mapping between Windows and Unix seek constants */
1601 req->whence = method;
1602 SetLastError( 0 );
1603 if (!SERVER_CALL_ERR())
1605 ret = req->new_low;
1606 if (highword) *highword = req->new_high;
1609 SERVER_END_REQ;
1610 return ret;
1614 /***********************************************************************
1615 * _llseek16 (KERNEL.84)
1617 * FIXME:
1618 * Seeking before the start of the file should be allowed for _llseek16,
1619 * but cause subsequent I/O operations to fail (cf. interrupt list)
1622 LONG WINAPI _llseek16( HFILE16 hFile, LONG lOffset, INT16 nOrigin )
1624 return SetFilePointer( DosFileHandleToWin32Handle(hFile), lOffset, NULL, nOrigin );
1628 /***********************************************************************
1629 * _llseek (KERNEL32.594)
1631 LONG WINAPI _llseek( HFILE hFile, LONG lOffset, INT nOrigin )
1633 return SetFilePointer( hFile, lOffset, NULL, nOrigin );
1637 /***********************************************************************
1638 * _lopen16 (KERNEL.85)
1640 HFILE16 WINAPI _lopen16( LPCSTR path, INT16 mode )
1642 return Win32HandleToDosFileHandle( _lopen( path, mode ) );
1646 /***********************************************************************
1647 * _lopen (KERNEL32.595)
1649 HFILE WINAPI _lopen( LPCSTR path, INT mode )
1651 DWORD access, sharing;
1653 TRACE("('%s',%04x)\n", path, mode );
1654 FILE_ConvertOFMode( mode, &access, &sharing );
1655 return CreateFileA( path, access, sharing, NULL, OPEN_EXISTING, 0, 0 );
1659 /***********************************************************************
1660 * _lwrite16 (KERNEL.86)
1662 UINT16 WINAPI _lwrite16( HFILE16 hFile, LPCSTR buffer, UINT16 count )
1664 return (UINT16)_hwrite( DosFileHandleToWin32Handle(hFile), buffer, (LONG)count );
1667 /***********************************************************************
1668 * _lwrite (KERNEL32.761)
1670 UINT WINAPI _lwrite( HFILE hFile, LPCSTR buffer, UINT count )
1672 return (UINT)_hwrite( hFile, buffer, (LONG)count );
1676 /***********************************************************************
1677 * _hread16 (KERNEL.349)
1679 LONG WINAPI _hread16( HFILE16 hFile, LPVOID buffer, LONG count)
1681 return _lread( DosFileHandleToWin32Handle(hFile), buffer, count );
1685 /***********************************************************************
1686 * _hread (KERNEL32.590)
1688 LONG WINAPI _hread( HFILE hFile, LPVOID buffer, LONG count)
1690 return _lread( hFile, buffer, count );
1694 /***********************************************************************
1695 * _hwrite16 (KERNEL.350)
1697 LONG WINAPI _hwrite16( HFILE16 hFile, LPCSTR buffer, LONG count )
1699 return _hwrite( DosFileHandleToWin32Handle(hFile), buffer, count );
1703 /***********************************************************************
1704 * _hwrite (KERNEL32.591)
1706 * experimentation yields that _lwrite:
1707 * o truncates the file at the current position with
1708 * a 0 len write
1709 * o returns 0 on a 0 length write
1710 * o works with console handles
1713 LONG WINAPI _hwrite( HFILE handle, LPCSTR buffer, LONG count )
1715 DWORD result;
1717 TRACE("%d %p %ld\n", handle, buffer, count );
1719 if (!count)
1721 /* Expand or truncate at current position */
1722 if (!SetEndOfFile( handle )) return HFILE_ERROR;
1723 return 0;
1725 if (!WriteFile( handle, buffer, count, &result, NULL ))
1726 return HFILE_ERROR;
1727 return result;
1731 /***********************************************************************
1732 * SetHandleCount16 (KERNEL.199)
1734 UINT16 WINAPI SetHandleCount16( UINT16 count )
1736 return SetHandleCount( count );
1740 /*************************************************************************
1741 * SetHandleCount (KERNEL32.494)
1743 UINT WINAPI SetHandleCount( UINT count )
1745 return min( 256, count );
1749 /***********************************************************************
1750 * FlushFileBuffers (KERNEL32.133)
1752 BOOL WINAPI FlushFileBuffers( HANDLE hFile )
1754 BOOL ret;
1755 SERVER_START_REQ( flush_file )
1757 req->handle = hFile;
1758 ret = !SERVER_CALL_ERR();
1760 SERVER_END_REQ;
1761 return ret;
1765 /**************************************************************************
1766 * SetEndOfFile (KERNEL32.483)
1768 BOOL WINAPI SetEndOfFile( HANDLE hFile )
1770 BOOL ret;
1771 SERVER_START_REQ( truncate_file )
1773 req->handle = hFile;
1774 ret = !SERVER_CALL_ERR();
1776 SERVER_END_REQ;
1777 return ret;
1781 /***********************************************************************
1782 * DeleteFile16 (KERNEL.146)
1784 BOOL16 WINAPI DeleteFile16( LPCSTR path )
1786 return DeleteFileA( path );
1790 /***********************************************************************
1791 * DeleteFileA (KERNEL32.71)
1793 BOOL WINAPI DeleteFileA( LPCSTR path )
1795 DOS_FULL_NAME full_name;
1797 TRACE("'%s'\n", path );
1799 if (!*path)
1801 ERR("Empty path passed\n");
1802 return FALSE;
1804 if (DOSFS_GetDevice( path ))
1806 WARN("cannot remove DOS device '%s'!\n", path);
1807 SetLastError( ERROR_FILE_NOT_FOUND );
1808 return FALSE;
1811 if (!DOSFS_GetFullName( path, TRUE, &full_name )) return FALSE;
1812 if (unlink( full_name.long_name ) == -1)
1814 FILE_SetDosError();
1815 return FALSE;
1817 return TRUE;
1821 /***********************************************************************
1822 * DeleteFileW (KERNEL32.72)
1824 BOOL WINAPI DeleteFileW( LPCWSTR path )
1826 LPSTR xpath = HEAP_strdupWtoA( GetProcessHeap(), 0, path );
1827 BOOL ret = DeleteFileA( xpath );
1828 HeapFree( GetProcessHeap(), 0, xpath );
1829 return ret;
1833 /***********************************************************************
1834 * GetFileType (KERNEL32.222)
1836 DWORD WINAPI GetFileType( HANDLE hFile )
1838 DWORD ret = FILE_TYPE_UNKNOWN;
1839 SERVER_START_REQ( get_file_info )
1841 req->handle = hFile;
1842 if (!SERVER_CALL_ERR()) ret = req->type;
1844 SERVER_END_REQ;
1845 return ret;
1849 /**************************************************************************
1850 * MoveFileExA (KERNEL32.???)
1852 BOOL WINAPI MoveFileExA( LPCSTR fn1, LPCSTR fn2, DWORD flag )
1854 DOS_FULL_NAME full_name1, full_name2;
1856 TRACE("(%s,%s,%04lx)\n", fn1, fn2, flag);
1858 if (!DOSFS_GetFullName( fn1, TRUE, &full_name1 )) return FALSE;
1860 if (fn2) /* !fn2 means delete fn1 */
1862 if (DOSFS_GetFullName( fn2, TRUE, &full_name2 ))
1864 /* target exists, check if we may overwrite */
1865 if (!(flag & MOVEFILE_REPLACE_EXISTING))
1867 /* FIXME: Use right error code */
1868 SetLastError( ERROR_ACCESS_DENIED );
1869 return FALSE;
1872 else if (!DOSFS_GetFullName( fn2, FALSE, &full_name2 )) return FALSE;
1874 /* Source name and target path are valid */
1876 if (flag & MOVEFILE_DELAY_UNTIL_REBOOT)
1878 /* FIXME: (bon@elektron.ikp.physik.th-darmstadt.de 970706)
1879 Perhaps we should queue these command and execute it
1880 when exiting... What about using on_exit(2)
1882 FIXME("Please move existing file '%s' to file '%s' when Wine has finished\n",
1883 full_name1.long_name, full_name2.long_name);
1884 return TRUE;
1887 if (full_name1.drive != full_name2.drive)
1889 /* use copy, if allowed */
1890 if (!(flag & MOVEFILE_COPY_ALLOWED))
1892 /* FIXME: Use right error code */
1893 SetLastError( ERROR_FILE_EXISTS );
1894 return FALSE;
1896 return CopyFileA( fn1, fn2, !(flag & MOVEFILE_REPLACE_EXISTING) );
1898 if (rename( full_name1.long_name, full_name2.long_name ) == -1)
1900 FILE_SetDosError();
1901 return FALSE;
1903 return TRUE;
1905 else /* fn2 == NULL means delete source */
1907 if (flag & MOVEFILE_DELAY_UNTIL_REBOOT)
1909 if (flag & MOVEFILE_COPY_ALLOWED) {
1910 WARN("Illegal flag\n");
1911 SetLastError( ERROR_GEN_FAILURE );
1912 return FALSE;
1914 /* FIXME: (bon@elektron.ikp.physik.th-darmstadt.de 970706)
1915 Perhaps we should queue these command and execute it
1916 when exiting... What about using on_exit(2)
1918 FIXME("Please delete file '%s' when Wine has finished\n",
1919 full_name1.long_name);
1920 return TRUE;
1923 if (unlink( full_name1.long_name ) == -1)
1925 FILE_SetDosError();
1926 return FALSE;
1928 return TRUE; /* successfully deleted */
1932 /**************************************************************************
1933 * MoveFileExW (KERNEL32.???)
1935 BOOL WINAPI MoveFileExW( LPCWSTR fn1, LPCWSTR fn2, DWORD flag )
1937 LPSTR afn1 = HEAP_strdupWtoA( GetProcessHeap(), 0, fn1 );
1938 LPSTR afn2 = HEAP_strdupWtoA( GetProcessHeap(), 0, fn2 );
1939 BOOL res = MoveFileExA( afn1, afn2, flag );
1940 HeapFree( GetProcessHeap(), 0, afn1 );
1941 HeapFree( GetProcessHeap(), 0, afn2 );
1942 return res;
1946 /**************************************************************************
1947 * MoveFileA (KERNEL32.387)
1949 * Move file or directory
1951 BOOL WINAPI MoveFileA( LPCSTR fn1, LPCSTR fn2 )
1953 DOS_FULL_NAME full_name1, full_name2;
1954 struct stat fstat;
1956 TRACE("(%s,%s)\n", fn1, fn2 );
1958 if (!DOSFS_GetFullName( fn1, TRUE, &full_name1 )) return FALSE;
1959 if (DOSFS_GetFullName( fn2, TRUE, &full_name2 )) {
1960 /* The new name must not already exist */
1961 SetLastError(ERROR_ALREADY_EXISTS);
1962 return FALSE;
1964 if (!DOSFS_GetFullName( fn2, FALSE, &full_name2 )) return FALSE;
1966 if (full_name1.drive == full_name2.drive) /* move */
1967 if (rename( full_name1.long_name, full_name2.long_name ) == -1)
1969 FILE_SetDosError();
1970 return FALSE;
1972 else return TRUE;
1973 else /*copy */ {
1974 if (stat( full_name1.long_name, &fstat ))
1976 WARN("Invalid source file %s\n",
1977 full_name1.long_name);
1978 FILE_SetDosError();
1979 return FALSE;
1981 if (S_ISDIR(fstat.st_mode)) {
1982 /* No Move for directories across file systems */
1983 /* FIXME: Use right error code */
1984 SetLastError( ERROR_GEN_FAILURE );
1985 return FALSE;
1987 else
1988 return CopyFileA(fn1, fn2, TRUE); /*fail, if exist */
1993 /**************************************************************************
1994 * MoveFileW (KERNEL32.390)
1996 BOOL WINAPI MoveFileW( LPCWSTR fn1, LPCWSTR fn2 )
1998 LPSTR afn1 = HEAP_strdupWtoA( GetProcessHeap(), 0, fn1 );
1999 LPSTR afn2 = HEAP_strdupWtoA( GetProcessHeap(), 0, fn2 );
2000 BOOL res = MoveFileA( afn1, afn2 );
2001 HeapFree( GetProcessHeap(), 0, afn1 );
2002 HeapFree( GetProcessHeap(), 0, afn2 );
2003 return res;
2007 /**************************************************************************
2008 * CopyFileA (KERNEL32.36)
2010 BOOL WINAPI CopyFileA( LPCSTR source, LPCSTR dest, BOOL fail_if_exists )
2012 HFILE h1, h2;
2013 BY_HANDLE_FILE_INFORMATION info;
2014 UINT count;
2015 BOOL ret = FALSE;
2016 int mode;
2017 char buffer[2048];
2019 if ((h1 = _lopen( source, OF_READ )) == HFILE_ERROR) return FALSE;
2020 if (!GetFileInformationByHandle( h1, &info ))
2022 CloseHandle( h1 );
2023 return FALSE;
2025 mode = (info.dwFileAttributes & FILE_ATTRIBUTE_READONLY) ? 0444 : 0666;
2026 if ((h2 = CreateFileA( dest, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
2027 fail_if_exists ? CREATE_NEW : CREATE_ALWAYS,
2028 info.dwFileAttributes, h1 )) == INVALID_HANDLE_VALUE)
2030 CloseHandle( h1 );
2031 return FALSE;
2033 while ((count = _lread( h1, buffer, sizeof(buffer) )) > 0)
2035 char *p = buffer;
2036 while (count > 0)
2038 INT res = _lwrite( h2, p, count );
2039 if (res <= 0) goto done;
2040 p += res;
2041 count -= res;
2044 ret = TRUE;
2045 done:
2046 CloseHandle( h1 );
2047 CloseHandle( h2 );
2048 return ret;
2052 /**************************************************************************
2053 * CopyFileW (KERNEL32.37)
2055 BOOL WINAPI CopyFileW( LPCWSTR source, LPCWSTR dest, BOOL fail_if_exists)
2057 LPSTR sourceA = HEAP_strdupWtoA( GetProcessHeap(), 0, source );
2058 LPSTR destA = HEAP_strdupWtoA( GetProcessHeap(), 0, dest );
2059 BOOL ret = CopyFileA( sourceA, destA, fail_if_exists );
2060 HeapFree( GetProcessHeap(), 0, sourceA );
2061 HeapFree( GetProcessHeap(), 0, destA );
2062 return ret;
2066 /**************************************************************************
2067 * CopyFileExA (KERNEL32.858)
2069 * This implementation ignores most of the extra parameters passed-in into
2070 * the "ex" version of the method and calls the CopyFile method.
2071 * It will have to be fixed eventually.
2073 BOOL WINAPI CopyFileExA(LPCSTR sourceFilename,
2074 LPCSTR destFilename,
2075 LPPROGRESS_ROUTINE progressRoutine,
2076 LPVOID appData,
2077 LPBOOL cancelFlagPointer,
2078 DWORD copyFlags)
2080 BOOL failIfExists = FALSE;
2083 * Interpret the only flag that CopyFile can interpret.
2085 if ( (copyFlags & COPY_FILE_FAIL_IF_EXISTS) != 0)
2087 failIfExists = TRUE;
2090 return CopyFileA(sourceFilename, destFilename, failIfExists);
2093 /**************************************************************************
2094 * CopyFileExW (KERNEL32.859)
2096 BOOL WINAPI CopyFileExW(LPCWSTR sourceFilename,
2097 LPCWSTR destFilename,
2098 LPPROGRESS_ROUTINE progressRoutine,
2099 LPVOID appData,
2100 LPBOOL cancelFlagPointer,
2101 DWORD copyFlags)
2103 LPSTR sourceA = HEAP_strdupWtoA( GetProcessHeap(), 0, sourceFilename );
2104 LPSTR destA = HEAP_strdupWtoA( GetProcessHeap(), 0, destFilename );
2106 BOOL ret = CopyFileExA(sourceA,
2107 destA,
2108 progressRoutine,
2109 appData,
2110 cancelFlagPointer,
2111 copyFlags);
2113 HeapFree( GetProcessHeap(), 0, sourceA );
2114 HeapFree( GetProcessHeap(), 0, destA );
2116 return ret;
2120 /***********************************************************************
2121 * SetFileTime (KERNEL32.650)
2123 BOOL WINAPI SetFileTime( HANDLE hFile,
2124 const FILETIME *lpCreationTime,
2125 const FILETIME *lpLastAccessTime,
2126 const FILETIME *lpLastWriteTime )
2128 BOOL ret;
2129 SERVER_START_REQ( set_file_time )
2131 req->handle = hFile;
2132 if (lpLastAccessTime)
2133 RtlTimeToSecondsSince1970( lpLastAccessTime, (DWORD *)&req->access_time );
2134 else
2135 req->access_time = 0; /* FIXME */
2136 if (lpLastWriteTime)
2137 RtlTimeToSecondsSince1970( lpLastWriteTime, (DWORD *)&req->write_time );
2138 else
2139 req->write_time = 0; /* FIXME */
2140 ret = !SERVER_CALL_ERR();
2142 SERVER_END_REQ;
2143 return ret;
2147 /**************************************************************************
2148 * LockFile (KERNEL32.511)
2150 BOOL WINAPI LockFile( HANDLE hFile, DWORD dwFileOffsetLow, DWORD dwFileOffsetHigh,
2151 DWORD nNumberOfBytesToLockLow, DWORD nNumberOfBytesToLockHigh )
2153 BOOL ret;
2154 SERVER_START_REQ( lock_file )
2156 req->handle = hFile;
2157 req->offset_low = dwFileOffsetLow;
2158 req->offset_high = dwFileOffsetHigh;
2159 req->count_low = nNumberOfBytesToLockLow;
2160 req->count_high = nNumberOfBytesToLockHigh;
2161 ret = !SERVER_CALL_ERR();
2163 SERVER_END_REQ;
2164 return ret;
2167 /**************************************************************************
2168 * LockFileEx [KERNEL32.512]
2170 * Locks a byte range within an open file for shared or exclusive access.
2172 * RETURNS
2173 * success: TRUE
2174 * failure: FALSE
2176 * NOTES
2177 * Per Microsoft docs, the third parameter (reserved) must be set to 0.
2179 BOOL WINAPI LockFileEx( HANDLE hFile, DWORD flags, DWORD reserved,
2180 DWORD nNumberOfBytesToLockLow, DWORD nNumberOfBytesToLockHigh,
2181 LPOVERLAPPED pOverlapped )
2183 FIXME("hFile=%d,flags=%ld,reserved=%ld,lowbytes=%ld,highbytes=%ld,overlapped=%p: stub.\n",
2184 hFile, flags, reserved, nNumberOfBytesToLockLow, nNumberOfBytesToLockHigh,
2185 pOverlapped);
2186 if (reserved == 0)
2187 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
2188 else
2190 ERR("reserved == %ld: Supposed to be 0??\n", reserved);
2191 SetLastError(ERROR_INVALID_PARAMETER);
2194 return FALSE;
2198 /**************************************************************************
2199 * UnlockFile (KERNEL32.703)
2201 BOOL WINAPI UnlockFile( HANDLE hFile, DWORD dwFileOffsetLow, DWORD dwFileOffsetHigh,
2202 DWORD nNumberOfBytesToUnlockLow, DWORD nNumberOfBytesToUnlockHigh )
2204 BOOL ret;
2205 SERVER_START_REQ( unlock_file )
2207 req->handle = hFile;
2208 req->offset_low = dwFileOffsetLow;
2209 req->offset_high = dwFileOffsetHigh;
2210 req->count_low = nNumberOfBytesToUnlockLow;
2211 req->count_high = nNumberOfBytesToUnlockHigh;
2212 ret = !SERVER_CALL_ERR();
2214 SERVER_END_REQ;
2215 return ret;
2219 /**************************************************************************
2220 * UnlockFileEx (KERNEL32.705)
2222 BOOL WINAPI UnlockFileEx(
2223 HFILE hFile,
2224 DWORD dwReserved,
2225 DWORD nNumberOfBytesToUnlockLow,
2226 DWORD nNumberOfBytesToUnlockHigh,
2227 LPOVERLAPPED lpOverlapped
2230 FIXME("hFile=%d,reserved=%ld,lowbytes=%ld,highbytes=%ld,overlapped=%p: stub.\n",
2231 hFile, dwReserved, nNumberOfBytesToUnlockLow, nNumberOfBytesToUnlockHigh,
2232 lpOverlapped);
2233 if (dwReserved == 0)
2234 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
2235 else
2237 ERR("reserved == %ld: Supposed to be 0??\n", dwReserved);
2238 SetLastError(ERROR_INVALID_PARAMETER);
2241 return FALSE;
2245 #if 0
2247 struct DOS_FILE_LOCK {
2248 struct DOS_FILE_LOCK * next;
2249 DWORD base;
2250 DWORD len;
2251 DWORD processId;
2252 FILE_OBJECT * dos_file;
2253 /* char * unix_name;*/
2256 typedef struct DOS_FILE_LOCK DOS_FILE_LOCK;
2258 static DOS_FILE_LOCK *locks = NULL;
2259 static void DOS_RemoveFileLocks(FILE_OBJECT *file);
2262 /* Locks need to be mirrored because unix file locking is based
2263 * on the pid. Inside of wine there can be multiple WINE processes
2264 * that share the same unix pid.
2265 * Read's and writes should check these locks also - not sure
2266 * how critical that is at this point (FIXME).
2269 static BOOL DOS_AddLock(FILE_OBJECT *file, struct flock *f)
2271 DOS_FILE_LOCK *curr;
2272 DWORD processId;
2274 processId = GetCurrentProcessId();
2276 /* check if lock overlaps a current lock for the same file */
2277 #if 0
2278 for (curr = locks; curr; curr = curr->next) {
2279 if (strcmp(curr->unix_name, file->unix_name) == 0) {
2280 if ((f->l_start == curr->base) && (f->l_len == curr->len))
2281 return TRUE;/* region is identic */
2282 if ((f->l_start < (curr->base + curr->len)) &&
2283 ((f->l_start + f->l_len) > curr->base)) {
2284 /* region overlaps */
2285 return FALSE;
2289 #endif
2291 curr = HeapAlloc( GetProcessHeap(), 0, sizeof(DOS_FILE_LOCK) );
2292 curr->processId = GetCurrentProcessId();
2293 curr->base = f->l_start;
2294 curr->len = f->l_len;
2295 /* curr->unix_name = HEAP_strdupA( GetProcessHeap(), 0, file->unix_name);*/
2296 curr->next = locks;
2297 curr->dos_file = file;
2298 locks = curr;
2299 return TRUE;
2302 static void DOS_RemoveFileLocks(FILE_OBJECT *file)
2304 DWORD processId;
2305 DOS_FILE_LOCK **curr;
2306 DOS_FILE_LOCK *rem;
2308 processId = GetCurrentProcessId();
2309 curr = &locks;
2310 while (*curr) {
2311 if ((*curr)->dos_file == file) {
2312 rem = *curr;
2313 *curr = (*curr)->next;
2314 /* HeapFree( GetProcessHeap(), 0, rem->unix_name );*/
2315 HeapFree( GetProcessHeap(), 0, rem );
2317 else
2318 curr = &(*curr)->next;
2322 static BOOL DOS_RemoveLock(FILE_OBJECT *file, struct flock *f)
2324 DWORD processId;
2325 DOS_FILE_LOCK **curr;
2326 DOS_FILE_LOCK *rem;
2328 processId = GetCurrentProcessId();
2329 for (curr = &locks; *curr; curr = &(*curr)->next) {
2330 if ((*curr)->processId == processId &&
2331 (*curr)->dos_file == file &&
2332 (*curr)->base == f->l_start &&
2333 (*curr)->len == f->l_len) {
2334 /* this is the same lock */
2335 rem = *curr;
2336 *curr = (*curr)->next;
2337 /* HeapFree( GetProcessHeap(), 0, rem->unix_name );*/
2338 HeapFree( GetProcessHeap(), 0, rem );
2339 return TRUE;
2342 /* no matching lock found */
2343 return FALSE;
2347 /**************************************************************************
2348 * LockFile (KERNEL32.511)
2350 BOOL WINAPI LockFile(
2351 HFILE hFile,DWORD dwFileOffsetLow,DWORD dwFileOffsetHigh,
2352 DWORD nNumberOfBytesToLockLow,DWORD nNumberOfBytesToLockHigh )
2354 struct flock f;
2355 FILE_OBJECT *file;
2357 TRACE("handle %d offsetlow=%ld offsethigh=%ld nbyteslow=%ld nbyteshigh=%ld\n",
2358 hFile, dwFileOffsetLow, dwFileOffsetHigh,
2359 nNumberOfBytesToLockLow, nNumberOfBytesToLockHigh);
2361 if (dwFileOffsetHigh || nNumberOfBytesToLockHigh) {
2362 FIXME("Unimplemented bytes > 32bits\n");
2363 return FALSE;
2366 f.l_start = dwFileOffsetLow;
2367 f.l_len = nNumberOfBytesToLockLow;
2368 f.l_whence = SEEK_SET;
2369 f.l_pid = 0;
2370 f.l_type = F_WRLCK;
2372 if (!(file = FILE_GetFile(hFile,0,NULL))) return FALSE;
2374 /* shadow locks internally */
2375 if (!DOS_AddLock(file, &f)) {
2376 SetLastError( ERROR_LOCK_VIOLATION );
2377 return FALSE;
2380 /* FIXME: Unix locking commented out for now, doesn't work with Excel */
2381 #ifdef USE_UNIX_LOCKS
2382 if (fcntl(file->unix_handle, F_SETLK, &f) == -1) {
2383 if (errno == EACCES || errno == EAGAIN) {
2384 SetLastError( ERROR_LOCK_VIOLATION );
2386 else {
2387 FILE_SetDosError();
2389 /* remove our internal copy of the lock */
2390 DOS_RemoveLock(file, &f);
2391 return FALSE;
2393 #endif
2394 return TRUE;
2398 /**************************************************************************
2399 * UnlockFile (KERNEL32.703)
2401 BOOL WINAPI UnlockFile(
2402 HFILE hFile,DWORD dwFileOffsetLow,DWORD dwFileOffsetHigh,
2403 DWORD nNumberOfBytesToUnlockLow,DWORD nNumberOfBytesToUnlockHigh )
2405 FILE_OBJECT *file;
2406 struct flock f;
2408 TRACE("handle %d offsetlow=%ld offsethigh=%ld nbyteslow=%ld nbyteshigh=%ld\n",
2409 hFile, dwFileOffsetLow, dwFileOffsetHigh,
2410 nNumberOfBytesToUnlockLow, nNumberOfBytesToUnlockHigh);
2412 if (dwFileOffsetHigh || nNumberOfBytesToUnlockHigh) {
2413 WARN("Unimplemented bytes > 32bits\n");
2414 return FALSE;
2417 f.l_start = dwFileOffsetLow;
2418 f.l_len = nNumberOfBytesToUnlockLow;
2419 f.l_whence = SEEK_SET;
2420 f.l_pid = 0;
2421 f.l_type = F_UNLCK;
2423 if (!(file = FILE_GetFile(hFile,0,NULL))) return FALSE;
2425 DOS_RemoveLock(file, &f); /* ok if fails - may be another wine */
2427 /* FIXME: Unix locking commented out for now, doesn't work with Excel */
2428 #ifdef USE_UNIX_LOCKS
2429 if (fcntl(file->unix_handle, F_SETLK, &f) == -1) {
2430 FILE_SetDosError();
2431 return FALSE;
2433 #endif
2434 return TRUE;
2436 #endif
2438 /**************************************************************************
2439 * GetFileAttributesExA [KERNEL32.874]
2441 BOOL WINAPI GetFileAttributesExA(
2442 LPCSTR lpFileName, GET_FILEEX_INFO_LEVELS fInfoLevelId,
2443 LPVOID lpFileInformation)
2445 DOS_FULL_NAME full_name;
2446 BY_HANDLE_FILE_INFORMATION info;
2448 if (lpFileName == NULL) return FALSE;
2449 if (lpFileInformation == NULL) return FALSE;
2451 if (fInfoLevelId == GetFileExInfoStandard) {
2452 LPWIN32_FILE_ATTRIBUTE_DATA lpFad =
2453 (LPWIN32_FILE_ATTRIBUTE_DATA) lpFileInformation;
2454 if (!DOSFS_GetFullName( lpFileName, TRUE, &full_name )) return FALSE;
2455 if (!FILE_Stat( full_name.long_name, &info )) return FALSE;
2457 lpFad->dwFileAttributes = info.dwFileAttributes;
2458 lpFad->ftCreationTime = info.ftCreationTime;
2459 lpFad->ftLastAccessTime = info.ftLastAccessTime;
2460 lpFad->ftLastWriteTime = info.ftLastWriteTime;
2461 lpFad->nFileSizeHigh = info.nFileSizeHigh;
2462 lpFad->nFileSizeLow = info.nFileSizeLow;
2464 else {
2465 FIXME("invalid info level %d!\n", fInfoLevelId);
2466 return FALSE;
2469 return TRUE;
2473 /**************************************************************************
2474 * GetFileAttributesExW [KERNEL32.875]
2476 BOOL WINAPI GetFileAttributesExW(
2477 LPCWSTR lpFileName, GET_FILEEX_INFO_LEVELS fInfoLevelId,
2478 LPVOID lpFileInformation)
2480 LPSTR nameA = HEAP_strdupWtoA( GetProcessHeap(), 0, lpFileName );
2481 BOOL res =
2482 GetFileAttributesExA( nameA, fInfoLevelId, lpFileInformation);
2483 HeapFree( GetProcessHeap(), 0, nameA );
2484 return res;