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