New mechanism to transfer file descriptors from client to server.
[wine/multimedia.git] / files / file.c
blobbcb62c781a4bce5eb59b3fc9cc8c1c220bf48815
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;
188 wine_server_send_fd( fd );
190 SERVER_START_REQ( alloc_file_handle )
192 req->access = access;
193 req->fd = fd;
194 SERVER_CALL();
195 ret = req->handle;
197 SERVER_END_REQ;
198 return ret;
202 /***********************************************************************
203 * FILE_GetUnixHandle
205 * Retrieve the Unix handle corresponding to a file handle.
206 * Returns -1 on failure.
208 int FILE_GetUnixHandle( HANDLE handle, DWORD access )
210 int ret, fd = -1;
211 SERVER_START_REQ( get_handle_fd )
213 req->handle = handle;
214 req->access = access;
215 if (!(ret = SERVER_CALL_ERR())) fd = req->fd;
217 SERVER_END_REQ;
218 if (!ret)
220 if (fd == -1) return wine_server_recv_fd( handle, 1 );
221 fd = dup(fd);
223 return fd;
227 /*************************************************************************
228 * FILE_OpenConsole
230 * Open a handle to the current process console.
231 * Returns 0 on failure.
233 static HANDLE FILE_OpenConsole( BOOL output, DWORD access, LPSECURITY_ATTRIBUTES sa )
235 HANDLE ret;
237 SERVER_START_REQ( open_console )
239 req->output = output;
240 req->access = access;
241 req->inherit = (sa && (sa->nLength>=sizeof(*sa)) && sa->bInheritHandle);
242 SetLastError(0);
243 SERVER_CALL_ERR();
244 ret = req->handle;
246 SERVER_END_REQ;
247 return ret;
251 /***********************************************************************
252 * FILE_CreateFile
254 * Implementation of CreateFile. Takes a Unix path name.
255 * Returns 0 on failure.
257 HANDLE FILE_CreateFile( LPCSTR filename, DWORD access, DWORD sharing,
258 LPSECURITY_ATTRIBUTES sa, DWORD creation,
259 DWORD attributes, HANDLE template, BOOL fail_read_only )
261 DWORD err;
262 HANDLE ret;
263 size_t len = strlen(filename);
265 if (len > REQUEST_MAX_VAR_SIZE)
267 FIXME("filename '%s' too long\n", filename );
268 SetLastError( ERROR_INVALID_PARAMETER );
269 return 0;
272 restart:
273 SERVER_START_VAR_REQ( create_file, len )
275 req->access = access;
276 req->inherit = (sa && (sa->nLength>=sizeof(*sa)) && sa->bInheritHandle);
277 req->sharing = sharing;
278 req->create = creation;
279 req->attrs = attributes;
280 memcpy( server_data_ptr(req), filename, len );
281 SetLastError(0);
282 err = SERVER_CALL();
283 ret = req->handle;
285 SERVER_END_VAR_REQ;
287 /* If write access failed, retry without GENERIC_WRITE */
289 if (!ret && !fail_read_only && (access & GENERIC_WRITE))
291 if ((err == STATUS_MEDIA_WRITE_PROTECTED) || (err == STATUS_ACCESS_DENIED))
293 TRACE("Write access failed for file '%s', trying without "
294 "write access\n", filename);
295 access &= ~GENERIC_WRITE;
296 goto restart;
300 if (err) SetLastError( RtlNtStatusToDosError(err) );
302 if (!ret)
303 WARN("Unable to create file '%s' (GLE %ld)\n", filename, GetLastError());
305 return ret;
309 /***********************************************************************
310 * FILE_CreateDevice
312 * Same as FILE_CreateFile but for a device
313 * Returns 0 on failure.
315 HANDLE FILE_CreateDevice( int client_id, DWORD access, LPSECURITY_ATTRIBUTES sa )
317 HANDLE ret;
318 SERVER_START_REQ( create_device )
320 req->access = access;
321 req->inherit = (sa && (sa->nLength>=sizeof(*sa)) && sa->bInheritHandle);
322 req->id = client_id;
323 SetLastError(0);
324 SERVER_CALL_ERR();
325 ret = req->handle;
327 SERVER_END_REQ;
328 return ret;
332 /*************************************************************************
333 * CreateFileA [KERNEL32.45] Creates or opens a file or other object
335 * Creates or opens an object, and returns a handle that can be used to
336 * access that object.
338 * PARAMS
340 * filename [in] pointer to filename to be accessed
341 * access [in] access mode requested
342 * sharing [in] share mode
343 * sa [in] pointer to security attributes
344 * creation [in] how to create the file
345 * attributes [in] attributes for newly created file
346 * template [in] handle to file with extended attributes to copy
348 * RETURNS
349 * Success: Open handle to specified file
350 * Failure: INVALID_HANDLE_VALUE
352 * NOTES
353 * Should call SetLastError() on failure.
355 * BUGS
357 * Doesn't support character devices, pipes, template files, or a
358 * lot of the 'attributes' flags yet.
360 HANDLE WINAPI CreateFileA( LPCSTR filename, DWORD access, DWORD sharing,
361 LPSECURITY_ATTRIBUTES sa, DWORD creation,
362 DWORD attributes, HANDLE template )
364 DOS_FULL_NAME full_name;
365 HANDLE ret;
367 if (!filename)
369 SetLastError( ERROR_INVALID_PARAMETER );
370 return INVALID_HANDLE_VALUE;
372 TRACE("%s %s%s%s%s%s%s%s\n",filename,
373 ((access & GENERIC_READ)==GENERIC_READ)?"GENERIC_READ ":"",
374 ((access & GENERIC_WRITE)==GENERIC_WRITE)?"GENERIC_WRITE ":"",
375 (!access)?"QUERY_ACCESS ":"",
376 ((sharing & FILE_SHARE_READ)==FILE_SHARE_READ)?"FILE_SHARE_READ ":"",
377 ((sharing & FILE_SHARE_WRITE)==FILE_SHARE_WRITE)?"FILE_SHARE_WRITE ":"",
378 ((sharing & FILE_SHARE_DELETE)==FILE_SHARE_DELETE)?"FILE_SHARE_DELETE ":"",
379 (creation ==CREATE_NEW)?"CREATE_NEW":
380 (creation ==CREATE_ALWAYS)?"CREATE_ALWAYS ":
381 (creation ==OPEN_EXISTING)?"OPEN_EXISTING ":
382 (creation ==OPEN_ALWAYS)?"OPEN_ALWAYS ":
383 (creation ==TRUNCATE_EXISTING)?"TRUNCATE_EXISTING ":"");
385 /* If the name starts with '\\?\', ignore the first 4 chars. */
386 if (!strncmp(filename, "\\\\?\\", 4))
388 filename += 4;
389 if (!strncmp(filename, "UNC\\", 4))
391 FIXME("UNC name (%s) not supported.\n", filename );
392 SetLastError( ERROR_PATH_NOT_FOUND );
393 return INVALID_HANDLE_VALUE;
397 if (!strncmp(filename, "\\\\.\\", 4)) {
398 if (!DOSFS_GetDevice( filename ))
400 ret = DEVICE_Open( filename+4, access, sa );
401 goto done;
403 else
404 filename+=4; /* fall into DOSFS_Device case below */
407 /* If the name still starts with '\\', it's a UNC name. */
408 if (!strncmp(filename, "\\\\", 2))
410 FIXME("UNC name (%s) not supported.\n", filename );
411 SetLastError( ERROR_PATH_NOT_FOUND );
412 return INVALID_HANDLE_VALUE;
415 /* If the name contains a DOS wild card (* or ?), do no create a file */
416 if(strchr(filename,'*') || strchr(filename,'?'))
417 return INVALID_HANDLE_VALUE;
419 /* Open a console for CONIN$ or CONOUT$ */
420 if (!strcasecmp(filename, "CONIN$"))
422 ret = FILE_OpenConsole( FALSE, access, sa );
423 goto done;
425 if (!strcasecmp(filename, "CONOUT$"))
427 ret = FILE_OpenConsole( TRUE, access, sa );
428 goto done;
431 if (DOSFS_GetDevice( filename ))
433 TRACE("opening device '%s'\n", filename );
435 if (!(ret = DOSFS_OpenDevice( filename, access )))
437 /* Do not silence this please. It is a critical error. -MM */
438 ERR("Couldn't open device '%s'!\n",filename);
439 SetLastError( ERROR_FILE_NOT_FOUND );
441 goto done;
444 /* check for filename, don't check for last entry if creating */
445 if (!DOSFS_GetFullName( filename,
446 (creation == OPEN_EXISTING) ||
447 (creation == TRUNCATE_EXISTING),
448 &full_name )) {
449 WARN("Unable to get full filename from '%s' (GLE %ld)\n",
450 filename, GetLastError());
451 return INVALID_HANDLE_VALUE;
454 ret = FILE_CreateFile( full_name.long_name, access, sharing,
455 sa, creation, attributes, template,
456 DRIVE_GetFlags(full_name.drive) & DRIVE_FAIL_READ_ONLY );
457 done:
458 if (!ret) ret = INVALID_HANDLE_VALUE;
459 return ret;
464 /*************************************************************************
465 * CreateFileW (KERNEL32.48)
467 HANDLE WINAPI CreateFileW( LPCWSTR filename, DWORD access, DWORD sharing,
468 LPSECURITY_ATTRIBUTES sa, DWORD creation,
469 DWORD attributes, HANDLE template)
471 LPSTR afn = HEAP_strdupWtoA( GetProcessHeap(), 0, filename );
472 HANDLE res = CreateFileA( afn, access, sharing, sa, creation, attributes, template );
473 HeapFree( GetProcessHeap(), 0, afn );
474 return res;
478 /***********************************************************************
479 * FILE_FillInfo
481 * Fill a file information from a struct stat.
483 static void FILE_FillInfo( struct stat *st, BY_HANDLE_FILE_INFORMATION *info )
485 if (S_ISDIR(st->st_mode))
486 info->dwFileAttributes = FILE_ATTRIBUTE_DIRECTORY;
487 else
488 info->dwFileAttributes = FILE_ATTRIBUTE_ARCHIVE;
489 if (!(st->st_mode & S_IWUSR))
490 info->dwFileAttributes |= FILE_ATTRIBUTE_READONLY;
492 RtlSecondsSince1970ToTime( st->st_mtime, &info->ftCreationTime );
493 RtlSecondsSince1970ToTime( st->st_mtime, &info->ftLastWriteTime );
494 RtlSecondsSince1970ToTime( st->st_atime, &info->ftLastAccessTime );
496 info->dwVolumeSerialNumber = 0; /* FIXME */
497 info->nFileSizeHigh = 0;
498 info->nFileSizeLow = S_ISDIR(st->st_mode) ? 0 : st->st_size;
499 info->nNumberOfLinks = st->st_nlink;
500 info->nFileIndexHigh = 0;
501 info->nFileIndexLow = st->st_ino;
505 /***********************************************************************
506 * FILE_Stat
508 * Stat a Unix path name. Return TRUE if OK.
510 BOOL FILE_Stat( LPCSTR unixName, BY_HANDLE_FILE_INFORMATION *info )
512 struct stat st;
514 if (lstat( unixName, &st ) == -1)
516 FILE_SetDosError();
517 return FALSE;
519 if (!S_ISLNK(st.st_mode)) FILE_FillInfo( &st, info );
520 else
522 /* do a "real" stat to find out
523 about the type of the symlink destination */
524 if (stat( unixName, &st ) == -1)
526 FILE_SetDosError();
527 return FALSE;
529 FILE_FillInfo( &st, info );
530 info->dwFileAttributes |= FILE_ATTRIBUTE_SYMLINK;
532 return TRUE;
536 /***********************************************************************
537 * GetFileInformationByHandle (KERNEL32.219)
539 DWORD WINAPI GetFileInformationByHandle( HANDLE hFile,
540 BY_HANDLE_FILE_INFORMATION *info )
542 DWORD ret;
543 if (!info) return 0;
545 SERVER_START_REQ( get_file_info )
547 req->handle = hFile;
548 if ((ret = !SERVER_CALL_ERR()))
550 RtlSecondsSince1970ToTime( req->write_time, &info->ftCreationTime );
551 RtlSecondsSince1970ToTime( req->write_time, &info->ftLastWriteTime );
552 RtlSecondsSince1970ToTime( req->access_time, &info->ftLastAccessTime );
553 info->dwFileAttributes = req->attr;
554 info->dwVolumeSerialNumber = req->serial;
555 info->nFileSizeHigh = req->size_high;
556 info->nFileSizeLow = req->size_low;
557 info->nNumberOfLinks = req->links;
558 info->nFileIndexHigh = req->index_high;
559 info->nFileIndexLow = req->index_low;
562 SERVER_END_REQ;
563 return ret;
567 /**************************************************************************
568 * GetFileAttributes16 (KERNEL.420)
570 DWORD WINAPI GetFileAttributes16( LPCSTR name )
572 return GetFileAttributesA( name );
576 /**************************************************************************
577 * GetFileAttributesA (KERNEL32.217)
579 DWORD WINAPI GetFileAttributesA( LPCSTR name )
581 DOS_FULL_NAME full_name;
582 BY_HANDLE_FILE_INFORMATION info;
584 if (name == NULL)
586 SetLastError( ERROR_INVALID_PARAMETER );
587 return -1;
589 if (!DOSFS_GetFullName( name, TRUE, &full_name) )
590 return -1;
591 if (!FILE_Stat( full_name.long_name, &info )) return -1;
592 return info.dwFileAttributes;
596 /**************************************************************************
597 * GetFileAttributesW (KERNEL32.218)
599 DWORD WINAPI GetFileAttributesW( LPCWSTR name )
601 LPSTR nameA = HEAP_strdupWtoA( GetProcessHeap(), 0, name );
602 DWORD res = GetFileAttributesA( nameA );
603 HeapFree( GetProcessHeap(), 0, nameA );
604 return res;
608 /***********************************************************************
609 * GetFileSize (KERNEL32.220)
611 DWORD WINAPI GetFileSize( HANDLE hFile, LPDWORD filesizehigh )
613 BY_HANDLE_FILE_INFORMATION info;
614 if (!GetFileInformationByHandle( hFile, &info )) return 0;
615 if (filesizehigh) *filesizehigh = info.nFileSizeHigh;
616 return info.nFileSizeLow;
620 /***********************************************************************
621 * GetFileTime (KERNEL32.221)
623 BOOL WINAPI GetFileTime( HANDLE hFile, FILETIME *lpCreationTime,
624 FILETIME *lpLastAccessTime,
625 FILETIME *lpLastWriteTime )
627 BY_HANDLE_FILE_INFORMATION info;
628 if (!GetFileInformationByHandle( hFile, &info )) return FALSE;
629 if (lpCreationTime) *lpCreationTime = info.ftCreationTime;
630 if (lpLastAccessTime) *lpLastAccessTime = info.ftLastAccessTime;
631 if (lpLastWriteTime) *lpLastWriteTime = info.ftLastWriteTime;
632 return TRUE;
635 /***********************************************************************
636 * CompareFileTime (KERNEL32.28)
638 INT WINAPI CompareFileTime( LPFILETIME x, LPFILETIME y )
640 if (!x || !y) return -1;
642 if (x->dwHighDateTime > y->dwHighDateTime)
643 return 1;
644 if (x->dwHighDateTime < y->dwHighDateTime)
645 return -1;
646 if (x->dwLowDateTime > y->dwLowDateTime)
647 return 1;
648 if (x->dwLowDateTime < y->dwLowDateTime)
649 return -1;
650 return 0;
653 /***********************************************************************
654 * FILE_GetTempFileName : utility for GetTempFileName
656 static UINT FILE_GetTempFileName( LPCSTR path, LPCSTR prefix, UINT unique,
657 LPSTR buffer, BOOL isWin16 )
659 static UINT unique_temp;
660 DOS_FULL_NAME full_name;
661 int i;
662 LPSTR p;
663 UINT num;
665 if ( !path || !prefix || !buffer ) return 0;
667 if (!unique_temp) unique_temp = time(NULL) & 0xffff;
668 num = unique ? (unique & 0xffff) : (unique_temp++ & 0xffff);
670 strcpy( buffer, path );
671 p = buffer + strlen(buffer);
673 /* add a \, if there isn't one and path is more than just the drive letter ... */
674 if ( !((strlen(buffer) == 2) && (buffer[1] == ':'))
675 && ((p == buffer) || (p[-1] != '\\'))) *p++ = '\\';
677 if (isWin16) *p++ = '~';
678 for (i = 3; (i > 0) && (*prefix); i--) *p++ = *prefix++;
679 sprintf( p, "%04x.tmp", num );
681 /* Now try to create it */
683 if (!unique)
687 HFILE handle = CreateFileA( buffer, GENERIC_WRITE, 0, NULL,
688 CREATE_NEW, FILE_ATTRIBUTE_NORMAL, 0 );
689 if (handle != INVALID_HANDLE_VALUE)
690 { /* We created it */
691 TRACE("created %s\n",
692 buffer);
693 CloseHandle( handle );
694 break;
696 if (GetLastError() != ERROR_FILE_EXISTS)
697 break; /* No need to go on */
698 num++;
699 sprintf( p, "%04x.tmp", num );
700 } while (num != (unique & 0xffff));
703 /* Get the full path name */
705 if (DOSFS_GetFullName( buffer, FALSE, &full_name ))
707 /* Check if we have write access in the directory */
708 if ((p = strrchr( full_name.long_name, '/' ))) *p = '\0';
709 if (access( full_name.long_name, W_OK ) == -1)
710 WARN("returns '%s', which doesn't seem to be writeable.\n",
711 buffer);
713 TRACE("returning %s\n", buffer );
714 return unique ? unique : num;
718 /***********************************************************************
719 * GetTempFileNameA (KERNEL32.290)
721 UINT WINAPI GetTempFileNameA( LPCSTR path, LPCSTR prefix, UINT unique,
722 LPSTR buffer)
724 return FILE_GetTempFileName(path, prefix, unique, buffer, FALSE);
727 /***********************************************************************
728 * GetTempFileNameW (KERNEL32.291)
730 UINT WINAPI GetTempFileNameW( LPCWSTR path, LPCWSTR prefix, UINT unique,
731 LPWSTR buffer )
733 LPSTR patha,prefixa;
734 char buffera[144];
735 UINT ret;
737 if (!path) return 0;
738 patha = HEAP_strdupWtoA( GetProcessHeap(), 0, path );
739 prefixa = HEAP_strdupWtoA( GetProcessHeap(), 0, prefix );
740 ret = FILE_GetTempFileName( patha, prefixa, unique, buffera, FALSE );
741 MultiByteToWideChar( CP_ACP, 0, buffera, -1, buffer, MAX_PATH );
742 HeapFree( GetProcessHeap(), 0, patha );
743 HeapFree( GetProcessHeap(), 0, prefixa );
744 return ret;
748 /***********************************************************************
749 * GetTempFileName16 (KERNEL.97)
751 UINT16 WINAPI GetTempFileName16( BYTE drive, LPCSTR prefix, UINT16 unique,
752 LPSTR buffer )
754 char temppath[144];
756 if (!(drive & ~TF_FORCEDRIVE)) /* drive 0 means current default drive */
757 drive |= DRIVE_GetCurrentDrive() + 'A';
759 if ((drive & TF_FORCEDRIVE) &&
760 !DRIVE_IsValid( toupper(drive & ~TF_FORCEDRIVE) - 'A' ))
762 drive &= ~TF_FORCEDRIVE;
763 WARN("invalid drive %d specified\n", drive );
766 if (drive & TF_FORCEDRIVE)
767 sprintf(temppath,"%c:", drive & ~TF_FORCEDRIVE );
768 else
769 GetTempPathA( 132, temppath );
770 return (UINT16)FILE_GetTempFileName( temppath, prefix, unique, buffer, TRUE );
773 /***********************************************************************
774 * FILE_DoOpenFile
776 * Implementation of OpenFile16() and OpenFile32().
778 static HFILE FILE_DoOpenFile( LPCSTR name, OFSTRUCT *ofs, UINT mode,
779 BOOL win32 )
781 HFILE hFileRet;
782 FILETIME filetime;
783 WORD filedatetime[2];
784 DOS_FULL_NAME full_name;
785 DWORD access, sharing;
786 char *p;
788 if (!ofs) return HFILE_ERROR;
790 TRACE("%s %s %s %s%s%s%s%s%s%s%s%s\n",name,
791 ((mode & 0x3 )==OF_READ)?"OF_READ":
792 ((mode & 0x3 )==OF_WRITE)?"OF_WRITE":
793 ((mode & 0x3 )==OF_READWRITE)?"OF_READWRITE":"unknown",
794 ((mode & 0x70 )==OF_SHARE_COMPAT)?"OF_SHARE_COMPAT":
795 ((mode & 0x70 )==OF_SHARE_DENY_NONE)?"OF_SHARE_DENY_NONE":
796 ((mode & 0x70 )==OF_SHARE_DENY_READ)?"OF_SHARE_DENY_READ":
797 ((mode & 0x70 )==OF_SHARE_DENY_WRITE)?"OF_SHARE_DENY_WRITE":
798 ((mode & 0x70 )==OF_SHARE_EXCLUSIVE)?"OF_SHARE_EXCLUSIVE":"unknown",
799 ((mode & OF_PARSE )==OF_PARSE)?"OF_PARSE ":"",
800 ((mode & OF_DELETE )==OF_DELETE)?"OF_DELETE ":"",
801 ((mode & OF_VERIFY )==OF_VERIFY)?"OF_VERIFY ":"",
802 ((mode & OF_SEARCH )==OF_SEARCH)?"OF_SEARCH ":"",
803 ((mode & OF_CANCEL )==OF_CANCEL)?"OF_CANCEL ":"",
804 ((mode & OF_CREATE )==OF_CREATE)?"OF_CREATE ":"",
805 ((mode & OF_PROMPT )==OF_PROMPT)?"OF_PROMPT ":"",
806 ((mode & OF_EXIST )==OF_EXIST)?"OF_EXIST ":"",
807 ((mode & OF_REOPEN )==OF_REOPEN)?"OF_REOPEN ":""
811 ofs->cBytes = sizeof(OFSTRUCT);
812 ofs->nErrCode = 0;
813 if (mode & OF_REOPEN) name = ofs->szPathName;
815 if (!name) {
816 ERR("called with `name' set to NULL ! Please debug.\n");
817 return HFILE_ERROR;
820 TRACE("%s %04x\n", name, mode );
822 /* the watcom 10.6 IDE relies on a valid path returned in ofs->szPathName
823 Are there any cases where getting the path here is wrong?
824 Uwe Bonnes 1997 Apr 2 */
825 if (!GetFullPathNameA( name, sizeof(ofs->szPathName),
826 ofs->szPathName, NULL )) goto error;
827 FILE_ConvertOFMode( mode, &access, &sharing );
829 /* OF_PARSE simply fills the structure */
831 if (mode & OF_PARSE)
833 ofs->fFixedDisk = (GetDriveType16( ofs->szPathName[0]-'A' )
834 != DRIVE_REMOVABLE);
835 TRACE("(%s): OF_PARSE, res = '%s'\n",
836 name, ofs->szPathName );
837 return 0;
840 /* OF_CREATE is completely different from all other options, so
841 handle it first */
843 if (mode & OF_CREATE)
845 if ((hFileRet = CreateFileA( name, GENERIC_READ | GENERIC_WRITE,
846 sharing, NULL, CREATE_ALWAYS,
847 FILE_ATTRIBUTE_NORMAL, 0 ))== INVALID_HANDLE_VALUE)
848 goto error;
849 goto success;
852 /* If OF_SEARCH is set, ignore the given path */
854 if ((mode & OF_SEARCH) && !(mode & OF_REOPEN))
856 /* First try the file name as is */
857 if (DOSFS_GetFullName( name, TRUE, &full_name )) goto found;
858 /* Now remove the path */
859 if (name[0] && (name[1] == ':')) name += 2;
860 if ((p = strrchr( name, '\\' ))) name = p + 1;
861 if ((p = strrchr( name, '/' ))) name = p + 1;
862 if (!name[0]) goto not_found;
865 /* Now look for the file */
867 if (!DIR_SearchPath( NULL, name, NULL, &full_name, win32 )) goto not_found;
869 found:
870 TRACE("found %s = %s\n",
871 full_name.long_name, full_name.short_name );
872 lstrcpynA( ofs->szPathName, full_name.short_name,
873 sizeof(ofs->szPathName) );
875 if (mode & OF_SHARE_EXCLUSIVE)
876 /* Some InstallShield version uses OF_SHARE_EXCLUSIVE
877 on the file <tempdir>/_ins0432._mp to determine how
878 far installation has proceeded.
879 _ins0432._mp is an executable and while running the
880 application expects the open with OF_SHARE_ to fail*/
881 /* Probable FIXME:
882 As our loader closes the files after loading the executable,
883 we can't find the running executable with FILE_InUse.
884 The loader should keep the file open, as Windows does that, too.
887 char *last = strrchr(full_name.long_name,'/');
888 if (!last)
889 last = full_name.long_name - 1;
890 if (GetModuleHandle16(last+1))
892 TRACE("Denying shared open for %s\n",full_name.long_name);
893 return HFILE_ERROR;
897 if (mode & OF_DELETE)
899 if (unlink( full_name.long_name ) == -1) goto not_found;
900 TRACE("(%s): OF_DELETE return = OK\n", name);
901 return 1;
904 hFileRet = FILE_CreateFile( full_name.long_name, access, sharing,
905 NULL, OPEN_EXISTING, 0, 0,
906 DRIVE_GetFlags(full_name.drive) & DRIVE_FAIL_READ_ONLY );
907 if (!hFileRet) goto not_found;
909 GetFileTime( hFileRet, NULL, NULL, &filetime );
910 FileTimeToDosDateTime( &filetime, &filedatetime[0], &filedatetime[1] );
911 if ((mode & OF_VERIFY) && (mode & OF_REOPEN))
913 if (memcmp( ofs->reserved, filedatetime, sizeof(ofs->reserved) ))
915 CloseHandle( hFileRet );
916 WARN("(%s): OF_VERIFY failed\n", name );
917 /* FIXME: what error here? */
918 SetLastError( ERROR_FILE_NOT_FOUND );
919 goto error;
922 memcpy( ofs->reserved, filedatetime, sizeof(ofs->reserved) );
924 success: /* We get here if the open was successful */
925 TRACE("(%s): OK, return = %d\n", name, hFileRet );
926 if (win32)
928 if (mode & OF_EXIST) /* Return the handle, but close it first */
929 CloseHandle( hFileRet );
931 else
933 hFileRet = Win32HandleToDosFileHandle( hFileRet );
934 if (hFileRet == HFILE_ERROR16) goto error;
935 if (mode & OF_EXIST) /* Return the handle, but close it first */
936 _lclose16( hFileRet );
938 return hFileRet;
940 not_found: /* We get here if the file does not exist */
941 WARN("'%s' not found or sharing violation\n", name );
942 SetLastError( ERROR_FILE_NOT_FOUND );
943 /* fall through */
945 error: /* We get here if there was an error opening the file */
946 ofs->nErrCode = GetLastError();
947 WARN("(%s): return = HFILE_ERROR error= %d\n",
948 name,ofs->nErrCode );
949 return HFILE_ERROR;
953 /***********************************************************************
954 * OpenFile16 (KERNEL.74)
956 HFILE16 WINAPI OpenFile16( LPCSTR name, OFSTRUCT *ofs, UINT16 mode )
958 return FILE_DoOpenFile( name, ofs, mode, FALSE );
962 /***********************************************************************
963 * OpenFile (KERNEL32.396)
965 HFILE WINAPI OpenFile( LPCSTR name, OFSTRUCT *ofs, UINT mode )
967 return FILE_DoOpenFile( name, ofs, mode, TRUE );
971 /***********************************************************************
972 * FILE_InitProcessDosHandles
974 * Allocates the default DOS handles for a process. Called either by
975 * Win32HandleToDosFileHandle below or by the DOSVM stuff.
977 static void FILE_InitProcessDosHandles( void )
979 dos_handles[0] = GetStdHandle(STD_INPUT_HANDLE);
980 dos_handles[1] = GetStdHandle(STD_OUTPUT_HANDLE);
981 dos_handles[2] = GetStdHandle(STD_ERROR_HANDLE);
982 dos_handles[3] = GetStdHandle(STD_ERROR_HANDLE);
983 dos_handles[4] = GetStdHandle(STD_ERROR_HANDLE);
986 /***********************************************************************
987 * Win32HandleToDosFileHandle (KERNEL32.21)
989 * Allocate a DOS handle for a Win32 handle. The Win32 handle is no
990 * longer valid after this function (even on failure).
992 * Note: this is not exactly right, since on Win95 the Win32 handles
993 * are on top of DOS handles and we do it the other way
994 * around. Should be good enough though.
996 HFILE WINAPI Win32HandleToDosFileHandle( HANDLE handle )
998 int i;
1000 if (!handle || (handle == INVALID_HANDLE_VALUE))
1001 return HFILE_ERROR;
1003 for (i = 5; i < DOS_TABLE_SIZE; i++)
1004 if (!dos_handles[i])
1006 dos_handles[i] = handle;
1007 TRACE("Got %d for h32 %d\n", i, handle );
1008 return (HFILE)i;
1010 CloseHandle( handle );
1011 SetLastError( ERROR_TOO_MANY_OPEN_FILES );
1012 return HFILE_ERROR;
1016 /***********************************************************************
1017 * DosFileHandleToWin32Handle (KERNEL32.20)
1019 * Return the Win32 handle for a DOS handle.
1021 * Note: this is not exactly right, since on Win95 the Win32 handles
1022 * are on top of DOS handles and we do it the other way
1023 * around. Should be good enough though.
1025 HANDLE WINAPI DosFileHandleToWin32Handle( HFILE handle )
1027 HFILE16 hfile = (HFILE16)handle;
1028 if (hfile < 5 && !dos_handles[hfile]) FILE_InitProcessDosHandles();
1029 if ((hfile >= DOS_TABLE_SIZE) || !dos_handles[hfile])
1031 SetLastError( ERROR_INVALID_HANDLE );
1032 return INVALID_HANDLE_VALUE;
1034 return dos_handles[hfile];
1038 /***********************************************************************
1039 * DisposeLZ32Handle (KERNEL32.22)
1041 * Note: this is not entirely correct, we should only close the
1042 * 32-bit handle and not the 16-bit one, but we cannot do
1043 * this because of the way our DOS handles are implemented.
1044 * It shouldn't break anything though.
1046 void WINAPI DisposeLZ32Handle( HANDLE handle )
1048 int i;
1050 if (!handle || (handle == INVALID_HANDLE_VALUE)) return;
1052 for (i = 5; i < DOS_TABLE_SIZE; i++)
1053 if (dos_handles[i] == handle)
1055 dos_handles[i] = 0;
1056 CloseHandle( handle );
1057 break;
1062 /***********************************************************************
1063 * FILE_Dup2
1065 * dup2() function for DOS handles.
1067 HFILE16 FILE_Dup2( HFILE16 hFile1, HFILE16 hFile2 )
1069 HANDLE new_handle;
1071 if (hFile1 < 5 && !dos_handles[hFile1]) FILE_InitProcessDosHandles();
1073 if ((hFile1 >= DOS_TABLE_SIZE) || (hFile2 >= DOS_TABLE_SIZE) || !dos_handles[hFile1])
1075 SetLastError( ERROR_INVALID_HANDLE );
1076 return HFILE_ERROR16;
1078 if (hFile2 < 5)
1080 FIXME("stdio handle closed, need proper conversion\n" );
1081 SetLastError( ERROR_INVALID_HANDLE );
1082 return HFILE_ERROR16;
1084 if (!DuplicateHandle( GetCurrentProcess(), dos_handles[hFile1],
1085 GetCurrentProcess(), &new_handle,
1086 0, FALSE, DUPLICATE_SAME_ACCESS ))
1087 return HFILE_ERROR16;
1088 if (dos_handles[hFile2]) CloseHandle( dos_handles[hFile2] );
1089 dos_handles[hFile2] = new_handle;
1090 return hFile2;
1094 /***********************************************************************
1095 * _lclose16 (KERNEL.81)
1097 HFILE16 WINAPI _lclose16( HFILE16 hFile )
1099 if (hFile < 5)
1101 FIXME("stdio handle closed, need proper conversion\n" );
1102 SetLastError( ERROR_INVALID_HANDLE );
1103 return HFILE_ERROR16;
1105 if ((hFile >= DOS_TABLE_SIZE) || !dos_handles[hFile])
1107 SetLastError( ERROR_INVALID_HANDLE );
1108 return HFILE_ERROR16;
1110 TRACE("%d (handle32=%d)\n", hFile, dos_handles[hFile] );
1111 CloseHandle( dos_handles[hFile] );
1112 dos_handles[hFile] = 0;
1113 return 0;
1117 /***********************************************************************
1118 * _lclose (KERNEL32.592)
1120 HFILE WINAPI _lclose( HFILE hFile )
1122 TRACE("handle %d\n", hFile );
1123 return CloseHandle( hFile ) ? 0 : HFILE_ERROR;
1126 /***********************************************************************
1127 * GetOverlappedResult (KERNEL32.360)
1129 * Check the result of an Asynchronous data transfer from a file.
1131 * RETURNS
1132 * TRUE on success
1133 * FALSE on failure
1135 * If successful (and relevant) lpTransfered will hold the number of
1136 * bytes transfered during the async operation.
1138 * BUGS
1140 * Currently only works for WaitCommEvent, ReadFile, WriteFile
1141 * with communications ports.
1144 BOOL WINAPI GetOverlappedResult(
1145 HANDLE hFile, /* [in] handle of file to check on */
1146 LPOVERLAPPED lpOverlapped, /* [in/out] pointer to overlapped */
1147 LPDWORD lpTransferred, /* [in/out] number of bytes transfered */
1148 BOOL bWait /* [in] wait for the transfer to complete ? */
1150 DWORD r;
1152 TRACE("(%d %p %p %x)\n", hFile, lpOverlapped, lpTransferred, bWait);
1154 if(lpOverlapped==NULL)
1156 ERR("lpOverlapped was null\n");
1157 return FALSE;
1159 if(!lpOverlapped->hEvent)
1161 ERR("lpOverlapped->hEvent was null\n");
1162 return FALSE;
1165 do {
1166 TRACE("waiting on %p\n",lpOverlapped);
1167 r = WaitForSingleObjectEx(lpOverlapped->hEvent, bWait?INFINITE:0, TRUE);
1168 TRACE("wait on %p returned %ld\n",lpOverlapped,r);
1169 } while (r==STATUS_USER_APC);
1171 if(lpTransferred)
1172 *lpTransferred = lpOverlapped->InternalHigh;
1174 SetLastError(lpOverlapped->Internal);
1176 return (r==WAIT_OBJECT_0);
1179 /***********************************************************************
1180 * FILE_AsyncResult (INTERNAL)
1182 static int FILE_AsyncResult(HANDLE hAsync, int result)
1184 int r;
1186 SERVER_START_REQ( async_result )
1188 req->ov_handle = hAsync;
1189 req->result = result;
1190 r = SERVER_CALL_ERR();
1192 SERVER_END_REQ;
1193 return !r;
1196 /***********************************************************************
1197 * FILE_AsyncReadService (INTERNAL)
1199 static void FILE_AsyncReadService(void **args)
1201 LPOVERLAPPED lpOverlapped = (LPOVERLAPPED)args[0];
1202 LPDWORD buffer = (LPDWORD)args[1];
1203 DWORD events = (DWORD)args[2];
1204 int fd, result, r;
1206 TRACE("%p %p %08lx\n", lpOverlapped, buffer, events );
1208 /* if there are no events, it must be a timeout */
1209 if(events==0)
1211 TRACE("read timed out\n");
1212 /* r = STATUS_TIMEOUT; */
1213 r = STATUS_SUCCESS;
1214 goto async_end;
1217 fd = FILE_GetUnixHandle(lpOverlapped->Offset, GENERIC_READ);
1218 if(fd<0)
1220 TRACE("FILE_GetUnixHandle(%ld) failed \n",lpOverlapped->Offset);
1221 r = STATUS_UNSUCCESSFUL;
1222 goto async_end;
1225 /* check to see if the data is ready (non-blocking) */
1226 result = read(fd, &buffer[lpOverlapped->InternalHigh],
1227 lpOverlapped->OffsetHigh - lpOverlapped->InternalHigh);
1228 close(fd);
1230 if ( (result<0) && ((errno == EAGAIN) || (errno == EINTR)))
1232 TRACE("Deferred read %d\n",errno);
1233 r = STATUS_PENDING;
1234 goto async_end;
1237 /* check to see if the transfer is complete */
1238 if(result<0)
1240 TRACE("read returned errno %d\n",errno);
1241 r = STATUS_UNSUCCESSFUL;
1242 goto async_end;
1245 lpOverlapped->InternalHigh += result;
1246 TRACE("read %d more bytes %ld/%ld so far\n",result,lpOverlapped->InternalHigh,lpOverlapped->OffsetHigh);
1248 if(lpOverlapped->InternalHigh < lpOverlapped->OffsetHigh)
1249 r = STATUS_PENDING;
1250 else
1251 r = STATUS_SUCCESS;
1253 async_end:
1254 lpOverlapped->Internal = r;
1255 if ( (r!=STATUS_PENDING)
1256 || (!FILE_AsyncResult( lpOverlapped->InternalHigh, r)))
1258 /* close the handle to the async operation */
1259 if(lpOverlapped->Offset)
1260 CloseHandle(lpOverlapped->Offset);
1261 lpOverlapped->Offset = 0;
1263 NtSetEvent( lpOverlapped->hEvent, NULL );
1264 TRACE("set event flag\n");
1268 /***********************************************************************
1269 * FILE_StartAsyncRead (INTERNAL)
1271 static BOOL FILE_StartAsyncRead( HANDLE hFile, LPOVERLAPPED overlapped, LPVOID buffer, DWORD count)
1273 int r;
1275 SERVER_START_REQ( create_async )
1277 req->file_handle = hFile;
1278 req->overlapped = overlapped;
1279 req->buffer = buffer;
1280 req->count = count;
1281 req->func = FILE_AsyncReadService;
1282 req->type = ASYNC_TYPE_READ;
1284 r=SERVER_CALL_ERR();
1286 overlapped->Offset = req->ov_handle;
1288 SERVER_END_REQ;
1290 if(!r)
1292 TRACE("ov=%ld IO is pending!!!\n",overlapped->Offset);
1293 SetLastError(ERROR_IO_PENDING);
1296 return !r;
1299 /***********************************************************************
1300 * ReadFile (KERNEL32.577)
1302 BOOL WINAPI ReadFile( HANDLE hFile, LPVOID buffer, DWORD bytesToRead,
1303 LPDWORD bytesRead, LPOVERLAPPED overlapped )
1305 int unix_handle, result;
1307 TRACE("%d %p %ld %p %p\n", hFile, buffer, bytesToRead,
1308 bytesRead, overlapped );
1310 if (bytesRead) *bytesRead = 0; /* Do this before anything else */
1311 if (!bytesToRead) return TRUE;
1313 /* this will only have impact if the overlapped structure is specified */
1314 if ( overlapped )
1316 /* if overlapped, check that there is an event flag */
1317 if ( (overlapped->hEvent == 0) ||
1318 (overlapped->hEvent == INVALID_HANDLE_VALUE) )
1320 return FALSE;
1323 overlapped->Offset = 0;
1324 overlapped->OffsetHigh = bytesToRead;
1325 overlapped->Internal = 0;
1326 overlapped->InternalHigh = 0;
1328 NtResetEvent( overlapped->hEvent, NULL );
1330 if(FILE_StartAsyncRead(hFile, overlapped, buffer, bytesToRead))
1332 overlapped->Internal = STATUS_PENDING;
1335 /* always fail on return, either ERROR_IO_PENDING or other error */
1336 return FALSE;
1339 unix_handle = FILE_GetUnixHandle( hFile, GENERIC_READ );
1340 if (unix_handle == -1) return FALSE;
1342 /* code for synchronous reads */
1343 while ((result = read( unix_handle, buffer, bytesToRead )) == -1)
1345 if ((errno == EAGAIN) || (errno == EINTR)) continue;
1346 if ((errno == EFAULT) && !IsBadWritePtr( buffer, bytesToRead )) continue;
1347 FILE_SetDosError();
1348 break;
1350 close( unix_handle );
1351 if (result == -1) return FALSE;
1352 if (bytesRead) *bytesRead = result;
1353 return TRUE;
1356 /***********************************************************************
1357 * FILE_AsyncWriteService (INTERNAL)
1359 static void FILE_AsyncWriteService(void **args)
1361 LPOVERLAPPED lpOverlapped = (LPOVERLAPPED)args[0];
1362 LPDWORD buffer = (LPDWORD)args[1];
1363 DWORD events = (DWORD)args[2];
1364 int fd, result, r;
1366 TRACE("(%p %p %lx)\n",lpOverlapped,buffer,events);
1368 /* if there are no events, it must be a timeout */
1369 if(events==0)
1371 TRACE("write timed out\n");
1372 r = STATUS_TIMEOUT;
1373 goto async_end;
1376 fd = FILE_GetUnixHandle(lpOverlapped->Offset, GENERIC_WRITE);
1377 if(fd<0)
1379 ERR("FILE_GetUnixHandle(%ld) failed \n",lpOverlapped->Offset);
1380 r = STATUS_UNSUCCESSFUL;
1381 goto async_end;
1384 /* write some data (non-blocking) */
1385 result = write(fd, &buffer[lpOverlapped->InternalHigh],
1386 lpOverlapped->OffsetHigh-lpOverlapped->InternalHigh);
1387 close(fd);
1389 if ( (result<0) && ((errno == EAGAIN) || (errno == EINTR)))
1391 r = STATUS_PENDING;
1392 goto async_end;
1395 /* check to see if the transfer is complete */
1396 if(result<0)
1398 r = STATUS_UNSUCCESSFUL;
1399 goto async_end;
1402 lpOverlapped->InternalHigh += result;
1404 if(lpOverlapped->InternalHigh < lpOverlapped->OffsetHigh)
1405 r = STATUS_PENDING;
1406 else
1407 r = STATUS_SUCCESS;
1409 async_end:
1410 lpOverlapped->Internal = r;
1411 if ( (r!=STATUS_PENDING)
1412 || (!FILE_AsyncResult( lpOverlapped->Offset, r)))
1414 /* close the handle to the async operation */
1415 CloseHandle(lpOverlapped->Offset);
1416 lpOverlapped->Offset = 0;
1418 NtSetEvent( lpOverlapped->hEvent, NULL );
1422 /***********************************************************************
1423 * FILE_StartAsyncWrite (INTERNAL)
1425 static BOOL FILE_StartAsyncWrite(HANDLE hFile, LPOVERLAPPED overlapped, LPCVOID buffer,DWORD count)
1427 int r;
1429 SERVER_START_REQ( create_async )
1431 req->file_handle = hFile;
1432 req->buffer = (LPVOID)buffer;
1433 req->overlapped = overlapped;
1434 req->count = 0;
1435 req->func = FILE_AsyncWriteService;
1436 req->type = ASYNC_TYPE_WRITE;
1438 r = SERVER_CALL_ERR();
1440 overlapped->Offset = req->ov_handle;
1442 SERVER_END_REQ;
1444 if(!r)
1446 SetLastError(ERROR_IO_PENDING);
1449 return !r;
1452 /***********************************************************************
1453 * WriteFile (KERNEL32.738)
1455 BOOL WINAPI WriteFile( HANDLE hFile, LPCVOID buffer, DWORD bytesToWrite,
1456 LPDWORD bytesWritten, LPOVERLAPPED overlapped )
1458 int unix_handle, result;
1460 TRACE("%d %p %ld %p %p\n", hFile, buffer, bytesToWrite,
1461 bytesWritten, overlapped );
1463 if (bytesWritten) *bytesWritten = 0; /* Do this before anything else */
1464 if (!bytesToWrite) return TRUE;
1466 /* this will only have impact if the overlappd structure is specified */
1467 if ( overlapped )
1469 if ( (overlapped->hEvent == 0) ||
1470 (overlapped->hEvent == INVALID_HANDLE_VALUE) )
1471 return FALSE;
1473 overlapped->Offset = 0;
1474 overlapped->OffsetHigh = bytesToWrite;
1475 overlapped->Internal = 0;
1476 overlapped->InternalHigh = 0;
1478 NtResetEvent( overlapped->hEvent, NULL );
1480 if (FILE_StartAsyncWrite(hFile, overlapped, buffer, bytesToWrite))
1482 overlapped->Internal = STATUS_PENDING;
1485 /* always fail on return, either ERROR_IO_PENDING or other error */
1486 return FALSE;
1489 unix_handle = FILE_GetUnixHandle( hFile, GENERIC_WRITE );
1490 if (unix_handle == -1) return FALSE;
1492 /* synchronous file write */
1493 while ((result = write( unix_handle, buffer, bytesToWrite )) == -1)
1495 if ((errno == EAGAIN) || (errno == EINTR)) continue;
1496 if ((errno == EFAULT) && !IsBadReadPtr( buffer, bytesToWrite )) continue;
1497 if (errno == ENOSPC)
1498 SetLastError( ERROR_DISK_FULL );
1499 else
1500 FILE_SetDosError();
1501 break;
1503 close( unix_handle );
1504 if (result == -1) return FALSE;
1505 if (bytesWritten) *bytesWritten = result;
1506 return TRUE;
1510 /***********************************************************************
1511 * WIN16_hread
1513 LONG WINAPI WIN16_hread( HFILE16 hFile, SEGPTR buffer, LONG count )
1515 LONG maxlen;
1517 TRACE("%d %08lx %ld\n",
1518 hFile, (DWORD)buffer, count );
1520 /* Some programs pass a count larger than the allocated buffer */
1521 maxlen = GetSelectorLimit16( SELECTOROF(buffer) ) - OFFSETOF(buffer) + 1;
1522 if (count > maxlen) count = maxlen;
1523 return _lread(DosFileHandleToWin32Handle(hFile), MapSL(buffer), count );
1527 /***********************************************************************
1528 * WIN16_lread
1530 UINT16 WINAPI WIN16_lread( HFILE16 hFile, SEGPTR buffer, UINT16 count )
1532 return (UINT16)WIN16_hread( hFile, buffer, (LONG)count );
1536 /***********************************************************************
1537 * _lread (KERNEL32.596)
1539 UINT WINAPI _lread( HFILE handle, LPVOID buffer, UINT count )
1541 DWORD result;
1542 if (!ReadFile( handle, buffer, count, &result, NULL )) return -1;
1543 return result;
1547 /***********************************************************************
1548 * _lread16 (KERNEL.82)
1550 UINT16 WINAPI _lread16( HFILE16 hFile, LPVOID buffer, UINT16 count )
1552 return (UINT16)_lread(DosFileHandleToWin32Handle(hFile), buffer, (LONG)count );
1556 /***********************************************************************
1557 * _lcreat16 (KERNEL.83)
1559 HFILE16 WINAPI _lcreat16( LPCSTR path, INT16 attr )
1561 return Win32HandleToDosFileHandle( _lcreat( path, attr ) );
1565 /***********************************************************************
1566 * _lcreat (KERNEL32.593)
1568 HFILE WINAPI _lcreat( LPCSTR path, INT attr )
1570 /* Mask off all flags not explicitly allowed by the doc */
1571 attr &= FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM;
1572 TRACE("%s %02x\n", path, attr );
1573 return CreateFileA( path, GENERIC_READ | GENERIC_WRITE,
1574 FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
1575 CREATE_ALWAYS, attr, 0 );
1579 /***********************************************************************
1580 * SetFilePointer (KERNEL32.492)
1582 DWORD WINAPI SetFilePointer( HANDLE hFile, LONG distance, LONG *highword,
1583 DWORD method )
1585 DWORD ret = 0xffffffff;
1587 if (highword &&
1588 ((distance >= 0 && *highword != 0) || (distance < 0 && *highword != -1)))
1590 FIXME("64-bit offsets not supported yet\n"
1591 "SetFilePointer(%08x,%08lx,%08lx,%08lx)\n",
1592 hFile,distance,*highword,method);
1593 SetLastError( ERROR_INVALID_PARAMETER );
1594 return ret;
1596 TRACE("handle %d offset %ld origin %ld\n",
1597 hFile, distance, method );
1599 SERVER_START_REQ( set_file_pointer )
1601 req->handle = hFile;
1602 req->low = distance;
1603 req->high = highword ? *highword : (distance >= 0) ? 0 : -1;
1604 /* FIXME: assumes 1:1 mapping between Windows and Unix seek constants */
1605 req->whence = method;
1606 SetLastError( 0 );
1607 if (!SERVER_CALL_ERR())
1609 ret = req->new_low;
1610 if (highword) *highword = req->new_high;
1613 SERVER_END_REQ;
1614 return ret;
1618 /***********************************************************************
1619 * _llseek16 (KERNEL.84)
1621 * FIXME:
1622 * Seeking before the start of the file should be allowed for _llseek16,
1623 * but cause subsequent I/O operations to fail (cf. interrupt list)
1626 LONG WINAPI _llseek16( HFILE16 hFile, LONG lOffset, INT16 nOrigin )
1628 return SetFilePointer( DosFileHandleToWin32Handle(hFile), lOffset, NULL, nOrigin );
1632 /***********************************************************************
1633 * _llseek (KERNEL32.594)
1635 LONG WINAPI _llseek( HFILE hFile, LONG lOffset, INT nOrigin )
1637 return SetFilePointer( hFile, lOffset, NULL, nOrigin );
1641 /***********************************************************************
1642 * _lopen16 (KERNEL.85)
1644 HFILE16 WINAPI _lopen16( LPCSTR path, INT16 mode )
1646 return Win32HandleToDosFileHandle( _lopen( path, mode ) );
1650 /***********************************************************************
1651 * _lopen (KERNEL32.595)
1653 HFILE WINAPI _lopen( LPCSTR path, INT mode )
1655 DWORD access, sharing;
1657 TRACE("('%s',%04x)\n", path, mode );
1658 FILE_ConvertOFMode( mode, &access, &sharing );
1659 return CreateFileA( path, access, sharing, NULL, OPEN_EXISTING, 0, 0 );
1663 /***********************************************************************
1664 * _lwrite16 (KERNEL.86)
1666 UINT16 WINAPI _lwrite16( HFILE16 hFile, LPCSTR buffer, UINT16 count )
1668 return (UINT16)_hwrite( DosFileHandleToWin32Handle(hFile), buffer, (LONG)count );
1671 /***********************************************************************
1672 * _lwrite (KERNEL32.761)
1674 UINT WINAPI _lwrite( HFILE hFile, LPCSTR buffer, UINT count )
1676 return (UINT)_hwrite( hFile, buffer, (LONG)count );
1680 /***********************************************************************
1681 * _hread16 (KERNEL.349)
1683 LONG WINAPI _hread16( HFILE16 hFile, LPVOID buffer, LONG count)
1685 return _lread( DosFileHandleToWin32Handle(hFile), buffer, count );
1689 /***********************************************************************
1690 * _hread (KERNEL32.590)
1692 LONG WINAPI _hread( HFILE hFile, LPVOID buffer, LONG count)
1694 return _lread( hFile, buffer, count );
1698 /***********************************************************************
1699 * _hwrite16 (KERNEL.350)
1701 LONG WINAPI _hwrite16( HFILE16 hFile, LPCSTR buffer, LONG count )
1703 return _hwrite( DosFileHandleToWin32Handle(hFile), buffer, count );
1707 /***********************************************************************
1708 * _hwrite (KERNEL32.591)
1710 * experimentation yields that _lwrite:
1711 * o truncates the file at the current position with
1712 * a 0 len write
1713 * o returns 0 on a 0 length write
1714 * o works with console handles
1717 LONG WINAPI _hwrite( HFILE handle, LPCSTR buffer, LONG count )
1719 DWORD result;
1721 TRACE("%d %p %ld\n", handle, buffer, count );
1723 if (!count)
1725 /* Expand or truncate at current position */
1726 if (!SetEndOfFile( handle )) return HFILE_ERROR;
1727 return 0;
1729 if (!WriteFile( handle, buffer, count, &result, NULL ))
1730 return HFILE_ERROR;
1731 return result;
1735 /***********************************************************************
1736 * SetHandleCount16 (KERNEL.199)
1738 UINT16 WINAPI SetHandleCount16( UINT16 count )
1740 return SetHandleCount( count );
1744 /*************************************************************************
1745 * SetHandleCount (KERNEL32.494)
1747 UINT WINAPI SetHandleCount( UINT count )
1749 return min( 256, count );
1753 /***********************************************************************
1754 * FlushFileBuffers (KERNEL32.133)
1756 BOOL WINAPI FlushFileBuffers( HANDLE hFile )
1758 BOOL ret;
1759 SERVER_START_REQ( flush_file )
1761 req->handle = hFile;
1762 ret = !SERVER_CALL_ERR();
1764 SERVER_END_REQ;
1765 return ret;
1769 /**************************************************************************
1770 * SetEndOfFile (KERNEL32.483)
1772 BOOL WINAPI SetEndOfFile( HANDLE hFile )
1774 BOOL ret;
1775 SERVER_START_REQ( truncate_file )
1777 req->handle = hFile;
1778 ret = !SERVER_CALL_ERR();
1780 SERVER_END_REQ;
1781 return ret;
1785 /***********************************************************************
1786 * DeleteFile16 (KERNEL.146)
1788 BOOL16 WINAPI DeleteFile16( LPCSTR path )
1790 return DeleteFileA( path );
1794 /***********************************************************************
1795 * DeleteFileA (KERNEL32.71)
1797 BOOL WINAPI DeleteFileA( LPCSTR path )
1799 DOS_FULL_NAME full_name;
1801 TRACE("'%s'\n", path );
1803 if (!*path)
1805 ERR("Empty path passed\n");
1806 return FALSE;
1808 if (DOSFS_GetDevice( path ))
1810 WARN("cannot remove DOS device '%s'!\n", path);
1811 SetLastError( ERROR_FILE_NOT_FOUND );
1812 return FALSE;
1815 if (!DOSFS_GetFullName( path, TRUE, &full_name )) return FALSE;
1816 if (unlink( full_name.long_name ) == -1)
1818 FILE_SetDosError();
1819 return FALSE;
1821 return TRUE;
1825 /***********************************************************************
1826 * DeleteFileW (KERNEL32.72)
1828 BOOL WINAPI DeleteFileW( LPCWSTR path )
1830 LPSTR xpath = HEAP_strdupWtoA( GetProcessHeap(), 0, path );
1831 BOOL ret = DeleteFileA( xpath );
1832 HeapFree( GetProcessHeap(), 0, xpath );
1833 return ret;
1837 /***********************************************************************
1838 * GetFileType (KERNEL32.222)
1840 DWORD WINAPI GetFileType( HANDLE hFile )
1842 DWORD ret = FILE_TYPE_UNKNOWN;
1843 SERVER_START_REQ( get_file_info )
1845 req->handle = hFile;
1846 if (!SERVER_CALL_ERR()) ret = req->type;
1848 SERVER_END_REQ;
1849 return ret;
1853 /**************************************************************************
1854 * MoveFileExA (KERNEL32.???)
1856 BOOL WINAPI MoveFileExA( LPCSTR fn1, LPCSTR fn2, DWORD flag )
1858 DOS_FULL_NAME full_name1, full_name2;
1860 TRACE("(%s,%s,%04lx)\n", fn1, fn2, flag);
1862 if (!DOSFS_GetFullName( fn1, TRUE, &full_name1 )) return FALSE;
1864 if (fn2) /* !fn2 means delete fn1 */
1866 if (DOSFS_GetFullName( fn2, TRUE, &full_name2 ))
1868 /* target exists, check if we may overwrite */
1869 if (!(flag & MOVEFILE_REPLACE_EXISTING))
1871 /* FIXME: Use right error code */
1872 SetLastError( ERROR_ACCESS_DENIED );
1873 return FALSE;
1876 else if (!DOSFS_GetFullName( fn2, FALSE, &full_name2 )) return FALSE;
1878 /* Source name and target path are valid */
1880 if (flag & MOVEFILE_DELAY_UNTIL_REBOOT)
1882 /* FIXME: (bon@elektron.ikp.physik.th-darmstadt.de 970706)
1883 Perhaps we should queue these command and execute it
1884 when exiting... What about using on_exit(2)
1886 FIXME("Please move existing file '%s' to file '%s' when Wine has finished\n",
1887 full_name1.long_name, full_name2.long_name);
1888 return TRUE;
1891 if (full_name1.drive != full_name2.drive)
1893 /* use copy, if allowed */
1894 if (!(flag & MOVEFILE_COPY_ALLOWED))
1896 /* FIXME: Use right error code */
1897 SetLastError( ERROR_FILE_EXISTS );
1898 return FALSE;
1900 return CopyFileA( fn1, fn2, !(flag & MOVEFILE_REPLACE_EXISTING) );
1902 if (rename( full_name1.long_name, full_name2.long_name ) == -1)
1904 FILE_SetDosError();
1905 return FALSE;
1907 return TRUE;
1909 else /* fn2 == NULL means delete source */
1911 if (flag & MOVEFILE_DELAY_UNTIL_REBOOT)
1913 if (flag & MOVEFILE_COPY_ALLOWED) {
1914 WARN("Illegal flag\n");
1915 SetLastError( ERROR_GEN_FAILURE );
1916 return FALSE;
1918 /* FIXME: (bon@elektron.ikp.physik.th-darmstadt.de 970706)
1919 Perhaps we should queue these command and execute it
1920 when exiting... What about using on_exit(2)
1922 FIXME("Please delete file '%s' when Wine has finished\n",
1923 full_name1.long_name);
1924 return TRUE;
1927 if (unlink( full_name1.long_name ) == -1)
1929 FILE_SetDosError();
1930 return FALSE;
1932 return TRUE; /* successfully deleted */
1936 /**************************************************************************
1937 * MoveFileExW (KERNEL32.???)
1939 BOOL WINAPI MoveFileExW( LPCWSTR fn1, LPCWSTR fn2, DWORD flag )
1941 LPSTR afn1 = HEAP_strdupWtoA( GetProcessHeap(), 0, fn1 );
1942 LPSTR afn2 = HEAP_strdupWtoA( GetProcessHeap(), 0, fn2 );
1943 BOOL res = MoveFileExA( afn1, afn2, flag );
1944 HeapFree( GetProcessHeap(), 0, afn1 );
1945 HeapFree( GetProcessHeap(), 0, afn2 );
1946 return res;
1950 /**************************************************************************
1951 * MoveFileA (KERNEL32.387)
1953 * Move file or directory
1955 BOOL WINAPI MoveFileA( LPCSTR fn1, LPCSTR fn2 )
1957 DOS_FULL_NAME full_name1, full_name2;
1958 struct stat fstat;
1960 TRACE("(%s,%s)\n", fn1, fn2 );
1962 if (!DOSFS_GetFullName( fn1, TRUE, &full_name1 )) return FALSE;
1963 if (DOSFS_GetFullName( fn2, TRUE, &full_name2 )) {
1964 /* The new name must not already exist */
1965 SetLastError(ERROR_ALREADY_EXISTS);
1966 return FALSE;
1968 if (!DOSFS_GetFullName( fn2, FALSE, &full_name2 )) return FALSE;
1970 if (full_name1.drive == full_name2.drive) /* move */
1971 if (rename( full_name1.long_name, full_name2.long_name ) == -1)
1973 FILE_SetDosError();
1974 return FALSE;
1976 else return TRUE;
1977 else /*copy */ {
1978 if (stat( full_name1.long_name, &fstat ))
1980 WARN("Invalid source file %s\n",
1981 full_name1.long_name);
1982 FILE_SetDosError();
1983 return FALSE;
1985 if (S_ISDIR(fstat.st_mode)) {
1986 /* No Move for directories across file systems */
1987 /* FIXME: Use right error code */
1988 SetLastError( ERROR_GEN_FAILURE );
1989 return FALSE;
1991 else
1992 return CopyFileA(fn1, fn2, TRUE); /*fail, if exist */
1997 /**************************************************************************
1998 * MoveFileW (KERNEL32.390)
2000 BOOL WINAPI MoveFileW( LPCWSTR fn1, LPCWSTR fn2 )
2002 LPSTR afn1 = HEAP_strdupWtoA( GetProcessHeap(), 0, fn1 );
2003 LPSTR afn2 = HEAP_strdupWtoA( GetProcessHeap(), 0, fn2 );
2004 BOOL res = MoveFileA( afn1, afn2 );
2005 HeapFree( GetProcessHeap(), 0, afn1 );
2006 HeapFree( GetProcessHeap(), 0, afn2 );
2007 return res;
2011 /**************************************************************************
2012 * CopyFileA (KERNEL32.36)
2014 BOOL WINAPI CopyFileA( LPCSTR source, LPCSTR dest, BOOL fail_if_exists )
2016 HFILE h1, h2;
2017 BY_HANDLE_FILE_INFORMATION info;
2018 UINT count;
2019 BOOL ret = FALSE;
2020 int mode;
2021 char buffer[2048];
2023 if ((h1 = _lopen( source, OF_READ )) == HFILE_ERROR) return FALSE;
2024 if (!GetFileInformationByHandle( h1, &info ))
2026 CloseHandle( h1 );
2027 return FALSE;
2029 mode = (info.dwFileAttributes & FILE_ATTRIBUTE_READONLY) ? 0444 : 0666;
2030 if ((h2 = CreateFileA( dest, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
2031 fail_if_exists ? CREATE_NEW : CREATE_ALWAYS,
2032 info.dwFileAttributes, h1 )) == INVALID_HANDLE_VALUE)
2034 CloseHandle( h1 );
2035 return FALSE;
2037 while ((count = _lread( h1, buffer, sizeof(buffer) )) > 0)
2039 char *p = buffer;
2040 while (count > 0)
2042 INT res = _lwrite( h2, p, count );
2043 if (res <= 0) goto done;
2044 p += res;
2045 count -= res;
2048 ret = TRUE;
2049 done:
2050 CloseHandle( h1 );
2051 CloseHandle( h2 );
2052 return ret;
2056 /**************************************************************************
2057 * CopyFileW (KERNEL32.37)
2059 BOOL WINAPI CopyFileW( LPCWSTR source, LPCWSTR dest, BOOL fail_if_exists)
2061 LPSTR sourceA = HEAP_strdupWtoA( GetProcessHeap(), 0, source );
2062 LPSTR destA = HEAP_strdupWtoA( GetProcessHeap(), 0, dest );
2063 BOOL ret = CopyFileA( sourceA, destA, fail_if_exists );
2064 HeapFree( GetProcessHeap(), 0, sourceA );
2065 HeapFree( GetProcessHeap(), 0, destA );
2066 return ret;
2070 /**************************************************************************
2071 * CopyFileExA (KERNEL32.858)
2073 * This implementation ignores most of the extra parameters passed-in into
2074 * the "ex" version of the method and calls the CopyFile method.
2075 * It will have to be fixed eventually.
2077 BOOL WINAPI CopyFileExA(LPCSTR sourceFilename,
2078 LPCSTR destFilename,
2079 LPPROGRESS_ROUTINE progressRoutine,
2080 LPVOID appData,
2081 LPBOOL cancelFlagPointer,
2082 DWORD copyFlags)
2084 BOOL failIfExists = FALSE;
2087 * Interpret the only flag that CopyFile can interpret.
2089 if ( (copyFlags & COPY_FILE_FAIL_IF_EXISTS) != 0)
2091 failIfExists = TRUE;
2094 return CopyFileA(sourceFilename, destFilename, failIfExists);
2097 /**************************************************************************
2098 * CopyFileExW (KERNEL32.859)
2100 BOOL WINAPI CopyFileExW(LPCWSTR sourceFilename,
2101 LPCWSTR destFilename,
2102 LPPROGRESS_ROUTINE progressRoutine,
2103 LPVOID appData,
2104 LPBOOL cancelFlagPointer,
2105 DWORD copyFlags)
2107 LPSTR sourceA = HEAP_strdupWtoA( GetProcessHeap(), 0, sourceFilename );
2108 LPSTR destA = HEAP_strdupWtoA( GetProcessHeap(), 0, destFilename );
2110 BOOL ret = CopyFileExA(sourceA,
2111 destA,
2112 progressRoutine,
2113 appData,
2114 cancelFlagPointer,
2115 copyFlags);
2117 HeapFree( GetProcessHeap(), 0, sourceA );
2118 HeapFree( GetProcessHeap(), 0, destA );
2120 return ret;
2124 /***********************************************************************
2125 * SetFileTime (KERNEL32.650)
2127 BOOL WINAPI SetFileTime( HANDLE hFile,
2128 const FILETIME *lpCreationTime,
2129 const FILETIME *lpLastAccessTime,
2130 const FILETIME *lpLastWriteTime )
2132 BOOL ret;
2133 SERVER_START_REQ( set_file_time )
2135 req->handle = hFile;
2136 if (lpLastAccessTime)
2137 RtlTimeToSecondsSince1970( lpLastAccessTime, (DWORD *)&req->access_time );
2138 else
2139 req->access_time = 0; /* FIXME */
2140 if (lpLastWriteTime)
2141 RtlTimeToSecondsSince1970( lpLastWriteTime, (DWORD *)&req->write_time );
2142 else
2143 req->write_time = 0; /* FIXME */
2144 ret = !SERVER_CALL_ERR();
2146 SERVER_END_REQ;
2147 return ret;
2151 /**************************************************************************
2152 * LockFile (KERNEL32.511)
2154 BOOL WINAPI LockFile( HANDLE hFile, DWORD dwFileOffsetLow, DWORD dwFileOffsetHigh,
2155 DWORD nNumberOfBytesToLockLow, DWORD nNumberOfBytesToLockHigh )
2157 BOOL ret;
2158 SERVER_START_REQ( lock_file )
2160 req->handle = hFile;
2161 req->offset_low = dwFileOffsetLow;
2162 req->offset_high = dwFileOffsetHigh;
2163 req->count_low = nNumberOfBytesToLockLow;
2164 req->count_high = nNumberOfBytesToLockHigh;
2165 ret = !SERVER_CALL_ERR();
2167 SERVER_END_REQ;
2168 return ret;
2171 /**************************************************************************
2172 * LockFileEx [KERNEL32.512]
2174 * Locks a byte range within an open file for shared or exclusive access.
2176 * RETURNS
2177 * success: TRUE
2178 * failure: FALSE
2180 * NOTES
2181 * Per Microsoft docs, the third parameter (reserved) must be set to 0.
2183 BOOL WINAPI LockFileEx( HANDLE hFile, DWORD flags, DWORD reserved,
2184 DWORD nNumberOfBytesToLockLow, DWORD nNumberOfBytesToLockHigh,
2185 LPOVERLAPPED pOverlapped )
2187 FIXME("hFile=%d,flags=%ld,reserved=%ld,lowbytes=%ld,highbytes=%ld,overlapped=%p: stub.\n",
2188 hFile, flags, reserved, nNumberOfBytesToLockLow, nNumberOfBytesToLockHigh,
2189 pOverlapped);
2190 if (reserved == 0)
2191 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
2192 else
2194 ERR("reserved == %ld: Supposed to be 0??\n", reserved);
2195 SetLastError(ERROR_INVALID_PARAMETER);
2198 return FALSE;
2202 /**************************************************************************
2203 * UnlockFile (KERNEL32.703)
2205 BOOL WINAPI UnlockFile( HANDLE hFile, DWORD dwFileOffsetLow, DWORD dwFileOffsetHigh,
2206 DWORD nNumberOfBytesToUnlockLow, DWORD nNumberOfBytesToUnlockHigh )
2208 BOOL ret;
2209 SERVER_START_REQ( unlock_file )
2211 req->handle = hFile;
2212 req->offset_low = dwFileOffsetLow;
2213 req->offset_high = dwFileOffsetHigh;
2214 req->count_low = nNumberOfBytesToUnlockLow;
2215 req->count_high = nNumberOfBytesToUnlockHigh;
2216 ret = !SERVER_CALL_ERR();
2218 SERVER_END_REQ;
2219 return ret;
2223 /**************************************************************************
2224 * UnlockFileEx (KERNEL32.705)
2226 BOOL WINAPI UnlockFileEx(
2227 HFILE hFile,
2228 DWORD dwReserved,
2229 DWORD nNumberOfBytesToUnlockLow,
2230 DWORD nNumberOfBytesToUnlockHigh,
2231 LPOVERLAPPED lpOverlapped
2234 FIXME("hFile=%d,reserved=%ld,lowbytes=%ld,highbytes=%ld,overlapped=%p: stub.\n",
2235 hFile, dwReserved, nNumberOfBytesToUnlockLow, nNumberOfBytesToUnlockHigh,
2236 lpOverlapped);
2237 if (dwReserved == 0)
2238 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
2239 else
2241 ERR("reserved == %ld: Supposed to be 0??\n", dwReserved);
2242 SetLastError(ERROR_INVALID_PARAMETER);
2245 return FALSE;
2249 #if 0
2251 struct DOS_FILE_LOCK {
2252 struct DOS_FILE_LOCK * next;
2253 DWORD base;
2254 DWORD len;
2255 DWORD processId;
2256 FILE_OBJECT * dos_file;
2257 /* char * unix_name;*/
2260 typedef struct DOS_FILE_LOCK DOS_FILE_LOCK;
2262 static DOS_FILE_LOCK *locks = NULL;
2263 static void DOS_RemoveFileLocks(FILE_OBJECT *file);
2266 /* Locks need to be mirrored because unix file locking is based
2267 * on the pid. Inside of wine there can be multiple WINE processes
2268 * that share the same unix pid.
2269 * Read's and writes should check these locks also - not sure
2270 * how critical that is at this point (FIXME).
2273 static BOOL DOS_AddLock(FILE_OBJECT *file, struct flock *f)
2275 DOS_FILE_LOCK *curr;
2276 DWORD processId;
2278 processId = GetCurrentProcessId();
2280 /* check if lock overlaps a current lock for the same file */
2281 #if 0
2282 for (curr = locks; curr; curr = curr->next) {
2283 if (strcmp(curr->unix_name, file->unix_name) == 0) {
2284 if ((f->l_start == curr->base) && (f->l_len == curr->len))
2285 return TRUE;/* region is identic */
2286 if ((f->l_start < (curr->base + curr->len)) &&
2287 ((f->l_start + f->l_len) > curr->base)) {
2288 /* region overlaps */
2289 return FALSE;
2293 #endif
2295 curr = HeapAlloc( GetProcessHeap(), 0, sizeof(DOS_FILE_LOCK) );
2296 curr->processId = GetCurrentProcessId();
2297 curr->base = f->l_start;
2298 curr->len = f->l_len;
2299 /* curr->unix_name = HEAP_strdupA( GetProcessHeap(), 0, file->unix_name);*/
2300 curr->next = locks;
2301 curr->dos_file = file;
2302 locks = curr;
2303 return TRUE;
2306 static void DOS_RemoveFileLocks(FILE_OBJECT *file)
2308 DWORD processId;
2309 DOS_FILE_LOCK **curr;
2310 DOS_FILE_LOCK *rem;
2312 processId = GetCurrentProcessId();
2313 curr = &locks;
2314 while (*curr) {
2315 if ((*curr)->dos_file == file) {
2316 rem = *curr;
2317 *curr = (*curr)->next;
2318 /* HeapFree( GetProcessHeap(), 0, rem->unix_name );*/
2319 HeapFree( GetProcessHeap(), 0, rem );
2321 else
2322 curr = &(*curr)->next;
2326 static BOOL DOS_RemoveLock(FILE_OBJECT *file, struct flock *f)
2328 DWORD processId;
2329 DOS_FILE_LOCK **curr;
2330 DOS_FILE_LOCK *rem;
2332 processId = GetCurrentProcessId();
2333 for (curr = &locks; *curr; curr = &(*curr)->next) {
2334 if ((*curr)->processId == processId &&
2335 (*curr)->dos_file == file &&
2336 (*curr)->base == f->l_start &&
2337 (*curr)->len == f->l_len) {
2338 /* this is the same lock */
2339 rem = *curr;
2340 *curr = (*curr)->next;
2341 /* HeapFree( GetProcessHeap(), 0, rem->unix_name );*/
2342 HeapFree( GetProcessHeap(), 0, rem );
2343 return TRUE;
2346 /* no matching lock found */
2347 return FALSE;
2351 /**************************************************************************
2352 * LockFile (KERNEL32.511)
2354 BOOL WINAPI LockFile(
2355 HFILE hFile,DWORD dwFileOffsetLow,DWORD dwFileOffsetHigh,
2356 DWORD nNumberOfBytesToLockLow,DWORD nNumberOfBytesToLockHigh )
2358 struct flock f;
2359 FILE_OBJECT *file;
2361 TRACE("handle %d offsetlow=%ld offsethigh=%ld nbyteslow=%ld nbyteshigh=%ld\n",
2362 hFile, dwFileOffsetLow, dwFileOffsetHigh,
2363 nNumberOfBytesToLockLow, nNumberOfBytesToLockHigh);
2365 if (dwFileOffsetHigh || nNumberOfBytesToLockHigh) {
2366 FIXME("Unimplemented bytes > 32bits\n");
2367 return FALSE;
2370 f.l_start = dwFileOffsetLow;
2371 f.l_len = nNumberOfBytesToLockLow;
2372 f.l_whence = SEEK_SET;
2373 f.l_pid = 0;
2374 f.l_type = F_WRLCK;
2376 if (!(file = FILE_GetFile(hFile,0,NULL))) return FALSE;
2378 /* shadow locks internally */
2379 if (!DOS_AddLock(file, &f)) {
2380 SetLastError( ERROR_LOCK_VIOLATION );
2381 return FALSE;
2384 /* FIXME: Unix locking commented out for now, doesn't work with Excel */
2385 #ifdef USE_UNIX_LOCKS
2386 if (fcntl(file->unix_handle, F_SETLK, &f) == -1) {
2387 if (errno == EACCES || errno == EAGAIN) {
2388 SetLastError( ERROR_LOCK_VIOLATION );
2390 else {
2391 FILE_SetDosError();
2393 /* remove our internal copy of the lock */
2394 DOS_RemoveLock(file, &f);
2395 return FALSE;
2397 #endif
2398 return TRUE;
2402 /**************************************************************************
2403 * UnlockFile (KERNEL32.703)
2405 BOOL WINAPI UnlockFile(
2406 HFILE hFile,DWORD dwFileOffsetLow,DWORD dwFileOffsetHigh,
2407 DWORD nNumberOfBytesToUnlockLow,DWORD nNumberOfBytesToUnlockHigh )
2409 FILE_OBJECT *file;
2410 struct flock f;
2412 TRACE("handle %d offsetlow=%ld offsethigh=%ld nbyteslow=%ld nbyteshigh=%ld\n",
2413 hFile, dwFileOffsetLow, dwFileOffsetHigh,
2414 nNumberOfBytesToUnlockLow, nNumberOfBytesToUnlockHigh);
2416 if (dwFileOffsetHigh || nNumberOfBytesToUnlockHigh) {
2417 WARN("Unimplemented bytes > 32bits\n");
2418 return FALSE;
2421 f.l_start = dwFileOffsetLow;
2422 f.l_len = nNumberOfBytesToUnlockLow;
2423 f.l_whence = SEEK_SET;
2424 f.l_pid = 0;
2425 f.l_type = F_UNLCK;
2427 if (!(file = FILE_GetFile(hFile,0,NULL))) return FALSE;
2429 DOS_RemoveLock(file, &f); /* ok if fails - may be another wine */
2431 /* FIXME: Unix locking commented out for now, doesn't work with Excel */
2432 #ifdef USE_UNIX_LOCKS
2433 if (fcntl(file->unix_handle, F_SETLK, &f) == -1) {
2434 FILE_SetDosError();
2435 return FALSE;
2437 #endif
2438 return TRUE;
2440 #endif
2442 /**************************************************************************
2443 * GetFileAttributesExA [KERNEL32.874]
2445 BOOL WINAPI GetFileAttributesExA(
2446 LPCSTR lpFileName, GET_FILEEX_INFO_LEVELS fInfoLevelId,
2447 LPVOID lpFileInformation)
2449 DOS_FULL_NAME full_name;
2450 BY_HANDLE_FILE_INFORMATION info;
2452 if (lpFileName == NULL) return FALSE;
2453 if (lpFileInformation == NULL) return FALSE;
2455 if (fInfoLevelId == GetFileExInfoStandard) {
2456 LPWIN32_FILE_ATTRIBUTE_DATA lpFad =
2457 (LPWIN32_FILE_ATTRIBUTE_DATA) lpFileInformation;
2458 if (!DOSFS_GetFullName( lpFileName, TRUE, &full_name )) return FALSE;
2459 if (!FILE_Stat( full_name.long_name, &info )) return FALSE;
2461 lpFad->dwFileAttributes = info.dwFileAttributes;
2462 lpFad->ftCreationTime = info.ftCreationTime;
2463 lpFad->ftLastAccessTime = info.ftLastAccessTime;
2464 lpFad->ftLastWriteTime = info.ftLastWriteTime;
2465 lpFad->nFileSizeHigh = info.nFileSizeHigh;
2466 lpFad->nFileSizeLow = info.nFileSizeLow;
2468 else {
2469 FIXME("invalid info level %d!\n", fInfoLevelId);
2470 return FALSE;
2473 return TRUE;
2477 /**************************************************************************
2478 * GetFileAttributesExW [KERNEL32.875]
2480 BOOL WINAPI GetFileAttributesExW(
2481 LPCWSTR lpFileName, GET_FILEEX_INFO_LEVELS fInfoLevelId,
2482 LPVOID lpFileInformation)
2484 LPSTR nameA = HEAP_strdupWtoA( GetProcessHeap(), 0, lpFileName );
2485 BOOL res =
2486 GetFileAttributesExA( nameA, fInfoLevelId, lpFileInformation);
2487 HeapFree( GetProcessHeap(), 0, nameA );
2488 return res;