Replaced PTR_SEG_TO_LIN macro by exported MapSL function.
[wine] / files / file.c
1 /*
2  * File handling functions
3  *
4  * Copyright 1993 John Burton
5  * Copyright 1996 Alexandre Julliard
6  *
7  * TODO:
8  *    Fix the CopyFileEx methods to implement the "extended" functionality.
9  *    Right now, they simply call the CopyFile method.
10  */
11
12 #include "config.h"
13
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>
33
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 "task.h"
44 #include "wincon.h"
45 #include "debugtools.h"
46
47 #include "server.h"
48
49 DEFAULT_DEBUG_CHANNEL(file);
50
51 #if defined(MAP_ANONYMOUS) && !defined(MAP_ANON)
52 #define MAP_ANON MAP_ANONYMOUS
53 #endif
54
55 /* Size of per-process table of DOS handles */
56 #define DOS_TABLE_SIZE 256
57
58 static HANDLE dos_handles[DOS_TABLE_SIZE];
59
60
61 /***********************************************************************
62  *              FILE_ConvertOFMode
63  *
64  * Convert OF_* mode into flags for CreateFile.
65  */
66 static void FILE_ConvertOFMode( INT mode, DWORD *access, DWORD *sharing )
67 {
68     switch(mode & 0x03)
69     {
70     case OF_READ:      *access = GENERIC_READ; break;
71     case OF_WRITE:     *access = GENERIC_WRITE; break;
72     case OF_READWRITE: *access = GENERIC_READ | GENERIC_WRITE; break;
73     default:           *access = 0; break;
74     }
75     switch(mode & 0x70)
76     {
77     case OF_SHARE_EXCLUSIVE:  *sharing = 0; break;
78     case OF_SHARE_DENY_WRITE: *sharing = FILE_SHARE_READ; break;
79     case OF_SHARE_DENY_READ:  *sharing = FILE_SHARE_WRITE; break;
80     case OF_SHARE_DENY_NONE:
81     case OF_SHARE_COMPAT:
82     default:                  *sharing = FILE_SHARE_READ | FILE_SHARE_WRITE; break;
83     }
84 }
85
86
87 /***********************************************************************
88  *              FILE_strcasecmp
89  *
90  * locale-independent case conversion for file I/O
91  */
92 int FILE_strcasecmp( const char *str1, const char *str2 )
93 {
94     for (;;)
95     {
96         int ret = FILE_toupper(*str1) - FILE_toupper(*str2);
97         if (ret || !*str1) return ret;
98         str1++;
99         str2++;
100     }
101 }
102
103
104 /***********************************************************************
105  *              FILE_strncasecmp
106  *
107  * locale-independent case conversion for file I/O
108  */
109 int FILE_strncasecmp( const char *str1, const char *str2, int len )
110 {
111     int ret = 0;
112     for ( ; len > 0; len--, str1++, str2++)
113         if ((ret = FILE_toupper(*str1) - FILE_toupper(*str2)) || !*str1) break;
114     return ret;
115 }
116
117
118 /***********************************************************************
119  *           FILE_SetDosError
120  *
121  * Set the DOS error code from errno.
122  */
123 void FILE_SetDosError(void)
124 {
125     int save_errno = errno; /* errno gets overwritten by printf */
126
127     TRACE("errno = %d %s\n", errno, strerror(errno));
128     switch (save_errno)
129     {
130     case EAGAIN:
131         SetLastError( ERROR_SHARING_VIOLATION );
132         break;
133     case EBADF:
134         SetLastError( ERROR_INVALID_HANDLE );
135         break;
136     case ENOSPC:
137         SetLastError( ERROR_HANDLE_DISK_FULL );
138         break;
139     case EACCES:
140     case EPERM:
141     case EROFS:
142         SetLastError( ERROR_ACCESS_DENIED );
143         break;
144     case EBUSY:
145         SetLastError( ERROR_LOCK_VIOLATION );
146         break;
147     case ENOENT:
148         SetLastError( ERROR_FILE_NOT_FOUND );
149         break;
150     case EISDIR:
151         SetLastError( ERROR_CANNOT_MAKE );
152         break;
153     case ENFILE:
154     case EMFILE:
155         SetLastError( ERROR_NO_MORE_FILES );
156         break;
157     case EEXIST:
158         SetLastError( ERROR_FILE_EXISTS );
159         break;
160     case EINVAL:
161     case ESPIPE:
162         SetLastError( ERROR_SEEK );
163         break;
164     case ENOTEMPTY:
165         SetLastError( ERROR_DIR_NOT_EMPTY );
166         break;
167     case ENOEXEC:
168         SetLastError( ERROR_BAD_FORMAT );
169         break;
170     default:
171         WARN( "unknown file error: %s", strerror(save_errno) );
172         SetLastError( ERROR_GEN_FAILURE );
173         break;
174     }
175     errno = save_errno;
176 }
177
178
179 /***********************************************************************
180  *           FILE_DupUnixHandle
181  *
182  * Duplicate a Unix handle into a task handle.
183  */
184 HFILE FILE_DupUnixHandle( int fd, DWORD access )
185 {
186     struct alloc_file_handle_request *req = get_req_buffer();
187     req->access  = access;
188     server_call_fd( REQ_ALLOC_FILE_HANDLE, fd, NULL );
189     return req->handle;
190 }
191
192
193 /***********************************************************************
194  *           FILE_GetUnixHandle
195  *
196  * Retrieve the Unix handle corresponding to a file handle.
197  */
198 int FILE_GetUnixHandle( HANDLE handle, DWORD access )
199 {
200     int unix_handle = -1;
201     if (access == GENERIC_READ)
202     {
203         struct get_read_fd_request *req = get_req_buffer();
204         req->handle = handle;
205         server_call_fd( REQ_GET_READ_FD, -1, &unix_handle );
206     }
207     else if (access == GENERIC_WRITE)
208     {
209         struct get_write_fd_request *req = get_req_buffer();
210         req->handle = handle;
211         server_call_fd( REQ_GET_WRITE_FD, -1, &unix_handle );
212     }
213     else ERR( "bad access %08lx\n", access );
214     return unix_handle;
215 }
216
217
218 /*************************************************************************
219  *              FILE_OpenConsole
220  *
221  * Open a handle to the current process console.
222  */
223 static HANDLE FILE_OpenConsole( BOOL output, DWORD access, LPSECURITY_ATTRIBUTES sa )
224 {
225     int ret = -1;
226
227     SERVER_START_REQ
228     {
229         struct open_console_request *req = server_alloc_req( sizeof(*req), 0 );
230
231         req->output  = output;
232         req->access  = access;
233         req->inherit = (sa && (sa->nLength>=sizeof(*sa)) && sa->bInheritHandle);
234         SetLastError(0);
235         if (!server_call( REQ_OPEN_CONSOLE )) ret = req->handle;
236     }
237     SERVER_END_REQ;
238     return ret;
239 }
240
241
242 /***********************************************************************
243  *           FILE_CreateFile
244  *
245  * Implementation of CreateFile. Takes a Unix path name.
246  */
247 HANDLE FILE_CreateFile( LPCSTR filename, DWORD access, DWORD sharing,
248                         LPSECURITY_ATTRIBUTES sa, DWORD creation,
249                         DWORD attributes, HANDLE template, BOOL fail_read_only )
250 {
251     DWORD err;
252     HANDLE ret;
253     size_t len = strlen(filename);
254
255     if (len > REQUEST_MAX_VAR_SIZE)
256     {
257         FIXME("filename '%s' too long\n", filename );
258         SetLastError( ERROR_INVALID_PARAMETER );
259         return -1;
260     }
261
262  restart:
263     SERVER_START_REQ
264     {
265         struct create_file_request *req = server_alloc_req( sizeof(*req), len );
266         req->access  = access;
267         req->inherit = (sa && (sa->nLength>=sizeof(*sa)) && sa->bInheritHandle);
268         req->sharing = sharing;
269         req->create  = creation;
270         req->attrs   = attributes;
271         memcpy( server_data_ptr(req), filename, len );
272         SetLastError(0);
273         err = server_call( REQ_CREATE_FILE );
274         ret = req->handle;
275     }
276     SERVER_END_REQ;
277
278     /* If write access failed, retry without GENERIC_WRITE */
279
280     if ((ret == -1) && !fail_read_only && (access & GENERIC_WRITE)) 
281     {
282         if ((err == STATUS_MEDIA_WRITE_PROTECTED) || (err == STATUS_ACCESS_DENIED))
283         {
284             TRACE("Write access failed for file '%s', trying without "
285                   "write access\n", filename);
286             access &= ~GENERIC_WRITE;
287             goto restart;
288         }
289     }
290
291     if (ret == -1)
292         WARN("Unable to create file '%s' (GLE %ld)\n", filename,
293              GetLastError());
294
295     return ret;
296 }
297
298
299 /***********************************************************************
300  *           FILE_CreateDevice
301  *
302  * Same as FILE_CreateFile but for a device
303  */
304 HFILE FILE_CreateDevice( int client_id, DWORD access, LPSECURITY_ATTRIBUTES sa )
305 {
306     HFILE ret;
307     SERVER_START_REQ
308     {
309         struct create_device_request *req = server_alloc_req( sizeof(*req), 0 );
310
311         req->access  = access;
312         req->inherit = (sa && (sa->nLength>=sizeof(*sa)) && sa->bInheritHandle);
313         req->id      = client_id;
314         SetLastError(0);
315         server_call( REQ_CREATE_DEVICE );
316         ret = req->handle;
317     }
318     SERVER_END_REQ;
319     return ret;
320 }
321
322
323 /*************************************************************************
324  * CreateFileA [KERNEL32.45]  Creates or opens a file or other object
325  *
326  * Creates or opens an object, and returns a handle that can be used to
327  * access that object.
328  *
329  * PARAMS
330  *
331  * filename     [I] pointer to filename to be accessed
332  * access       [I] access mode requested
333  * sharing      [I] share mode
334  * sa           [I] pointer to security attributes
335  * creation     [I] how to create the file
336  * attributes   [I] attributes for newly created file
337  * template     [I] handle to file with extended attributes to copy
338  *
339  * RETURNS
340  *   Success: Open handle to specified file
341  *   Failure: INVALID_HANDLE_VALUE
342  *
343  * NOTES
344  *  Should call SetLastError() on failure.
345  *
346  * BUGS
347  *
348  * Doesn't support character devices, pipes, template files, or a
349  * lot of the 'attributes' flags yet.
350  */
351 HANDLE WINAPI CreateFileA( LPCSTR filename, DWORD access, DWORD sharing,
352                               LPSECURITY_ATTRIBUTES sa, DWORD creation,
353                               DWORD attributes, HANDLE template )
354 {
355     DOS_FULL_NAME full_name;
356
357     if (!filename)
358     {
359         SetLastError( ERROR_INVALID_PARAMETER );
360         return HFILE_ERROR;
361     }
362     TRACE("%s %s%s%s%s%s%s%s\n",filename,
363           ((access & GENERIC_READ)==GENERIC_READ)?"GENERIC_READ ":"",
364           ((access & GENERIC_WRITE)==GENERIC_WRITE)?"GENERIC_WRITE ":"",
365           (!access)?"QUERY_ACCESS ":"",
366           ((sharing & FILE_SHARE_READ)==FILE_SHARE_READ)?"FILE_SHARE_READ ":"",
367           ((sharing & FILE_SHARE_WRITE)==FILE_SHARE_WRITE)?"FILE_SHARE_WRITE ":"",
368           ((sharing & FILE_SHARE_DELETE)==FILE_SHARE_DELETE)?"FILE_SHARE_DELETE ":"",
369           (creation ==CREATE_NEW)?"CREATE_NEW":
370           (creation ==CREATE_ALWAYS)?"CREATE_ALWAYS ":
371           (creation ==OPEN_EXISTING)?"OPEN_EXISTING ":
372           (creation ==OPEN_ALWAYS)?"OPEN_ALWAYS ":
373           (creation ==TRUNCATE_EXISTING)?"TRUNCATE_EXISTING ":"");
374
375     /* If the name starts with '\\?\', ignore the first 4 chars. */
376     if (!strncmp(filename, "\\\\?\\", 4))
377     {
378         filename += 4;
379         if (!strncmp(filename, "UNC\\", 4))
380         {
381             FIXME("UNC name (%s) not supported.\n", filename );
382             SetLastError( ERROR_PATH_NOT_FOUND );
383             return HFILE_ERROR;
384         }
385     }
386
387     if (!strncmp(filename, "\\\\.\\", 4)) {
388         if (!DOSFS_GetDevice( filename ))
389                 return DEVICE_Open( filename+4, access, sa );
390         else
391                 filename+=4; /* fall into DOSFS_Device case below */
392     }
393
394     /* If the name still starts with '\\', it's a UNC name. */
395     if (!strncmp(filename, "\\\\", 2))
396     {
397         FIXME("UNC name (%s) not supported.\n", filename );
398         SetLastError( ERROR_PATH_NOT_FOUND );
399         return HFILE_ERROR;
400     }
401
402     /* If the name contains a DOS wild card (* or ?), do no create a file */
403     if(strchr(filename,'*') || strchr(filename,'?'))
404         return HFILE_ERROR;
405
406     /* Open a console for CONIN$ or CONOUT$ */
407     if (!strcasecmp(filename, "CONIN$")) return FILE_OpenConsole( FALSE, access, sa );
408     if (!strcasecmp(filename, "CONOUT$")) return FILE_OpenConsole( TRUE, access, sa );
409
410     if (DOSFS_GetDevice( filename ))
411     {
412         HFILE   ret;
413
414         TRACE("opening device '%s'\n", filename );
415
416         if (HFILE_ERROR!=(ret=DOSFS_OpenDevice( filename, access )))
417                 return ret;
418
419         /* Do not silence this please. It is a critical error. -MM */
420         ERR("Couldn't open device '%s'!\n",filename);
421         SetLastError( ERROR_FILE_NOT_FOUND );
422         return HFILE_ERROR;
423     }
424
425     /* check for filename, don't check for last entry if creating */
426     if (!DOSFS_GetFullName( filename,
427                             (creation == OPEN_EXISTING) ||
428                             (creation == TRUNCATE_EXISTING),
429                             &full_name )) {
430         WARN("Unable to get full filename from '%s' (GLE %ld)\n",
431              filename, GetLastError());
432         return HFILE_ERROR;
433     }
434
435     return FILE_CreateFile( full_name.long_name, access, sharing,
436                             sa, creation, attributes, template,
437                             DRIVE_GetFlags(full_name.drive) & DRIVE_FAIL_READ_ONLY );
438 }
439
440
441
442 /*************************************************************************
443  *              CreateFileW              (KERNEL32.48)
444  */
445 HANDLE WINAPI CreateFileW( LPCWSTR filename, DWORD access, DWORD sharing,
446                               LPSECURITY_ATTRIBUTES sa, DWORD creation,
447                               DWORD attributes, HANDLE template)
448 {
449     LPSTR afn = HEAP_strdupWtoA( GetProcessHeap(), 0, filename );
450     HANDLE res = CreateFileA( afn, access, sharing, sa, creation, attributes, template );
451     HeapFree( GetProcessHeap(), 0, afn );
452     return res;
453 }
454
455
456 /***********************************************************************
457  *           FILE_FillInfo
458  *
459  * Fill a file information from a struct stat.
460  */
461 static void FILE_FillInfo( struct stat *st, BY_HANDLE_FILE_INFORMATION *info )
462 {
463     if (S_ISDIR(st->st_mode))
464         info->dwFileAttributes = FILE_ATTRIBUTE_DIRECTORY;
465     else
466         info->dwFileAttributes = FILE_ATTRIBUTE_ARCHIVE;
467     if (!(st->st_mode & S_IWUSR))
468         info->dwFileAttributes |= FILE_ATTRIBUTE_READONLY;
469
470     RtlSecondsSince1970ToTime( st->st_mtime, &info->ftCreationTime );
471     RtlSecondsSince1970ToTime( st->st_mtime, &info->ftLastWriteTime );
472     RtlSecondsSince1970ToTime( st->st_atime, &info->ftLastAccessTime );
473
474     info->dwVolumeSerialNumber = 0;  /* FIXME */
475     info->nFileSizeHigh = 0;
476     info->nFileSizeLow  = S_ISDIR(st->st_mode) ? 0 : st->st_size;
477     info->nNumberOfLinks = st->st_nlink;
478     info->nFileIndexHigh = 0;
479     info->nFileIndexLow  = st->st_ino;
480 }
481
482
483 /***********************************************************************
484  *           FILE_Stat
485  *
486  * Stat a Unix path name. Return TRUE if OK.
487  */
488 BOOL FILE_Stat( LPCSTR unixName, BY_HANDLE_FILE_INFORMATION *info )
489 {
490     struct stat st;
491
492     if (lstat( unixName, &st ) == -1)
493     {
494         FILE_SetDosError();
495         return FALSE;
496     }
497     if (!S_ISLNK(st.st_mode)) FILE_FillInfo( &st, info );
498     else
499     {
500         /* do a "real" stat to find out
501            about the type of the symlink destination */
502         if (stat( unixName, &st ) == -1)
503         {
504             FILE_SetDosError();
505             return FALSE;
506         }
507         FILE_FillInfo( &st, info );
508         info->dwFileAttributes |= FILE_ATTRIBUTE_SYMLINK;
509     }
510     return TRUE;
511 }
512
513
514 /***********************************************************************
515  *             GetFileInformationByHandle   (KERNEL32.219)
516  */
517 DWORD WINAPI GetFileInformationByHandle( HANDLE hFile,
518                                          BY_HANDLE_FILE_INFORMATION *info )
519 {
520     DWORD ret;
521     if (!info) return 0;
522
523     SERVER_START_REQ
524     {
525         struct get_file_info_request *req = server_alloc_req( sizeof(*req), 0 );
526         req->handle = hFile;
527         if ((ret = !server_call( REQ_GET_FILE_INFO )))
528         {
529             RtlSecondsSince1970ToTime( req->write_time, &info->ftCreationTime );
530             RtlSecondsSince1970ToTime( req->write_time, &info->ftLastWriteTime );
531             RtlSecondsSince1970ToTime( req->access_time, &info->ftLastAccessTime );
532             info->dwFileAttributes     = req->attr;
533             info->dwVolumeSerialNumber = req->serial;
534             info->nFileSizeHigh        = req->size_high;
535             info->nFileSizeLow         = req->size_low;
536             info->nNumberOfLinks       = req->links;
537             info->nFileIndexHigh       = req->index_high;
538             info->nFileIndexLow        = req->index_low;
539         }
540     }
541     SERVER_END_REQ;
542     return ret;
543 }
544
545
546 /**************************************************************************
547  *           GetFileAttributes16   (KERNEL.420)
548  */
549 DWORD WINAPI GetFileAttributes16( LPCSTR name )
550 {
551     return GetFileAttributesA( name );
552 }
553
554
555 /**************************************************************************
556  *           GetFileAttributesA   (KERNEL32.217)
557  */
558 DWORD WINAPI GetFileAttributesA( LPCSTR name )
559 {
560     DOS_FULL_NAME full_name;
561     BY_HANDLE_FILE_INFORMATION info;
562
563     if (name == NULL || *name=='\0') return -1;
564
565     if (!DOSFS_GetFullName( name, TRUE, &full_name )) return -1;
566     if (!FILE_Stat( full_name.long_name, &info )) return -1;
567     return info.dwFileAttributes;
568 }
569
570
571 /**************************************************************************
572  *           GetFileAttributesW   (KERNEL32.218)
573  */
574 DWORD WINAPI GetFileAttributesW( LPCWSTR name )
575 {
576     LPSTR nameA = HEAP_strdupWtoA( GetProcessHeap(), 0, name );
577     DWORD res = GetFileAttributesA( nameA );
578     HeapFree( GetProcessHeap(), 0, nameA );
579     return res;
580 }
581
582
583 /***********************************************************************
584  *           GetFileSize   (KERNEL32.220)
585  */
586 DWORD WINAPI GetFileSize( HANDLE hFile, LPDWORD filesizehigh )
587 {
588     BY_HANDLE_FILE_INFORMATION info;
589     if (!GetFileInformationByHandle( hFile, &info )) return 0;
590     if (filesizehigh) *filesizehigh = info.nFileSizeHigh;
591     return info.nFileSizeLow;
592 }
593
594
595 /***********************************************************************
596  *           GetFileTime   (KERNEL32.221)
597  */
598 BOOL WINAPI GetFileTime( HANDLE hFile, FILETIME *lpCreationTime,
599                            FILETIME *lpLastAccessTime,
600                            FILETIME *lpLastWriteTime )
601 {
602     BY_HANDLE_FILE_INFORMATION info;
603     if (!GetFileInformationByHandle( hFile, &info )) return FALSE;
604     if (lpCreationTime)   *lpCreationTime   = info.ftCreationTime;
605     if (lpLastAccessTime) *lpLastAccessTime = info.ftLastAccessTime;
606     if (lpLastWriteTime)  *lpLastWriteTime  = info.ftLastWriteTime;
607     return TRUE;
608 }
609
610 /***********************************************************************
611  *           CompareFileTime   (KERNEL32.28)
612  */
613 INT WINAPI CompareFileTime( LPFILETIME x, LPFILETIME y )
614 {
615         if (!x || !y) return -1;
616
617         if (x->dwHighDateTime > y->dwHighDateTime)
618                 return 1;
619         if (x->dwHighDateTime < y->dwHighDateTime)
620                 return -1;
621         if (x->dwLowDateTime > y->dwLowDateTime)
622                 return 1;
623         if (x->dwLowDateTime < y->dwLowDateTime)
624                 return -1;
625         return 0;
626 }
627
628 /***********************************************************************
629  *           FILE_GetTempFileName : utility for GetTempFileName
630  */
631 static UINT FILE_GetTempFileName( LPCSTR path, LPCSTR prefix, UINT unique,
632                                   LPSTR buffer, BOOL isWin16 )
633 {
634     static UINT unique_temp;
635     DOS_FULL_NAME full_name;
636     int i;
637     LPSTR p;
638     UINT num;
639
640     if ( !path || !prefix || !buffer ) return 0;
641
642     if (!unique_temp) unique_temp = time(NULL) & 0xffff;
643     num = unique ? (unique & 0xffff) : (unique_temp++ & 0xffff);
644
645     strcpy( buffer, path );
646     p = buffer + strlen(buffer);
647
648     /* add a \, if there isn't one and path is more than just the drive letter ... */
649     if ( !((strlen(buffer) == 2) && (buffer[1] == ':')) 
650         && ((p == buffer) || (p[-1] != '\\'))) *p++ = '\\';
651
652     if (isWin16) *p++ = '~';
653     for (i = 3; (i > 0) && (*prefix); i--) *p++ = *prefix++;
654     sprintf( p, "%04x.tmp", num );
655
656     /* Now try to create it */
657
658     if (!unique)
659     {
660         do
661         {
662             HFILE handle = CreateFileA( buffer, GENERIC_WRITE, 0, NULL,
663                                             CREATE_NEW, FILE_ATTRIBUTE_NORMAL, -1 );
664             if (handle != INVALID_HANDLE_VALUE)
665             {  /* We created it */
666                 TRACE("created %s\n",
667                               buffer);
668                 CloseHandle( handle );
669                 break;
670             }
671             if (GetLastError() != ERROR_FILE_EXISTS)
672                 break;  /* No need to go on */
673             num++;
674             sprintf( p, "%04x.tmp", num );
675         } while (num != (unique & 0xffff));
676     }
677
678     /* Get the full path name */
679
680     if (DOSFS_GetFullName( buffer, FALSE, &full_name ))
681     {
682         /* Check if we have write access in the directory */
683         if ((p = strrchr( full_name.long_name, '/' ))) *p = '\0';
684         if (access( full_name.long_name, W_OK ) == -1)
685             WARN("returns '%s', which doesn't seem to be writeable.\n",
686                  buffer);
687     }
688     TRACE("returning %s\n", buffer );
689     return unique ? unique : num;
690 }
691
692
693 /***********************************************************************
694  *           GetTempFileNameA   (KERNEL32.290)
695  */
696 UINT WINAPI GetTempFileNameA( LPCSTR path, LPCSTR prefix, UINT unique,
697                                   LPSTR buffer)
698 {
699     return FILE_GetTempFileName(path, prefix, unique, buffer, FALSE);
700 }
701
702 /***********************************************************************
703  *           GetTempFileNameW   (KERNEL32.291)
704  */
705 UINT WINAPI GetTempFileNameW( LPCWSTR path, LPCWSTR prefix, UINT unique,
706                                   LPWSTR buffer )
707 {
708     LPSTR   patha,prefixa;
709     char    buffera[144];
710     UINT  ret;
711
712     if (!path) return 0;
713     patha   = HEAP_strdupWtoA( GetProcessHeap(), 0, path );
714     prefixa = HEAP_strdupWtoA( GetProcessHeap(), 0, prefix );
715     ret     = FILE_GetTempFileName( patha, prefixa, unique, buffera, FALSE );
716     MultiByteToWideChar( CP_ACP, 0, buffera, -1, buffer, MAX_PATH );
717     HeapFree( GetProcessHeap(), 0, patha );
718     HeapFree( GetProcessHeap(), 0, prefixa );
719     return ret;
720 }
721
722
723 /***********************************************************************
724  *           GetTempFileName16   (KERNEL.97)
725  */
726 UINT16 WINAPI GetTempFileName16( BYTE drive, LPCSTR prefix, UINT16 unique,
727                                  LPSTR buffer )
728 {
729     char temppath[144];
730
731     if (!(drive & ~TF_FORCEDRIVE)) /* drive 0 means current default drive */
732         drive |= DRIVE_GetCurrentDrive() + 'A';
733
734     if ((drive & TF_FORCEDRIVE) &&
735         !DRIVE_IsValid( toupper(drive & ~TF_FORCEDRIVE) - 'A' ))
736     {
737         drive &= ~TF_FORCEDRIVE;
738         WARN("invalid drive %d specified\n", drive );
739     }
740
741     if (drive & TF_FORCEDRIVE)
742         sprintf(temppath,"%c:", drive & ~TF_FORCEDRIVE );
743     else
744         GetTempPathA( 132, temppath );
745     return (UINT16)FILE_GetTempFileName( temppath, prefix, unique, buffer, TRUE );
746 }
747
748 /***********************************************************************
749  *           FILE_DoOpenFile
750  *
751  * Implementation of OpenFile16() and OpenFile32().
752  */
753 static HFILE FILE_DoOpenFile( LPCSTR name, OFSTRUCT *ofs, UINT mode,
754                                 BOOL win32 )
755 {
756     HFILE hFileRet;
757     FILETIME filetime;
758     WORD filedatetime[2];
759     DOS_FULL_NAME full_name;
760     DWORD access, sharing;
761     char *p;
762
763     if (!ofs) return HFILE_ERROR;
764     
765     TRACE("%s %s %s %s%s%s%s%s%s%s%s%s\n",name,
766           ((mode & 0x3 )==OF_READ)?"OF_READ":
767           ((mode & 0x3 )==OF_WRITE)?"OF_WRITE":
768           ((mode & 0x3 )==OF_READWRITE)?"OF_READWRITE":"unknown",
769           ((mode & 0x70 )==OF_SHARE_COMPAT)?"OF_SHARE_COMPAT":
770           ((mode & 0x70 )==OF_SHARE_DENY_NONE)?"OF_SHARE_DENY_NONE":
771           ((mode & 0x70 )==OF_SHARE_DENY_READ)?"OF_SHARE_DENY_READ":
772           ((mode & 0x70 )==OF_SHARE_DENY_WRITE)?"OF_SHARE_DENY_WRITE":
773           ((mode & 0x70 )==OF_SHARE_EXCLUSIVE)?"OF_SHARE_EXCLUSIVE":"unknown",
774           ((mode & OF_PARSE )==OF_PARSE)?"OF_PARSE ":"",
775           ((mode & OF_DELETE )==OF_DELETE)?"OF_DELETE ":"",
776           ((mode & OF_VERIFY )==OF_VERIFY)?"OF_VERIFY ":"",
777           ((mode & OF_SEARCH )==OF_SEARCH)?"OF_SEARCH ":"",
778           ((mode & OF_CANCEL )==OF_CANCEL)?"OF_CANCEL ":"",
779           ((mode & OF_CREATE )==OF_CREATE)?"OF_CREATE ":"",
780           ((mode & OF_PROMPT )==OF_PROMPT)?"OF_PROMPT ":"",
781           ((mode & OF_EXIST )==OF_EXIST)?"OF_EXIST ":"",
782           ((mode & OF_REOPEN )==OF_REOPEN)?"OF_REOPEN ":""
783           );
784       
785
786     ofs->cBytes = sizeof(OFSTRUCT);
787     ofs->nErrCode = 0;
788     if (mode & OF_REOPEN) name = ofs->szPathName;
789
790     if (!name) {
791         ERR("called with `name' set to NULL ! Please debug.\n");
792         return HFILE_ERROR;
793     }
794
795     TRACE("%s %04x\n", name, mode );
796
797     /* the watcom 10.6 IDE relies on a valid path returned in ofs->szPathName
798        Are there any cases where getting the path here is wrong? 
799        Uwe Bonnes 1997 Apr 2 */
800     if (!GetFullPathNameA( name, sizeof(ofs->szPathName),
801                              ofs->szPathName, NULL )) goto error;
802     FILE_ConvertOFMode( mode, &access, &sharing );
803
804     /* OF_PARSE simply fills the structure */
805
806     if (mode & OF_PARSE)
807     {
808         ofs->fFixedDisk = (GetDriveType16( ofs->szPathName[0]-'A' )
809                            != DRIVE_REMOVABLE);
810         TRACE("(%s): OF_PARSE, res = '%s'\n",
811                       name, ofs->szPathName );
812         return 0;
813     }
814
815     /* OF_CREATE is completely different from all other options, so
816        handle it first */
817
818     if (mode & OF_CREATE)
819     {
820         if ((hFileRet = CreateFileA( name, GENERIC_READ | GENERIC_WRITE,
821                                        sharing, NULL, CREATE_ALWAYS,
822                                        FILE_ATTRIBUTE_NORMAL, -1 ))== INVALID_HANDLE_VALUE)
823             goto error;
824         goto success;
825     }
826
827     /* If OF_SEARCH is set, ignore the given path */
828
829     if ((mode & OF_SEARCH) && !(mode & OF_REOPEN))
830     {
831         /* First try the file name as is */
832         if (DOSFS_GetFullName( name, TRUE, &full_name )) goto found;
833         /* Now remove the path */
834         if (name[0] && (name[1] == ':')) name += 2;
835         if ((p = strrchr( name, '\\' ))) name = p + 1;
836         if ((p = strrchr( name, '/' ))) name = p + 1;
837         if (!name[0]) goto not_found;
838     }
839
840     /* Now look for the file */
841
842     if (!DIR_SearchPath( NULL, name, NULL, &full_name, win32 )) goto not_found;
843
844 found:
845     TRACE("found %s = %s\n",
846                   full_name.long_name, full_name.short_name );
847     lstrcpynA( ofs->szPathName, full_name.short_name,
848                  sizeof(ofs->szPathName) );
849
850     if (mode & OF_SHARE_EXCLUSIVE)
851       /* Some InstallShield version uses OF_SHARE_EXCLUSIVE 
852          on the file <tempdir>/_ins0432._mp to determine how
853          far installation has proceeded.
854          _ins0432._mp is an executable and while running the
855          application expects the open with OF_SHARE_ to fail*/
856       /* Probable FIXME:
857          As our loader closes the files after loading the executable,
858          we can't find the running executable with FILE_InUse.
859          Perhaps the loader should keep the file open.
860          Recheck against how Win handles that case */
861       {
862         char *last = strrchr(full_name.long_name,'/');
863         if (!last)
864           last = full_name.long_name - 1;
865         if (GetModuleHandle16(last+1))
866           {
867             TRACE("Denying shared open for %s\n",full_name.long_name);
868             return HFILE_ERROR;
869           }
870       }
871
872     if (mode & OF_DELETE)
873     {
874         if (unlink( full_name.long_name ) == -1) goto not_found;
875         TRACE("(%s): OF_DELETE return = OK\n", name);
876         return 1;
877     }
878
879     hFileRet = FILE_CreateFile( full_name.long_name, access, sharing,
880                                 NULL, OPEN_EXISTING, 0, -1,
881                                 DRIVE_GetFlags(full_name.drive) & DRIVE_FAIL_READ_ONLY );
882     if (hFileRet == HFILE_ERROR) goto not_found;
883
884     GetFileTime( hFileRet, NULL, NULL, &filetime );
885     FileTimeToDosDateTime( &filetime, &filedatetime[0], &filedatetime[1] );
886     if ((mode & OF_VERIFY) && (mode & OF_REOPEN))
887     {
888         if (memcmp( ofs->reserved, filedatetime, sizeof(ofs->reserved) ))
889         {
890             CloseHandle( hFileRet );
891             WARN("(%s): OF_VERIFY failed\n", name );
892             /* FIXME: what error here? */
893             SetLastError( ERROR_FILE_NOT_FOUND );
894             goto error;
895         }
896     }
897     memcpy( ofs->reserved, filedatetime, sizeof(ofs->reserved) );
898
899 success:  /* We get here if the open was successful */
900     TRACE("(%s): OK, return = %d\n", name, hFileRet );
901     if (win32)
902     {
903         if (mode & OF_EXIST) /* Return the handle, but close it first */
904             CloseHandle( hFileRet );
905     }
906     else
907     {
908         hFileRet = Win32HandleToDosFileHandle( hFileRet );
909         if (hFileRet == HFILE_ERROR16) goto error;
910         if (mode & OF_EXIST) /* Return the handle, but close it first */
911             _lclose16( hFileRet );
912     }
913     return hFileRet;
914
915 not_found:  /* We get here if the file does not exist */
916     WARN("'%s' not found or sharing violation\n", name );
917     SetLastError( ERROR_FILE_NOT_FOUND );
918     /* fall through */
919
920 error:  /* We get here if there was an error opening the file */
921     ofs->nErrCode = GetLastError();
922     WARN("(%s): return = HFILE_ERROR error= %d\n", 
923                   name,ofs->nErrCode );
924     return HFILE_ERROR;
925 }
926
927
928 /***********************************************************************
929  *           OpenFile16   (KERNEL.74)
930  */
931 HFILE16 WINAPI OpenFile16( LPCSTR name, OFSTRUCT *ofs, UINT16 mode )
932 {
933     return FILE_DoOpenFile( name, ofs, mode, FALSE );
934 }
935
936
937 /***********************************************************************
938  *           OpenFile   (KERNEL32.396)
939  */
940 HFILE WINAPI OpenFile( LPCSTR name, OFSTRUCT *ofs, UINT mode )
941 {
942     return FILE_DoOpenFile( name, ofs, mode, TRUE );
943 }
944
945
946 /***********************************************************************
947  *           FILE_InitProcessDosHandles
948  *
949  * Allocates the default DOS handles for a process. Called either by
950  * Win32HandleToDosFileHandle below or by the DOSVM stuff.
951  */
952 static void FILE_InitProcessDosHandles( void )
953 {
954     dos_handles[0] = GetStdHandle(STD_INPUT_HANDLE);
955     dos_handles[1] = GetStdHandle(STD_OUTPUT_HANDLE);
956     dos_handles[2] = GetStdHandle(STD_ERROR_HANDLE);
957     dos_handles[3] = GetStdHandle(STD_ERROR_HANDLE);
958     dos_handles[4] = GetStdHandle(STD_ERROR_HANDLE);
959 }
960
961 /***********************************************************************
962  *           Win32HandleToDosFileHandle   (KERNEL32.21)
963  *
964  * Allocate a DOS handle for a Win32 handle. The Win32 handle is no
965  * longer valid after this function (even on failure).
966  *
967  * Note: this is not exactly right, since on Win95 the Win32 handles
968  *       are on top of DOS handles and we do it the other way
969  *       around. Should be good enough though.
970  */
971 HFILE WINAPI Win32HandleToDosFileHandle( HANDLE handle )
972 {
973     int i;
974
975     if (!handle || (handle == INVALID_HANDLE_VALUE))
976         return HFILE_ERROR;
977
978     for (i = 5; i < DOS_TABLE_SIZE; i++)
979         if (!dos_handles[i])
980         {
981             dos_handles[i] = handle;
982             TRACE("Got %d for h32 %d\n", i, handle );
983             return (HFILE)i;
984         }
985     CloseHandle( handle );
986     SetLastError( ERROR_TOO_MANY_OPEN_FILES );
987     return HFILE_ERROR;
988 }
989
990
991 /***********************************************************************
992  *           DosFileHandleToWin32Handle   (KERNEL32.20)
993  *
994  * Return the Win32 handle for a DOS handle.
995  *
996  * Note: this is not exactly right, since on Win95 the Win32 handles
997  *       are on top of DOS handles and we do it the other way
998  *       around. Should be good enough though.
999  */
1000 HANDLE WINAPI DosFileHandleToWin32Handle( HFILE handle )
1001 {
1002     HFILE16 hfile = (HFILE16)handle;
1003     if (hfile < 5 && !dos_handles[hfile]) FILE_InitProcessDosHandles();
1004     if ((hfile >= DOS_TABLE_SIZE) || !dos_handles[hfile])
1005     {
1006         SetLastError( ERROR_INVALID_HANDLE );
1007         return INVALID_HANDLE_VALUE;
1008     }
1009     return dos_handles[hfile];
1010 }
1011
1012
1013 /***********************************************************************
1014  *           DisposeLZ32Handle   (KERNEL32.22)
1015  *
1016  * Note: this is not entirely correct, we should only close the
1017  *       32-bit handle and not the 16-bit one, but we cannot do
1018  *       this because of the way our DOS handles are implemented.
1019  *       It shouldn't break anything though.
1020  */
1021 void WINAPI DisposeLZ32Handle( HANDLE handle )
1022 {
1023     int i;
1024
1025     if (!handle || (handle == INVALID_HANDLE_VALUE)) return;
1026
1027     for (i = 5; i < DOS_TABLE_SIZE; i++)
1028         if (dos_handles[i] == handle)
1029         {
1030             dos_handles[i] = 0;
1031             CloseHandle( handle );
1032             break;
1033         }
1034 }
1035
1036
1037 /***********************************************************************
1038  *           FILE_Dup2
1039  *
1040  * dup2() function for DOS handles.
1041  */
1042 HFILE16 FILE_Dup2( HFILE16 hFile1, HFILE16 hFile2 )
1043 {
1044     HANDLE new_handle;
1045
1046     if (hFile1 < 5 && !dos_handles[hFile1]) FILE_InitProcessDosHandles();
1047
1048     if ((hFile1 >= DOS_TABLE_SIZE) || (hFile2 >= DOS_TABLE_SIZE) || !dos_handles[hFile1])
1049     {
1050         SetLastError( ERROR_INVALID_HANDLE );
1051         return HFILE_ERROR16;
1052     }
1053     if (hFile2 < 5)
1054     {
1055         FIXME("stdio handle closed, need proper conversion\n" );
1056         SetLastError( ERROR_INVALID_HANDLE );
1057         return HFILE_ERROR16;
1058     }
1059     if (!DuplicateHandle( GetCurrentProcess(), dos_handles[hFile1],
1060                           GetCurrentProcess(), &new_handle,
1061                           0, FALSE, DUPLICATE_SAME_ACCESS ))
1062         return HFILE_ERROR16;
1063     if (dos_handles[hFile2]) CloseHandle( dos_handles[hFile2] );
1064     dos_handles[hFile2] = new_handle;
1065     return hFile2;
1066 }
1067
1068
1069 /***********************************************************************
1070  *           _lclose16   (KERNEL.81)
1071  */
1072 HFILE16 WINAPI _lclose16( HFILE16 hFile )
1073 {
1074     if (hFile < 5)
1075     {
1076         FIXME("stdio handle closed, need proper conversion\n" );
1077         SetLastError( ERROR_INVALID_HANDLE );
1078         return HFILE_ERROR16;
1079     }
1080     if ((hFile >= DOS_TABLE_SIZE) || !dos_handles[hFile])
1081     {
1082         SetLastError( ERROR_INVALID_HANDLE );
1083         return HFILE_ERROR16;
1084     }
1085     TRACE("%d (handle32=%d)\n", hFile, dos_handles[hFile] );
1086     CloseHandle( dos_handles[hFile] );
1087     dos_handles[hFile] = 0;
1088     return 0;
1089 }
1090
1091
1092 /***********************************************************************
1093  *           _lclose   (KERNEL32.592)
1094  */
1095 HFILE WINAPI _lclose( HFILE hFile )
1096 {
1097     TRACE("handle %d\n", hFile );
1098     return CloseHandle( hFile ) ? 0 : HFILE_ERROR;
1099 }
1100
1101 /***********************************************************************
1102  *              GetOverlappedResult     (KERNEL32.360)
1103  */
1104 BOOL WINAPI GetOverlappedResult(HANDLE hFile,LPOVERLAPPED lpOverlapped,
1105                                 LPDWORD lpNumberOfBytesTransferred,
1106                                 BOOL bWait)
1107 {
1108     /* Since all i/o is currently synchronous,
1109      * return true, assuming ReadFile/WriteFile
1110      * have completed the operation */
1111     FIXME("NO Asynch I/O, assuming Read/Write succeeded\n" );
1112     return TRUE;
1113 }
1114
1115 /***********************************************************************
1116  *              ReadFile                (KERNEL32.428)
1117  */
1118 BOOL WINAPI ReadFile( HANDLE hFile, LPVOID buffer, DWORD bytesToRead,
1119                         LPDWORD bytesRead, LPOVERLAPPED overlapped )
1120 {
1121     int unix_handle, result;
1122
1123     TRACE("%d %p %ld\n", hFile, buffer, bytesToRead );
1124
1125     if (bytesRead) *bytesRead = 0;  /* Do this before anything else */
1126     if (!bytesToRead) return TRUE;
1127
1128     if ( overlapped ) {
1129       SetLastError ( ERROR_INVALID_PARAMETER );
1130       return FALSE;
1131     }
1132
1133     unix_handle = FILE_GetUnixHandle( hFile, GENERIC_READ );
1134     if (unix_handle == -1) return FALSE;
1135     while ((result = read( unix_handle, buffer, bytesToRead )) == -1)
1136     {
1137         if ((errno == EAGAIN) || (errno == EINTR)) continue;
1138         if ((errno == EFAULT) && !IsBadWritePtr( buffer, bytesToRead )) continue;
1139         FILE_SetDosError();
1140         break;
1141     }
1142     close( unix_handle );
1143     if (result == -1) return FALSE;
1144     if (bytesRead) *bytesRead = result;
1145     return TRUE;
1146 }
1147
1148
1149 /***********************************************************************
1150  *             WriteFile               (KERNEL32.578)
1151  */
1152 BOOL WINAPI WriteFile( HANDLE hFile, LPCVOID buffer, DWORD bytesToWrite,
1153                          LPDWORD bytesWritten, LPOVERLAPPED overlapped )
1154 {
1155     int unix_handle, result;
1156
1157     TRACE("%d %p %ld\n", hFile, buffer, bytesToWrite );
1158
1159     if (bytesWritten) *bytesWritten = 0;  /* Do this before anything else */
1160     if (!bytesToWrite) return TRUE;
1161
1162     if ( overlapped ) {
1163       SetLastError ( ERROR_INVALID_PARAMETER );
1164       return FALSE;
1165     }
1166
1167     unix_handle = FILE_GetUnixHandle( hFile, GENERIC_WRITE );
1168     if (unix_handle == -1) return FALSE;
1169     while ((result = write( unix_handle, buffer, bytesToWrite )) == -1)
1170     {
1171         if ((errno == EAGAIN) || (errno == EINTR)) continue;
1172         if ((errno == EFAULT) && !IsBadReadPtr( buffer, bytesToWrite )) continue;
1173         if (errno == ENOSPC)
1174             SetLastError( ERROR_DISK_FULL );
1175         else
1176         FILE_SetDosError();
1177         break;
1178     }
1179     close( unix_handle );
1180     if (result == -1) return FALSE;
1181     if (bytesWritten) *bytesWritten = result;
1182     return TRUE;
1183 }
1184
1185
1186 /***********************************************************************
1187  *           WIN16_hread
1188  */
1189 LONG WINAPI WIN16_hread( HFILE16 hFile, SEGPTR buffer, LONG count )
1190 {
1191     LONG maxlen;
1192
1193     TRACE("%d %08lx %ld\n",
1194                   hFile, (DWORD)buffer, count );
1195
1196     /* Some programs pass a count larger than the allocated buffer */
1197     maxlen = GetSelectorLimit16( SELECTOROF(buffer) ) - OFFSETOF(buffer) + 1;
1198     if (count > maxlen) count = maxlen;
1199     return _lread(DosFileHandleToWin32Handle(hFile), MapSL(buffer), count );
1200 }
1201
1202
1203 /***********************************************************************
1204  *           WIN16_lread
1205  */
1206 UINT16 WINAPI WIN16_lread( HFILE16 hFile, SEGPTR buffer, UINT16 count )
1207 {
1208     return (UINT16)WIN16_hread( hFile, buffer, (LONG)count );
1209 }
1210
1211
1212 /***********************************************************************
1213  *           _lread   (KERNEL32.596)
1214  */
1215 UINT WINAPI _lread( HFILE handle, LPVOID buffer, UINT count )
1216 {
1217     DWORD result;
1218     if (!ReadFile( handle, buffer, count, &result, NULL )) return -1;
1219     return result;
1220 }
1221
1222
1223 /***********************************************************************
1224  *           _lread16   (KERNEL.82)
1225  */
1226 UINT16 WINAPI _lread16( HFILE16 hFile, LPVOID buffer, UINT16 count )
1227 {
1228     return (UINT16)_lread(DosFileHandleToWin32Handle(hFile), buffer, (LONG)count );
1229 }
1230
1231
1232 /***********************************************************************
1233  *           _lcreat16   (KERNEL.83)
1234  */
1235 HFILE16 WINAPI _lcreat16( LPCSTR path, INT16 attr )
1236 {
1237     return Win32HandleToDosFileHandle( _lcreat( path, attr ) );
1238 }
1239
1240
1241 /***********************************************************************
1242  *           _lcreat   (KERNEL32.593)
1243  */
1244 HFILE WINAPI _lcreat( LPCSTR path, INT attr )
1245 {
1246     /* Mask off all flags not explicitly allowed by the doc */
1247     attr &= FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM;
1248     TRACE("%s %02x\n", path, attr );
1249     return CreateFileA( path, GENERIC_READ | GENERIC_WRITE,
1250                         FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
1251                         CREATE_ALWAYS, attr, -1 );
1252 }
1253
1254
1255 /***********************************************************************
1256  *           SetFilePointer   (KERNEL32.492)
1257  */
1258 DWORD WINAPI SetFilePointer( HANDLE hFile, LONG distance, LONG *highword,
1259                              DWORD method )
1260 {
1261     DWORD ret = 0xffffffff;
1262
1263     if (highword &&
1264         ((distance >= 0 && *highword != 0) || (distance < 0 && *highword != -1)))
1265     {
1266         FIXME("64-bit offsets not supported yet\n"
1267               "SetFilePointer(%08x,%08lx,%08lx,%08lx)\n",
1268               hFile,distance,*highword,method);
1269         SetLastError( ERROR_INVALID_PARAMETER );
1270         return ret;
1271     }
1272     TRACE("handle %d offset %ld origin %ld\n",
1273           hFile, distance, method );
1274
1275     SERVER_START_REQ
1276     {
1277         struct set_file_pointer_request *req = server_alloc_req( sizeof(*req), 0 );
1278         req->handle = hFile;
1279         req->low = distance;
1280         req->high = highword ? *highword : (distance >= 0) ? 0 : -1;
1281         /* FIXME: assumes 1:1 mapping between Windows and Unix seek constants */
1282         req->whence = method;
1283         SetLastError( 0 );
1284         if (!server_call( REQ_SET_FILE_POINTER ))
1285         {
1286             ret = req->new_low;
1287             if (highword) *highword = req->new_high;
1288         }
1289     }
1290     SERVER_END_REQ;
1291     return ret;
1292 }
1293
1294
1295 /***********************************************************************
1296  *           _llseek16   (KERNEL.84)
1297  *
1298  * FIXME:
1299  *   Seeking before the start of the file should be allowed for _llseek16,
1300  *   but cause subsequent I/O operations to fail (cf. interrupt list)
1301  *
1302  */
1303 LONG WINAPI _llseek16( HFILE16 hFile, LONG lOffset, INT16 nOrigin )
1304 {
1305     return SetFilePointer( DosFileHandleToWin32Handle(hFile), lOffset, NULL, nOrigin );
1306 }
1307
1308
1309 /***********************************************************************
1310  *           _llseek   (KERNEL32.594)
1311  */
1312 LONG WINAPI _llseek( HFILE hFile, LONG lOffset, INT nOrigin )
1313 {
1314     return SetFilePointer( hFile, lOffset, NULL, nOrigin );
1315 }
1316
1317
1318 /***********************************************************************
1319  *           _lopen16   (KERNEL.85)
1320  */
1321 HFILE16 WINAPI _lopen16( LPCSTR path, INT16 mode )
1322 {
1323     return Win32HandleToDosFileHandle( _lopen( path, mode ) );
1324 }
1325
1326
1327 /***********************************************************************
1328  *           _lopen   (KERNEL32.595)
1329  */
1330 HFILE WINAPI _lopen( LPCSTR path, INT mode )
1331 {
1332     DWORD access, sharing;
1333
1334     TRACE("('%s',%04x)\n", path, mode );
1335     FILE_ConvertOFMode( mode, &access, &sharing );
1336     return CreateFileA( path, access, sharing, NULL, OPEN_EXISTING, 0, -1 );
1337 }
1338
1339
1340 /***********************************************************************
1341  *           _lwrite16   (KERNEL.86)
1342  */
1343 UINT16 WINAPI _lwrite16( HFILE16 hFile, LPCSTR buffer, UINT16 count )
1344 {
1345     return (UINT16)_hwrite( DosFileHandleToWin32Handle(hFile), buffer, (LONG)count );
1346 }
1347
1348 /***********************************************************************
1349  *           _lwrite   (KERNEL32.761)
1350  */
1351 UINT WINAPI _lwrite( HFILE hFile, LPCSTR buffer, UINT count )
1352 {
1353     return (UINT)_hwrite( hFile, buffer, (LONG)count );
1354 }
1355
1356
1357 /***********************************************************************
1358  *           _hread16   (KERNEL.349)
1359  */
1360 LONG WINAPI _hread16( HFILE16 hFile, LPVOID buffer, LONG count)
1361 {
1362     return _lread( DosFileHandleToWin32Handle(hFile), buffer, count );
1363 }
1364
1365
1366 /***********************************************************************
1367  *           _hread   (KERNEL32.590)
1368  */
1369 LONG WINAPI _hread( HFILE hFile, LPVOID buffer, LONG count)
1370 {
1371     return _lread( hFile, buffer, count );
1372 }
1373
1374
1375 /***********************************************************************
1376  *           _hwrite16   (KERNEL.350)
1377  */
1378 LONG WINAPI _hwrite16( HFILE16 hFile, LPCSTR buffer, LONG count )
1379 {
1380     return _hwrite( DosFileHandleToWin32Handle(hFile), buffer, count );
1381 }
1382
1383
1384 /***********************************************************************
1385  *           _hwrite   (KERNEL32.591)
1386  *
1387  *      experimentation yields that _lwrite:
1388  *              o truncates the file at the current position with 
1389  *                a 0 len write
1390  *              o returns 0 on a 0 length write
1391  *              o works with console handles
1392  *              
1393  */
1394 LONG WINAPI _hwrite( HFILE handle, LPCSTR buffer, LONG count )
1395 {
1396     DWORD result;
1397
1398     TRACE("%d %p %ld\n", handle, buffer, count );
1399
1400     if (!count)
1401     {
1402         /* Expand or truncate at current position */
1403         if (!SetEndOfFile( handle )) return HFILE_ERROR;
1404         return 0;
1405     }
1406     if (!WriteFile( handle, buffer, count, &result, NULL ))
1407         return HFILE_ERROR;
1408     return result;
1409 }
1410
1411
1412 /***********************************************************************
1413  *           SetHandleCount16   (KERNEL.199)
1414  */
1415 UINT16 WINAPI SetHandleCount16( UINT16 count )
1416 {
1417     HGLOBAL16 hPDB = GetCurrentPDB16();
1418     PDB16 *pdb = (PDB16 *)GlobalLock16( hPDB );
1419     BYTE *files = MapSL( pdb->fileHandlesPtr );
1420
1421     TRACE("(%d)\n", count );
1422
1423     if (count < 20) count = 20;  /* No point in going below 20 */
1424     else if (count > 254) count = 254;
1425
1426     if (count == 20)
1427     {
1428         if (pdb->nbFiles > 20)
1429         {
1430             memcpy( pdb->fileHandles, files, 20 );
1431             GlobalFree16( pdb->hFileHandles );
1432             pdb->fileHandlesPtr = (SEGPTR)MAKELONG( 0x18,
1433                                                    GlobalHandleToSel16( hPDB ) );
1434             pdb->hFileHandles = 0;
1435             pdb->nbFiles = 20;
1436         }
1437     }
1438     else  /* More than 20, need a new file handles table */
1439     {
1440         BYTE *newfiles;
1441         HGLOBAL16 newhandle = GlobalAlloc16( GMEM_MOVEABLE, count );
1442         if (!newhandle)
1443         {
1444             SetLastError( ERROR_NOT_ENOUGH_MEMORY );
1445             return pdb->nbFiles;
1446         }
1447         newfiles = (BYTE *)GlobalLock16( newhandle );
1448
1449         if (count > pdb->nbFiles)
1450         {
1451             memcpy( newfiles, files, pdb->nbFiles );
1452             memset( newfiles + pdb->nbFiles, 0xff, count - pdb->nbFiles );
1453         }
1454         else memcpy( newfiles, files, count );
1455         if (pdb->nbFiles > 20) GlobalFree16( pdb->hFileHandles );
1456         pdb->fileHandlesPtr = WIN16_GlobalLock16( newhandle );
1457         pdb->hFileHandles   = newhandle;
1458         pdb->nbFiles = count;
1459     }
1460     return pdb->nbFiles;
1461 }
1462
1463
1464 /*************************************************************************
1465  *           SetHandleCount   (KERNEL32.494)
1466  */
1467 UINT WINAPI SetHandleCount( UINT count )
1468 {
1469     return min( 256, count );
1470 }
1471
1472
1473 /***********************************************************************
1474  *           FlushFileBuffers   (KERNEL32.133)
1475  */
1476 BOOL WINAPI FlushFileBuffers( HANDLE hFile )
1477 {
1478     BOOL ret;
1479     SERVER_START_REQ
1480     {
1481         struct flush_file_request *req = server_alloc_req( sizeof(*req), 0 );
1482         req->handle = hFile;
1483         ret = !server_call( REQ_FLUSH_FILE );
1484     }
1485     SERVER_END_REQ;
1486     return ret;
1487 }
1488
1489
1490 /**************************************************************************
1491  *           SetEndOfFile   (KERNEL32.483)
1492  */
1493 BOOL WINAPI SetEndOfFile( HANDLE hFile )
1494 {
1495     BOOL ret;
1496     SERVER_START_REQ
1497     {
1498         struct truncate_file_request *req = server_alloc_req( sizeof(*req), 0 );
1499         req->handle = hFile;
1500         ret = !server_call( REQ_TRUNCATE_FILE );
1501     }
1502     SERVER_END_REQ;
1503     return ret;
1504 }
1505
1506
1507 /***********************************************************************
1508  *           DeleteFile16   (KERNEL.146)
1509  */
1510 BOOL16 WINAPI DeleteFile16( LPCSTR path )
1511 {
1512     return DeleteFileA( path );
1513 }
1514
1515
1516 /***********************************************************************
1517  *           DeleteFileA   (KERNEL32.71)
1518  */
1519 BOOL WINAPI DeleteFileA( LPCSTR path )
1520 {
1521     DOS_FULL_NAME full_name;
1522
1523     TRACE("'%s'\n", path );
1524
1525     if (!*path)
1526     {
1527         ERR("Empty path passed\n");
1528         return FALSE;
1529     }
1530     if (DOSFS_GetDevice( path ))
1531     {
1532         WARN("cannot remove DOS device '%s'!\n", path);
1533         SetLastError( ERROR_FILE_NOT_FOUND );
1534         return FALSE;
1535     }
1536
1537     if (!DOSFS_GetFullName( path, TRUE, &full_name )) return FALSE;
1538     if (unlink( full_name.long_name ) == -1)
1539     {
1540         FILE_SetDosError();
1541         return FALSE;
1542     }
1543     return TRUE;
1544 }
1545
1546
1547 /***********************************************************************
1548  *           DeleteFileW   (KERNEL32.72)
1549  */
1550 BOOL WINAPI DeleteFileW( LPCWSTR path )
1551 {
1552     LPSTR xpath = HEAP_strdupWtoA( GetProcessHeap(), 0, path );
1553     BOOL ret = DeleteFileA( xpath );
1554     HeapFree( GetProcessHeap(), 0, xpath );
1555     return ret;
1556 }
1557
1558
1559 /***********************************************************************
1560  *           GetFileType   (KERNEL32.222)
1561  */
1562 DWORD WINAPI GetFileType( HANDLE hFile )
1563 {
1564     DWORD ret = FILE_TYPE_UNKNOWN;
1565     SERVER_START_REQ
1566     {
1567         struct get_file_info_request *req = server_alloc_req( sizeof(*req), 0 );
1568         req->handle = hFile;
1569         if (!server_call( REQ_GET_FILE_INFO )) ret = req->type;
1570     }
1571     SERVER_END_REQ;
1572     return ret;
1573 }
1574
1575
1576 /**************************************************************************
1577  *           MoveFileExA   (KERNEL32.???)
1578  */
1579 BOOL WINAPI MoveFileExA( LPCSTR fn1, LPCSTR fn2, DWORD flag )
1580 {
1581     DOS_FULL_NAME full_name1, full_name2;
1582
1583     TRACE("(%s,%s,%04lx)\n", fn1, fn2, flag);
1584
1585     if (!DOSFS_GetFullName( fn1, TRUE, &full_name1 )) return FALSE;
1586
1587     if (fn2)  /* !fn2 means delete fn1 */
1588     {
1589         if (DOSFS_GetFullName( fn2, TRUE, &full_name2 )) 
1590         {
1591             /* target exists, check if we may overwrite */
1592             if (!(flag & MOVEFILE_REPLACE_EXISTING))
1593             {
1594                 /* FIXME: Use right error code */
1595                 SetLastError( ERROR_ACCESS_DENIED );
1596                 return FALSE;
1597             }
1598         }
1599         else if (!DOSFS_GetFullName( fn2, FALSE, &full_name2 )) return FALSE;
1600
1601         /* Source name and target path are valid */
1602
1603         if (flag & MOVEFILE_DELAY_UNTIL_REBOOT)
1604         {
1605             /* FIXME: (bon@elektron.ikp.physik.th-darmstadt.de 970706)
1606                Perhaps we should queue these command and execute it 
1607                when exiting... What about using on_exit(2)
1608             */
1609             FIXME("Please move existing file '%s' to file '%s' when Wine has finished\n",
1610                   full_name1.long_name, full_name2.long_name);
1611             return TRUE;
1612         }
1613
1614         if (full_name1.drive != full_name2.drive)
1615         {
1616             /* use copy, if allowed */
1617             if (!(flag & MOVEFILE_COPY_ALLOWED))
1618             {
1619                 /* FIXME: Use right error code */
1620                 SetLastError( ERROR_FILE_EXISTS );
1621                 return FALSE;
1622             }
1623             return CopyFileA( fn1, fn2, !(flag & MOVEFILE_REPLACE_EXISTING) );
1624         }
1625         if (rename( full_name1.long_name, full_name2.long_name ) == -1)
1626         {
1627             FILE_SetDosError();
1628             return FALSE;
1629         }
1630         return TRUE;
1631     }
1632     else /* fn2 == NULL means delete source */
1633     {
1634         if (flag & MOVEFILE_DELAY_UNTIL_REBOOT)
1635         {
1636             if (flag & MOVEFILE_COPY_ALLOWED) {  
1637                 WARN("Illegal flag\n");
1638                 SetLastError( ERROR_GEN_FAILURE );
1639                 return FALSE;
1640             }
1641             /* FIXME: (bon@elektron.ikp.physik.th-darmstadt.de 970706)
1642                Perhaps we should queue these command and execute it 
1643                when exiting... What about using on_exit(2)
1644             */
1645             FIXME("Please delete file '%s' when Wine has finished\n",
1646                   full_name1.long_name);
1647             return TRUE;
1648         }
1649
1650         if (unlink( full_name1.long_name ) == -1)
1651         {
1652             FILE_SetDosError();
1653             return FALSE;
1654         }
1655         return TRUE; /* successfully deleted */
1656     }
1657 }
1658
1659 /**************************************************************************
1660  *           MoveFileExW   (KERNEL32.???)
1661  */
1662 BOOL WINAPI MoveFileExW( LPCWSTR fn1, LPCWSTR fn2, DWORD flag )
1663 {
1664     LPSTR afn1 = HEAP_strdupWtoA( GetProcessHeap(), 0, fn1 );
1665     LPSTR afn2 = HEAP_strdupWtoA( GetProcessHeap(), 0, fn2 );
1666     BOOL res = MoveFileExA( afn1, afn2, flag );
1667     HeapFree( GetProcessHeap(), 0, afn1 );
1668     HeapFree( GetProcessHeap(), 0, afn2 );
1669     return res;
1670 }
1671
1672
1673 /**************************************************************************
1674  *           MoveFileA   (KERNEL32.387)
1675  *
1676  *  Move file or directory
1677  */
1678 BOOL WINAPI MoveFileA( LPCSTR fn1, LPCSTR fn2 )
1679 {
1680     DOS_FULL_NAME full_name1, full_name2;
1681     struct stat fstat;
1682
1683     TRACE("(%s,%s)\n", fn1, fn2 );
1684
1685     if (!DOSFS_GetFullName( fn1, TRUE, &full_name1 )) return FALSE;
1686     if (DOSFS_GetFullName( fn2, TRUE, &full_name2 ))  {
1687       /* The new name must not already exist */ 
1688       SetLastError(ERROR_ALREADY_EXISTS);
1689       return FALSE;
1690     }
1691     if (!DOSFS_GetFullName( fn2, FALSE, &full_name2 )) return FALSE;
1692
1693     if (full_name1.drive == full_name2.drive) /* move */
1694     if (rename( full_name1.long_name, full_name2.long_name ) == -1)
1695     {
1696         FILE_SetDosError();
1697         return FALSE;
1698     }
1699       else return TRUE;
1700     else /*copy */ {
1701       if (stat(  full_name1.long_name, &fstat ))
1702         {
1703           WARN("Invalid source file %s\n",
1704                         full_name1.long_name);
1705           FILE_SetDosError();
1706           return FALSE;
1707         }
1708       if (S_ISDIR(fstat.st_mode)) {
1709         /* No Move for directories across file systems */
1710         /* FIXME: Use right error code */
1711         SetLastError( ERROR_GEN_FAILURE );
1712         return FALSE;
1713       }
1714       else
1715         return CopyFileA(fn1, fn2, TRUE); /*fail, if exist */ 
1716     }
1717 }
1718
1719
1720 /**************************************************************************
1721  *           MoveFileW   (KERNEL32.390)
1722  */
1723 BOOL WINAPI MoveFileW( LPCWSTR fn1, LPCWSTR fn2 )
1724 {
1725     LPSTR afn1 = HEAP_strdupWtoA( GetProcessHeap(), 0, fn1 );
1726     LPSTR afn2 = HEAP_strdupWtoA( GetProcessHeap(), 0, fn2 );
1727     BOOL res = MoveFileA( afn1, afn2 );
1728     HeapFree( GetProcessHeap(), 0, afn1 );
1729     HeapFree( GetProcessHeap(), 0, afn2 );
1730     return res;
1731 }
1732
1733
1734 /**************************************************************************
1735  *           CopyFileA   (KERNEL32.36)
1736  */
1737 BOOL WINAPI CopyFileA( LPCSTR source, LPCSTR dest, BOOL fail_if_exists )
1738 {
1739     HFILE h1, h2;
1740     BY_HANDLE_FILE_INFORMATION info;
1741     UINT count;
1742     BOOL ret = FALSE;
1743     int mode;
1744     char buffer[2048];
1745
1746     if ((h1 = _lopen( source, OF_READ )) == HFILE_ERROR) return FALSE;
1747     if (!GetFileInformationByHandle( h1, &info ))
1748     {
1749         CloseHandle( h1 );
1750         return FALSE;
1751     }
1752     mode = (info.dwFileAttributes & FILE_ATTRIBUTE_READONLY) ? 0444 : 0666;
1753     if ((h2 = CreateFileA( dest, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
1754                              fail_if_exists ? CREATE_NEW : CREATE_ALWAYS,
1755                              info.dwFileAttributes, h1 )) == HFILE_ERROR)
1756     {
1757         CloseHandle( h1 );
1758         return FALSE;
1759     }
1760     while ((count = _lread( h1, buffer, sizeof(buffer) )) > 0)
1761     {
1762         char *p = buffer;
1763         while (count > 0)
1764         {
1765             INT res = _lwrite( h2, p, count );
1766             if (res <= 0) goto done;
1767             p += res;
1768             count -= res;
1769         }
1770     }
1771     ret =  TRUE;
1772 done:
1773     CloseHandle( h1 );
1774     CloseHandle( h2 );
1775     return ret;
1776 }
1777
1778
1779 /**************************************************************************
1780  *           CopyFileW   (KERNEL32.37)
1781  */
1782 BOOL WINAPI CopyFileW( LPCWSTR source, LPCWSTR dest, BOOL fail_if_exists)
1783 {
1784     LPSTR sourceA = HEAP_strdupWtoA( GetProcessHeap(), 0, source );
1785     LPSTR destA   = HEAP_strdupWtoA( GetProcessHeap(), 0, dest );
1786     BOOL ret = CopyFileA( sourceA, destA, fail_if_exists );
1787     HeapFree( GetProcessHeap(), 0, sourceA );
1788     HeapFree( GetProcessHeap(), 0, destA );
1789     return ret;
1790 }
1791
1792
1793 /**************************************************************************
1794  *           CopyFileExA   (KERNEL32.858)
1795  *
1796  * This implementation ignores most of the extra parameters passed-in into
1797  * the "ex" version of the method and calls the CopyFile method.
1798  * It will have to be fixed eventually.
1799  */
1800 BOOL WINAPI CopyFileExA(LPCSTR             sourceFilename,
1801                            LPCSTR             destFilename,
1802                            LPPROGRESS_ROUTINE progressRoutine,
1803                            LPVOID             appData,
1804                            LPBOOL           cancelFlagPointer,
1805                            DWORD              copyFlags)
1806 {
1807   BOOL failIfExists = FALSE;
1808
1809   /*
1810    * Interpret the only flag that CopyFile can interpret.
1811    */
1812   if ( (copyFlags & COPY_FILE_FAIL_IF_EXISTS) != 0)
1813   {
1814     failIfExists = TRUE;
1815   }
1816
1817   return CopyFileA(sourceFilename, destFilename, failIfExists);
1818 }
1819
1820 /**************************************************************************
1821  *           CopyFileExW   (KERNEL32.859)
1822  */
1823 BOOL WINAPI CopyFileExW(LPCWSTR            sourceFilename,
1824                            LPCWSTR            destFilename,
1825                            LPPROGRESS_ROUTINE progressRoutine,
1826                            LPVOID             appData,
1827                            LPBOOL           cancelFlagPointer,
1828                            DWORD              copyFlags)
1829 {
1830     LPSTR sourceA = HEAP_strdupWtoA( GetProcessHeap(), 0, sourceFilename );
1831     LPSTR destA   = HEAP_strdupWtoA( GetProcessHeap(), 0, destFilename );
1832
1833     BOOL ret = CopyFileExA(sourceA,
1834                               destA,
1835                               progressRoutine,
1836                               appData,
1837                               cancelFlagPointer,
1838                               copyFlags);
1839
1840     HeapFree( GetProcessHeap(), 0, sourceA );
1841     HeapFree( GetProcessHeap(), 0, destA );
1842
1843     return ret;
1844 }
1845
1846
1847 /***********************************************************************
1848  *              SetFileTime   (KERNEL32.650)
1849  */
1850 BOOL WINAPI SetFileTime( HANDLE hFile,
1851                            const FILETIME *lpCreationTime,
1852                            const FILETIME *lpLastAccessTime,
1853                            const FILETIME *lpLastWriteTime )
1854 {
1855     BOOL ret;
1856     SERVER_START_REQ
1857     {
1858         struct set_file_time_request *req = server_alloc_req( sizeof(*req), 0 );
1859         req->handle = hFile;
1860         if (lpLastAccessTime)
1861             RtlTimeToSecondsSince1970( lpLastAccessTime, (DWORD *)&req->access_time );
1862         else
1863             req->access_time = 0; /* FIXME */
1864         if (lpLastWriteTime)
1865             RtlTimeToSecondsSince1970( lpLastWriteTime, (DWORD *)&req->write_time );
1866         else
1867             req->write_time = 0; /* FIXME */
1868         ret = !server_call( REQ_SET_FILE_TIME );
1869     }
1870     SERVER_END_REQ;
1871     return ret;
1872 }
1873
1874
1875 /**************************************************************************
1876  *           LockFile   (KERNEL32.511)
1877  */
1878 BOOL WINAPI LockFile( HANDLE hFile, DWORD dwFileOffsetLow, DWORD dwFileOffsetHigh,
1879                         DWORD nNumberOfBytesToLockLow, DWORD nNumberOfBytesToLockHigh )
1880 {
1881     BOOL ret;
1882     SERVER_START_REQ
1883     {
1884         struct lock_file_request *req = server_alloc_req( sizeof(*req), 0 );
1885
1886         req->handle      = hFile;
1887         req->offset_low  = dwFileOffsetLow;
1888         req->offset_high = dwFileOffsetHigh;
1889         req->count_low   = nNumberOfBytesToLockLow;
1890         req->count_high  = nNumberOfBytesToLockHigh;
1891         ret = !server_call( REQ_LOCK_FILE );
1892     }
1893     SERVER_END_REQ;
1894     return ret;
1895 }
1896
1897 /**************************************************************************
1898  * LockFileEx [KERNEL32.512]
1899  *
1900  * Locks a byte range within an open file for shared or exclusive access.
1901  *
1902  * RETURNS
1903  *   success: TRUE
1904  *   failure: FALSE
1905  * NOTES
1906  *
1907  * Per Microsoft docs, the third parameter (reserved) must be set to 0.
1908  */
1909 BOOL WINAPI LockFileEx( HANDLE hFile, DWORD flags, DWORD reserved,
1910                       DWORD nNumberOfBytesToLockLow, DWORD nNumberOfBytesToLockHigh,
1911                       LPOVERLAPPED pOverlapped )
1912 {
1913     FIXME("hFile=%d,flags=%ld,reserved=%ld,lowbytes=%ld,highbytes=%ld,overlapped=%p: stub.\n",
1914           hFile, flags, reserved, nNumberOfBytesToLockLow, nNumberOfBytesToLockHigh,
1915           pOverlapped);
1916     if (reserved == 0)
1917         SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1918     else
1919     {
1920         ERR("reserved == %ld: Supposed to be 0??\n", reserved);
1921         SetLastError(ERROR_INVALID_PARAMETER);
1922     }
1923
1924     return FALSE;
1925 }
1926
1927
1928 /**************************************************************************
1929  *           UnlockFile   (KERNEL32.703)
1930  */
1931 BOOL WINAPI UnlockFile( HANDLE hFile, DWORD dwFileOffsetLow, DWORD dwFileOffsetHigh,
1932                           DWORD nNumberOfBytesToUnlockLow, DWORD nNumberOfBytesToUnlockHigh )
1933 {
1934     BOOL ret;
1935     SERVER_START_REQ
1936     {
1937         struct unlock_file_request *req = server_alloc_req( sizeof(*req), 0 );
1938
1939         req->handle      = hFile;
1940         req->offset_low  = dwFileOffsetLow;
1941         req->offset_high = dwFileOffsetHigh;
1942         req->count_low   = nNumberOfBytesToUnlockLow;
1943         req->count_high  = nNumberOfBytesToUnlockHigh;
1944         ret = !server_call( REQ_UNLOCK_FILE );
1945     }
1946     SERVER_END_REQ;
1947     return ret;
1948 }
1949
1950
1951 /**************************************************************************
1952  *           UnlockFileEx   (KERNEL32.705)
1953  */
1954 BOOL WINAPI UnlockFileEx(
1955                 HFILE hFile,
1956                 DWORD dwReserved,
1957                 DWORD nNumberOfBytesToUnlockLow,
1958                 DWORD nNumberOfBytesToUnlockHigh,
1959                 LPOVERLAPPED lpOverlapped
1960 )
1961 {
1962         FIXME("hFile=%d,reserved=%ld,lowbytes=%ld,highbytes=%ld,overlapped=%p: stub.\n",
1963           hFile, dwReserved, nNumberOfBytesToUnlockLow, nNumberOfBytesToUnlockHigh,
1964           lpOverlapped);
1965         if (dwReserved == 0)
1966                 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1967         else
1968         {
1969                 ERR("reserved == %ld: Supposed to be 0??\n", dwReserved);
1970                 SetLastError(ERROR_INVALID_PARAMETER);
1971         }
1972
1973         return FALSE;
1974 }
1975
1976
1977 #if 0
1978
1979 struct DOS_FILE_LOCK {
1980   struct DOS_FILE_LOCK *        next;
1981   DWORD                         base;
1982   DWORD                         len;
1983   DWORD                         processId;
1984   FILE_OBJECT *                 dos_file;
1985 /*  char *                      unix_name;*/
1986 };
1987
1988 typedef struct DOS_FILE_LOCK DOS_FILE_LOCK;
1989
1990 static DOS_FILE_LOCK *locks = NULL;
1991 static void DOS_RemoveFileLocks(FILE_OBJECT *file);
1992
1993
1994 /* Locks need to be mirrored because unix file locking is based
1995  * on the pid. Inside of wine there can be multiple WINE processes
1996  * that share the same unix pid.
1997  * Read's and writes should check these locks also - not sure
1998  * how critical that is at this point (FIXME).
1999  */
2000
2001 static BOOL DOS_AddLock(FILE_OBJECT *file, struct flock *f)
2002 {
2003   DOS_FILE_LOCK *curr;
2004   DWORD         processId;
2005
2006   processId = GetCurrentProcessId();
2007
2008   /* check if lock overlaps a current lock for the same file */
2009 #if 0
2010   for (curr = locks; curr; curr = curr->next) {
2011     if (strcmp(curr->unix_name, file->unix_name) == 0) {
2012       if ((f->l_start == curr->base) && (f->l_len == curr->len))
2013         return TRUE;/* region is identic */
2014       if ((f->l_start < (curr->base + curr->len)) &&
2015           ((f->l_start + f->l_len) > curr->base)) {
2016         /* region overlaps */
2017         return FALSE;
2018       }
2019     }
2020   }
2021 #endif
2022
2023   curr = HeapAlloc( GetProcessHeap(), 0, sizeof(DOS_FILE_LOCK) );
2024   curr->processId = GetCurrentProcessId();
2025   curr->base = f->l_start;
2026   curr->len = f->l_len;
2027 /*  curr->unix_name = HEAP_strdupA( GetProcessHeap(), 0, file->unix_name);*/
2028   curr->next = locks;
2029   curr->dos_file = file;
2030   locks = curr;
2031   return TRUE;
2032 }
2033
2034 static void DOS_RemoveFileLocks(FILE_OBJECT *file)
2035 {
2036   DWORD         processId;
2037   DOS_FILE_LOCK **curr;
2038   DOS_FILE_LOCK *rem;
2039
2040   processId = GetCurrentProcessId();
2041   curr = &locks;
2042   while (*curr) {
2043     if ((*curr)->dos_file == file) {
2044       rem = *curr;
2045       *curr = (*curr)->next;
2046 /*      HeapFree( GetProcessHeap(), 0, rem->unix_name );*/
2047       HeapFree( GetProcessHeap(), 0, rem );
2048     }
2049     else
2050       curr = &(*curr)->next;
2051   }
2052 }
2053
2054 static BOOL DOS_RemoveLock(FILE_OBJECT *file, struct flock *f)
2055 {
2056   DWORD         processId;
2057   DOS_FILE_LOCK **curr;
2058   DOS_FILE_LOCK *rem;
2059
2060   processId = GetCurrentProcessId();
2061   for (curr = &locks; *curr; curr = &(*curr)->next) {
2062     if ((*curr)->processId == processId &&
2063         (*curr)->dos_file == file &&
2064         (*curr)->base == f->l_start &&
2065         (*curr)->len == f->l_len) {
2066       /* this is the same lock */
2067       rem = *curr;
2068       *curr = (*curr)->next;
2069 /*      HeapFree( GetProcessHeap(), 0, rem->unix_name );*/
2070       HeapFree( GetProcessHeap(), 0, rem );
2071       return TRUE;
2072     }
2073   }
2074   /* no matching lock found */
2075   return FALSE;
2076 }
2077
2078
2079 /**************************************************************************
2080  *           LockFile   (KERNEL32.511)
2081  */
2082 BOOL WINAPI LockFile(
2083         HFILE hFile,DWORD dwFileOffsetLow,DWORD dwFileOffsetHigh,
2084         DWORD nNumberOfBytesToLockLow,DWORD nNumberOfBytesToLockHigh )
2085 {
2086   struct flock f;
2087   FILE_OBJECT *file;
2088
2089   TRACE("handle %d offsetlow=%ld offsethigh=%ld nbyteslow=%ld nbyteshigh=%ld\n",
2090                hFile, dwFileOffsetLow, dwFileOffsetHigh,
2091                nNumberOfBytesToLockLow, nNumberOfBytesToLockHigh);
2092
2093   if (dwFileOffsetHigh || nNumberOfBytesToLockHigh) {
2094     FIXME("Unimplemented bytes > 32bits\n");
2095     return FALSE;
2096   }
2097
2098   f.l_start = dwFileOffsetLow;
2099   f.l_len = nNumberOfBytesToLockLow;
2100   f.l_whence = SEEK_SET;
2101   f.l_pid = 0;
2102   f.l_type = F_WRLCK;
2103
2104   if (!(file = FILE_GetFile(hFile,0,NULL))) return FALSE;
2105
2106   /* shadow locks internally */
2107   if (!DOS_AddLock(file, &f)) {
2108     SetLastError( ERROR_LOCK_VIOLATION );
2109     return FALSE;
2110   }
2111
2112   /* FIXME: Unix locking commented out for now, doesn't work with Excel */
2113 #ifdef USE_UNIX_LOCKS
2114   if (fcntl(file->unix_handle, F_SETLK, &f) == -1) {
2115     if (errno == EACCES || errno == EAGAIN) {
2116       SetLastError( ERROR_LOCK_VIOLATION );
2117     }
2118     else {
2119       FILE_SetDosError();
2120     }
2121     /* remove our internal copy of the lock */
2122     DOS_RemoveLock(file, &f);
2123     return FALSE;
2124   }
2125 #endif
2126   return TRUE;
2127 }
2128
2129
2130 /**************************************************************************
2131  *           UnlockFile   (KERNEL32.703)
2132  */
2133 BOOL WINAPI UnlockFile(
2134         HFILE hFile,DWORD dwFileOffsetLow,DWORD dwFileOffsetHigh,
2135         DWORD nNumberOfBytesToUnlockLow,DWORD nNumberOfBytesToUnlockHigh )
2136 {
2137   FILE_OBJECT *file;
2138   struct flock f;
2139
2140   TRACE("handle %d offsetlow=%ld offsethigh=%ld nbyteslow=%ld nbyteshigh=%ld\n",
2141                hFile, dwFileOffsetLow, dwFileOffsetHigh,
2142                nNumberOfBytesToUnlockLow, nNumberOfBytesToUnlockHigh);
2143
2144   if (dwFileOffsetHigh || nNumberOfBytesToUnlockHigh) {
2145     WARN("Unimplemented bytes > 32bits\n");
2146     return FALSE;
2147   }
2148
2149   f.l_start = dwFileOffsetLow;
2150   f.l_len = nNumberOfBytesToUnlockLow;
2151   f.l_whence = SEEK_SET;
2152   f.l_pid = 0;
2153   f.l_type = F_UNLCK;
2154
2155   if (!(file = FILE_GetFile(hFile,0,NULL))) return FALSE;
2156
2157   DOS_RemoveLock(file, &f);     /* ok if fails - may be another wine */
2158
2159   /* FIXME: Unix locking commented out for now, doesn't work with Excel */
2160 #ifdef USE_UNIX_LOCKS
2161   if (fcntl(file->unix_handle, F_SETLK, &f) == -1) {
2162     FILE_SetDosError();
2163     return FALSE;
2164   }
2165 #endif
2166   return TRUE;
2167 }
2168 #endif
2169
2170 /**************************************************************************
2171  * GetFileAttributesExA [KERNEL32.874]
2172  */
2173 BOOL WINAPI GetFileAttributesExA(
2174         LPCSTR lpFileName, GET_FILEEX_INFO_LEVELS fInfoLevelId,
2175         LPVOID lpFileInformation)
2176 {
2177     DOS_FULL_NAME full_name;
2178     BY_HANDLE_FILE_INFORMATION info;
2179     
2180     if (lpFileName == NULL) return FALSE;
2181     if (lpFileInformation == NULL) return FALSE;
2182
2183     if (fInfoLevelId == GetFileExInfoStandard) {
2184         LPWIN32_FILE_ATTRIBUTE_DATA lpFad = 
2185             (LPWIN32_FILE_ATTRIBUTE_DATA) lpFileInformation;
2186         if (!DOSFS_GetFullName( lpFileName, TRUE, &full_name )) return FALSE;
2187         if (!FILE_Stat( full_name.long_name, &info )) return FALSE;
2188
2189         lpFad->dwFileAttributes = info.dwFileAttributes;
2190         lpFad->ftCreationTime   = info.ftCreationTime;
2191         lpFad->ftLastAccessTime = info.ftLastAccessTime;
2192         lpFad->ftLastWriteTime  = info.ftLastWriteTime;
2193         lpFad->nFileSizeHigh    = info.nFileSizeHigh;
2194         lpFad->nFileSizeLow     = info.nFileSizeLow;
2195     }
2196     else {
2197         FIXME("invalid info level %d!\n", fInfoLevelId);
2198         return FALSE;
2199     }
2200
2201     return TRUE;
2202 }
2203
2204
2205 /**************************************************************************
2206  * GetFileAttributesExW [KERNEL32.875]
2207  */
2208 BOOL WINAPI GetFileAttributesExW(
2209         LPCWSTR lpFileName, GET_FILEEX_INFO_LEVELS fInfoLevelId,
2210         LPVOID lpFileInformation)
2211 {
2212     LPSTR nameA = HEAP_strdupWtoA( GetProcessHeap(), 0, lpFileName );
2213     BOOL res = 
2214         GetFileAttributesExA( nameA, fInfoLevelId, lpFileInformation);
2215     HeapFree( GetProcessHeap(), 0, nameA );
2216     return res;
2217 }