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