Added regedit unit test, a couple minor changes to regedit.
[wine] / files / file.c
1 /*
2  * File handling functions
3  *
4  * Copyright 1993 John Burton
5  * Copyright 1996 Alexandre Julliard
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, write to the Free Software
19  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
20  *
21  * TODO:
22  *    Fix the CopyFileEx methods to implement the "extended" functionality.
23  *    Right now, they simply call the CopyFile method.
24  */
25
26 #include "config.h"
27 #include "wine/port.h"
28
29 #include <assert.h>
30 #include <ctype.h>
31 #include <errno.h>
32 #include <fcntl.h>
33 #include <stdlib.h>
34 #include <stdio.h>
35 #include <string.h>
36 #ifdef HAVE_SYS_ERRNO_H
37 #include <sys/errno.h>
38 #endif
39 #include <sys/types.h>
40 #include <sys/stat.h>
41 #ifdef HAVE_SYS_MMAN_H
42 #include <sys/mman.h>
43 #endif
44 #include <sys/time.h>
45 #include <sys/poll.h>
46 #include <time.h>
47 #include <unistd.h>
48 #include <utime.h>
49
50 #include "winerror.h"
51 #include "windef.h"
52 #include "winbase.h"
53 #include "wine/winbase16.h"
54 #include "wine/server.h"
55
56 #include "drive.h"
57 #include "file.h"
58 #include "async.h"
59 #include "heap.h"
60 #include "msdos.h"
61 #include "wincon.h"
62
63 #include "smb.h"
64 #include "wine/debug.h"
65
66 WINE_DEFAULT_DEBUG_CHANNEL(file);
67
68 #if defined(MAP_ANONYMOUS) && !defined(MAP_ANON)
69 #define MAP_ANON MAP_ANONYMOUS
70 #endif
71
72 /* Size of per-process table of DOS handles */
73 #define DOS_TABLE_SIZE 256
74
75 /* Macro to derive file offset from OVERLAPPED struct */
76 #define OVERLAPPED_OFFSET(overlapped) ((off_t) (overlapped)->Offset + ((off_t) (overlapped)->OffsetHigh << 32))
77
78 static HANDLE dos_handles[DOS_TABLE_SIZE];
79
80 mode_t FILE_umask;
81
82 extern HANDLE WINAPI FILE_SmbOpen(LPCSTR name);
83
84 /***********************************************************************
85  *                  Asynchronous file I/O                              *
86  */
87 static DWORD fileio_get_async_status (const async_private *ovp);
88 static DWORD fileio_get_async_count (const async_private *ovp);
89 static void fileio_set_async_status (async_private *ovp, const DWORD status);
90 static void CALLBACK fileio_call_completion_func (ULONG_PTR data);
91 static void fileio_async_cleanup (async_private *ovp);
92
93 static async_ops fileio_async_ops =
94 {
95     fileio_get_async_status,       /* get_status */
96     fileio_set_async_status,       /* set_status */
97     fileio_get_async_count,        /* get_count */
98     fileio_call_completion_func,   /* call_completion */
99     fileio_async_cleanup           /* cleanup */
100 };
101
102 static async_ops fileio_nocomp_async_ops =
103 {
104     fileio_get_async_status,       /* get_status */
105     fileio_set_async_status,       /* set_status */
106     fileio_get_async_count,        /* get_count */
107     NULL,                          /* call_completion */
108     fileio_async_cleanup           /* cleanup */
109 };
110
111 typedef struct async_fileio
112 {
113     struct async_private             async;
114     LPOVERLAPPED                     lpOverlapped;
115     LPOVERLAPPED_COMPLETION_ROUTINE  completion_func;
116     char                             *buffer;
117     int                              count;
118     enum fd_type                     fd_type;
119 } async_fileio;
120
121 static DWORD fileio_get_async_status (const struct async_private *ovp)
122 {
123     return ((async_fileio*) ovp)->lpOverlapped->Internal;
124 }
125
126 static void fileio_set_async_status (async_private *ovp, const DWORD status)
127 {
128     ((async_fileio*) ovp)->lpOverlapped->Internal = status;
129 }
130
131 static DWORD fileio_get_async_count (const struct async_private *ovp)
132 {
133     async_fileio *fileio = (async_fileio*) ovp;
134     DWORD ret = fileio->count - fileio->lpOverlapped->InternalHigh;
135     return (ret < 0 ? 0 : ret);
136 }
137
138 static void CALLBACK fileio_call_completion_func (ULONG_PTR data)
139 {
140     async_fileio *ovp = (async_fileio*) data;
141     TRACE ("data: %p\n", ovp);
142
143     ovp->completion_func( ovp->lpOverlapped->Internal,
144                           ovp->lpOverlapped->InternalHigh,
145                           ovp->lpOverlapped );
146
147     fileio_async_cleanup ( &ovp->async );
148 }
149
150 static void fileio_async_cleanup ( struct async_private *ovp )
151 {
152     HeapFree ( GetProcessHeap(), 0, ovp );
153 }
154
155 /***********************************************************************
156  *              FILE_ConvertOFMode
157  *
158  * Convert OF_* mode into flags for CreateFile.
159  */
160 static void FILE_ConvertOFMode( INT mode, DWORD *access, DWORD *sharing )
161 {
162     switch(mode & 0x03)
163     {
164     case OF_READ:      *access = GENERIC_READ; break;
165     case OF_WRITE:     *access = GENERIC_WRITE; break;
166     case OF_READWRITE: *access = GENERIC_READ | GENERIC_WRITE; break;
167     default:           *access = 0; break;
168     }
169     switch(mode & 0x70)
170     {
171     case OF_SHARE_EXCLUSIVE:  *sharing = 0; break;
172     case OF_SHARE_DENY_WRITE: *sharing = FILE_SHARE_READ; break;
173     case OF_SHARE_DENY_READ:  *sharing = FILE_SHARE_WRITE; break;
174     case OF_SHARE_DENY_NONE:
175     case OF_SHARE_COMPAT:
176     default:                  *sharing = FILE_SHARE_READ | FILE_SHARE_WRITE; break;
177     }
178 }
179
180
181 /***********************************************************************
182  *              FILE_strcasecmp
183  *
184  * locale-independent case conversion for file I/O
185  */
186 int FILE_strcasecmp( const char *str1, const char *str2 )
187 {
188     for (;;)
189     {
190         int ret = FILE_toupper(*str1) - FILE_toupper(*str2);
191         if (ret || !*str1) return ret;
192         str1++;
193         str2++;
194     }
195 }
196
197
198 /***********************************************************************
199  *              FILE_strncasecmp
200  *
201  * locale-independent case conversion for file I/O
202  */
203 int FILE_strncasecmp( const char *str1, const char *str2, int len )
204 {
205     int ret = 0;
206     for ( ; len > 0; len--, str1++, str2++)
207         if ((ret = FILE_toupper(*str1) - FILE_toupper(*str2)) || !*str1) break;
208     return ret;
209 }
210
211
212 /***********************************************************************
213  *           FILE_GetNtStatus(void)
214  *
215  * Retrieve the Nt Status code from errno.
216  * Try to be consistent with FILE_SetDosError().
217  */
218 DWORD FILE_GetNtStatus(void)
219 {
220     int err = errno;
221     DWORD nt;
222     TRACE ( "errno = %d\n", errno );
223     switch ( err )
224     {
225     case EAGAIN:       nt = STATUS_SHARING_VIOLATION;       break;
226     case EBADF:        nt = STATUS_INVALID_HANDLE;          break;
227     case ENOSPC:       nt = STATUS_DISK_FULL;               break;
228     case EPERM:
229     case EROFS:
230     case EACCES:       nt = STATUS_ACCESS_DENIED;           break;
231     case ENOENT:       nt = STATUS_SHARING_VIOLATION;       break;
232     case EISDIR:       nt = STATUS_FILE_IS_A_DIRECTORY;     break;
233     case EMFILE:
234     case ENFILE:       nt = STATUS_NO_MORE_FILES;           break;
235     case EINVAL:
236     case ENOTEMPTY:    nt = STATUS_DIRECTORY_NOT_EMPTY;     break;
237     case EPIPE:        nt = STATUS_PIPE_BROKEN;             break;
238     case ENOEXEC:      /* ?? */
239     case ESPIPE:       /* ?? */
240     case EEXIST:       /* ?? */
241     default:
242         FIXME ( "Converting errno %d to STATUS_UNSUCCESSFUL\n", err );
243         nt = STATUS_UNSUCCESSFUL;
244     }
245     return nt;
246 }
247
248 /***********************************************************************
249  *           FILE_SetDosError
250  *
251  * Set the DOS error code from errno.
252  */
253 void FILE_SetDosError(void)
254 {
255     int save_errno = errno; /* errno gets overwritten by printf */
256
257     TRACE("errno = %d %s\n", errno, strerror(errno));
258     switch (save_errno)
259     {
260     case EAGAIN:
261         SetLastError( ERROR_SHARING_VIOLATION );
262         break;
263     case EBADF:
264         SetLastError( ERROR_INVALID_HANDLE );
265         break;
266     case ENOSPC:
267         SetLastError( ERROR_HANDLE_DISK_FULL );
268         break;
269     case EACCES:
270     case EPERM:
271     case EROFS:
272         SetLastError( ERROR_ACCESS_DENIED );
273         break;
274     case EBUSY:
275         SetLastError( ERROR_LOCK_VIOLATION );
276         break;
277     case ENOENT:
278         SetLastError( ERROR_FILE_NOT_FOUND );
279         break;
280     case EISDIR:
281         SetLastError( ERROR_CANNOT_MAKE );
282         break;
283     case ENFILE:
284     case EMFILE:
285         SetLastError( ERROR_NO_MORE_FILES );
286         break;
287     case EEXIST:
288         SetLastError( ERROR_FILE_EXISTS );
289         break;
290     case EINVAL:
291     case ESPIPE:
292         SetLastError( ERROR_SEEK );
293         break;
294     case ENOTEMPTY:
295         SetLastError( ERROR_DIR_NOT_EMPTY );
296         break;
297     case ENOEXEC:
298         SetLastError( ERROR_BAD_FORMAT );
299         break;
300     default:
301         WARN("unknown file error: %s\n", strerror(save_errno) );
302         SetLastError( ERROR_GEN_FAILURE );
303         break;
304     }
305     errno = save_errno;
306 }
307
308
309 /***********************************************************************
310  *           FILE_GetUnixHandleType
311  *
312  * Retrieve the Unix handle corresponding to a file handle.
313  * Returns -1 on failure.
314  */
315 static int FILE_GetUnixHandleType( HANDLE handle, DWORD access, enum fd_type *type, int *flags_ptr )
316 {
317     int ret, flags, fd = -1;
318
319     ret = wine_server_handle_to_fd( handle, access, &fd, type, &flags );
320     if (flags_ptr) *flags_ptr = flags;
321     if (ret) SetLastError( RtlNtStatusToDosError(ret) );
322     else if (((access & GENERIC_READ)  && (flags & FD_FLAG_RECV_SHUTDOWN)) ||
323              ((access & GENERIC_WRITE) && (flags & FD_FLAG_SEND_SHUTDOWN)))
324     {
325         close (fd);
326         SetLastError ( ERROR_PIPE_NOT_CONNECTED );
327         return -1;
328     }
329     return fd;
330 }
331
332 /***********************************************************************
333  *           FILE_GetUnixHandle
334  *
335  * Retrieve the Unix handle corresponding to a file handle.
336  * Returns -1 on failure.
337  */
338 int FILE_GetUnixHandle( HANDLE handle, DWORD access )
339 {
340     return FILE_GetUnixHandleType( handle, access, NULL, NULL );
341 }
342
343 /*************************************************************************
344  *              FILE_OpenConsole
345  *
346  * Open a handle to the current process console.
347  * Returns 0 on failure.
348  */
349 static HANDLE FILE_OpenConsole( BOOL output, DWORD access, DWORD sharing, LPSECURITY_ATTRIBUTES sa )
350 {
351     HANDLE ret;
352
353     SERVER_START_REQ( open_console )
354     {
355         req->from    = output;
356         req->access  = access;
357         req->share   = sharing;
358         req->inherit = (sa && (sa->nLength>=sizeof(*sa)) && sa->bInheritHandle);
359         SetLastError(0);
360         wine_server_call_err( req );
361         ret = reply->handle;
362     }
363     SERVER_END_REQ;
364     return ret;
365 }
366
367
368 /***********************************************************************
369  *           FILE_CreateFile
370  *
371  * Implementation of CreateFile. Takes a Unix path name.
372  * Returns 0 on failure.
373  */
374 HANDLE FILE_CreateFile( LPCSTR filename, DWORD access, DWORD sharing,
375                         LPSECURITY_ATTRIBUTES sa, DWORD creation,
376                         DWORD attributes, HANDLE template, BOOL fail_read_only,
377                         UINT drive_type )
378 {
379     unsigned int err;
380     HANDLE ret;
381
382     for (;;)
383     {
384         SERVER_START_REQ( create_file )
385         {
386             req->access     = access;
387             req->inherit    = (sa && (sa->nLength>=sizeof(*sa)) && sa->bInheritHandle);
388             req->sharing    = sharing;
389             req->create     = creation;
390             req->attrs      = attributes;
391             req->drive_type = drive_type;
392             wine_server_add_data( req, filename, strlen(filename) );
393             SetLastError(0);
394             err = wine_server_call( req );
395             ret = reply->handle;
396         }
397         SERVER_END_REQ;
398
399         /* If write access failed, retry without GENERIC_WRITE */
400
401         if (!ret && !fail_read_only && (access & GENERIC_WRITE))
402         {
403             if ((err == STATUS_MEDIA_WRITE_PROTECTED) || (err == STATUS_ACCESS_DENIED))
404             {
405                 TRACE("Write access failed for file '%s', trying without "
406                       "write access\n", filename);
407                 access &= ~GENERIC_WRITE;
408                 continue;
409             }
410         }
411
412         if (err) SetLastError( RtlNtStatusToDosError(err) );
413
414         if (!ret) WARN("Unable to create file '%s' (GLE %ld)\n", filename, GetLastError());
415         return ret;
416     }
417 }
418
419
420 /***********************************************************************
421  *           FILE_CreateDevice
422  *
423  * Same as FILE_CreateFile but for a device
424  * Returns 0 on failure.
425  */
426 HANDLE FILE_CreateDevice( int client_id, DWORD access, LPSECURITY_ATTRIBUTES sa )
427 {
428     HANDLE ret;
429     SERVER_START_REQ( create_device )
430     {
431         req->access  = access;
432         req->inherit = (sa && (sa->nLength>=sizeof(*sa)) && sa->bInheritHandle);
433         req->id      = client_id;
434         SetLastError(0);
435         wine_server_call_err( req );
436         ret = reply->handle;
437     }
438     SERVER_END_REQ;
439     return ret;
440 }
441
442 static HANDLE FILE_OpenPipe(LPCSTR name, DWORD access)
443 {
444     WCHAR buffer[MAX_PATH];
445     HANDLE ret;
446     DWORD len = 0;
447
448     if (name && !(len = MultiByteToWideChar( CP_ACP, 0, name, strlen(name), buffer, MAX_PATH )))
449     {
450         SetLastError( ERROR_FILENAME_EXCED_RANGE );
451         return 0;
452     }
453     SERVER_START_REQ( open_named_pipe )
454     {
455         req->access = access;
456         SetLastError(0);
457         wine_server_add_data( req, buffer, len * sizeof(WCHAR) );
458         wine_server_call_err( req );
459         ret = reply->handle;
460     }
461     SERVER_END_REQ;
462     TRACE("Returned %d\n",ret);
463     return ret;
464 }
465
466 /*************************************************************************
467  * CreateFileA [KERNEL32.@]  Creates or opens a file or other object
468  *
469  * Creates or opens an object, and returns a handle that can be used to
470  * access that object.
471  *
472  * PARAMS
473  *
474  * filename     [in] pointer to filename to be accessed
475  * access       [in] access mode requested
476  * sharing      [in] share mode
477  * sa           [in] pointer to security attributes
478  * creation     [in] how to create the file
479  * attributes   [in] attributes for newly created file
480  * template     [in] handle to file with extended attributes to copy
481  *
482  * RETURNS
483  *   Success: Open handle to specified file
484  *   Failure: INVALID_HANDLE_VALUE
485  *
486  * NOTES
487  *  Should call SetLastError() on failure.
488  *
489  * BUGS
490  *
491  * Doesn't support character devices, template files, or a
492  * lot of the 'attributes' flags yet.
493  */
494 HANDLE WINAPI CreateFileA( LPCSTR filename, DWORD access, DWORD sharing,
495                               LPSECURITY_ATTRIBUTES sa, DWORD creation,
496                               DWORD attributes, HANDLE template )
497 {
498     DOS_FULL_NAME full_name;
499     HANDLE ret;
500
501     if (!filename)
502     {
503         SetLastError( ERROR_INVALID_PARAMETER );
504         return INVALID_HANDLE_VALUE;
505     }
506     TRACE("%s %s%s%s%s%s%s%s\n",filename,
507           ((access & GENERIC_READ)==GENERIC_READ)?"GENERIC_READ ":"",
508           ((access & GENERIC_WRITE)==GENERIC_WRITE)?"GENERIC_WRITE ":"",
509           (!access)?"QUERY_ACCESS ":"",
510           ((sharing & FILE_SHARE_READ)==FILE_SHARE_READ)?"FILE_SHARE_READ ":"",
511           ((sharing & FILE_SHARE_WRITE)==FILE_SHARE_WRITE)?"FILE_SHARE_WRITE ":"",
512           ((sharing & FILE_SHARE_DELETE)==FILE_SHARE_DELETE)?"FILE_SHARE_DELETE ":"",
513           (creation ==CREATE_NEW)?"CREATE_NEW":
514           (creation ==CREATE_ALWAYS)?"CREATE_ALWAYS ":
515           (creation ==OPEN_EXISTING)?"OPEN_EXISTING ":
516           (creation ==OPEN_ALWAYS)?"OPEN_ALWAYS ":
517           (creation ==TRUNCATE_EXISTING)?"TRUNCATE_EXISTING ":"");
518
519     /* If the name starts with '\\?\', ignore the first 4 chars. */
520     if (!strncmp(filename, "\\\\?\\", 4))
521     {
522         filename += 4;
523         if (!strncmp(filename, "UNC\\", 4))
524         {
525             FIXME("UNC name (%s) not supported.\n", filename );
526             SetLastError( ERROR_PATH_NOT_FOUND );
527             return INVALID_HANDLE_VALUE;
528         }
529     }
530
531     if (!strncmp(filename, "\\\\.\\", 4)) {
532         if(!strncasecmp(&filename[4],"pipe\\",5))
533         {
534             TRACE("Opening a pipe: %s\n",filename);
535             ret = FILE_OpenPipe(filename,access);
536             goto done;
537         }
538         else if (isalpha(filename[4]) && filename[5] == ':' && filename[6] == '\0')
539         {
540             ret = FILE_CreateDevice( (toupper(filename[4]) - 'A') | 0x20000, access, sa );
541             goto done;
542         }
543         else if (!DOSFS_GetDevice( filename ))
544         {
545             ret = DEVICE_Open( filename+4, access, sa );
546             goto done;
547         }
548         else
549                 filename+=4; /* fall into DOSFS_Device case below */
550     }
551
552     /* If the name still starts with '\\', it's a UNC name. */
553     if (!strncmp(filename, "\\\\", 2))
554     {
555         ret = SMB_CreateFileA(filename, access, sharing, sa, creation, attributes, template );
556         goto done;
557     }
558
559     /* If the name contains a DOS wild card (* or ?), do no create a file */
560     if(strchr(filename,'*') || strchr(filename,'?'))
561         return INVALID_HANDLE_VALUE;
562
563     /* Open a console for CONIN$ or CONOUT$ */
564     if (!strcasecmp(filename, "CONIN$"))
565     {
566         ret = FILE_OpenConsole( FALSE, access, sharing, sa );
567         goto done;
568     }
569     if (!strcasecmp(filename, "CONOUT$"))
570     {
571         ret = FILE_OpenConsole( TRUE, access, sharing, sa );
572         goto done;
573     }
574
575     if (DOSFS_GetDevice( filename ))
576     {
577         TRACE("opening device '%s'\n", filename );
578
579         if (!(ret = DOSFS_OpenDevice( filename, access, attributes, sa )))
580         {
581             /* Do not silence this please. It is a critical error. -MM */
582             ERR("Couldn't open device '%s'!\n",filename);
583             SetLastError( ERROR_FILE_NOT_FOUND );
584         }
585         goto done;
586     }
587
588     /* check for filename, don't check for last entry if creating */
589     if (!DOSFS_GetFullName( filename,
590                             (creation == OPEN_EXISTING) ||
591                             (creation == TRUNCATE_EXISTING),
592                             &full_name )) {
593         WARN("Unable to get full filename from '%s' (GLE %ld)\n",
594              filename, GetLastError());
595         return INVALID_HANDLE_VALUE;
596     }
597
598     ret = FILE_CreateFile( full_name.long_name, access, sharing,
599                            sa, creation, attributes, template,
600                            DRIVE_GetFlags(full_name.drive) & DRIVE_FAIL_READ_ONLY,
601                            GetDriveTypeA( full_name.short_name ) );
602  done:
603     if (!ret) ret = INVALID_HANDLE_VALUE;
604     return ret;
605 }
606
607
608
609 /*************************************************************************
610  *              CreateFileW              (KERNEL32.@)
611  */
612 HANDLE WINAPI CreateFileW( LPCWSTR filename, DWORD access, DWORD sharing,
613                               LPSECURITY_ATTRIBUTES sa, DWORD creation,
614                               DWORD attributes, HANDLE template)
615 {
616     LPSTR afn = HEAP_strdupWtoA( GetProcessHeap(), 0, filename );
617     HANDLE res = CreateFileA( afn, access, sharing, sa, creation, attributes, template );
618     HeapFree( GetProcessHeap(), 0, afn );
619     return res;
620 }
621
622
623 /***********************************************************************
624  *           FILE_FillInfo
625  *
626  * Fill a file information from a struct stat.
627  */
628 static void FILE_FillInfo( struct stat *st, BY_HANDLE_FILE_INFORMATION *info )
629 {
630     if (S_ISDIR(st->st_mode))
631         info->dwFileAttributes = FILE_ATTRIBUTE_DIRECTORY;
632     else
633         info->dwFileAttributes = FILE_ATTRIBUTE_ARCHIVE;
634     if (!(st->st_mode & S_IWUSR))
635         info->dwFileAttributes |= FILE_ATTRIBUTE_READONLY;
636
637     RtlSecondsSince1970ToTime( st->st_mtime, &info->ftCreationTime );
638     RtlSecondsSince1970ToTime( st->st_mtime, &info->ftLastWriteTime );
639     RtlSecondsSince1970ToTime( st->st_atime, &info->ftLastAccessTime );
640
641     info->dwVolumeSerialNumber = 0;  /* FIXME */
642     info->nFileSizeHigh = 0;
643     info->nFileSizeLow  = 0;
644     if (!S_ISDIR(st->st_mode)) {
645         info->nFileSizeHigh = st->st_size >> 32;
646         info->nFileSizeLow  = st->st_size & 0xffffffff;
647     }
648     info->nNumberOfLinks = st->st_nlink;
649     info->nFileIndexHigh = 0;
650     info->nFileIndexLow  = st->st_ino;
651 }
652
653
654 /***********************************************************************
655  *           FILE_Stat
656  *
657  * Stat a Unix path name. Return TRUE if OK.
658  */
659 BOOL FILE_Stat( LPCSTR unixName, BY_HANDLE_FILE_INFORMATION *info )
660 {
661     struct stat st;
662
663     if (lstat( unixName, &st ) == -1)
664     {
665         FILE_SetDosError();
666         return FALSE;
667     }
668     if (!S_ISLNK(st.st_mode)) FILE_FillInfo( &st, info );
669     else
670     {
671         /* do a "real" stat to find out
672            about the type of the symlink destination */
673         if (stat( unixName, &st ) == -1)
674         {
675             FILE_SetDosError();
676             return FALSE;
677         }
678         FILE_FillInfo( &st, info );
679         info->dwFileAttributes |= FILE_ATTRIBUTE_SYMLINK;
680     }
681     return TRUE;
682 }
683
684
685 /***********************************************************************
686  *             GetFileInformationByHandle   (KERNEL32.@)
687  */
688 DWORD WINAPI GetFileInformationByHandle( HANDLE hFile,
689                                          BY_HANDLE_FILE_INFORMATION *info )
690 {
691     DWORD ret;
692     if (!info) return 0;
693
694     SERVER_START_REQ( get_file_info )
695     {
696         req->handle = hFile;
697         if ((ret = !wine_server_call_err( req )))
698         {
699             /* FIXME: which file types are supported ?
700              * Serial ports (FILE_TYPE_CHAR) are not,
701              * and MSDN also says that pipes are not supported.
702              * FILE_TYPE_REMOTE seems to be supported according to
703              * MSDN q234741.txt */
704             if ((reply->type == FILE_TYPE_DISK) ||  (reply->type == FILE_TYPE_REMOTE))
705             {
706                 RtlSecondsSince1970ToTime( reply->write_time, &info->ftCreationTime );
707                 RtlSecondsSince1970ToTime( reply->write_time, &info->ftLastWriteTime );
708                 RtlSecondsSince1970ToTime( reply->access_time, &info->ftLastAccessTime );
709                 info->dwFileAttributes     = reply->attr;
710                 info->dwVolumeSerialNumber = reply->serial;
711                 info->nFileSizeHigh        = reply->size_high;
712                 info->nFileSizeLow         = reply->size_low;
713                 info->nNumberOfLinks       = reply->links;
714                 info->nFileIndexHigh       = reply->index_high;
715                 info->nFileIndexLow        = reply->index_low;
716             }
717             else
718             {
719                 SetLastError(ERROR_NOT_SUPPORTED);
720                 ret = 0;
721             }
722         }
723     }
724     SERVER_END_REQ;
725     return ret;
726 }
727
728
729 /**************************************************************************
730  *           GetFileAttributes   (KERNEL.420)
731  */
732 DWORD WINAPI GetFileAttributes16( LPCSTR name )
733 {
734     return GetFileAttributesA( name );
735 }
736
737
738 /**************************************************************************
739  *           GetFileAttributesA   (KERNEL32.@)
740  */
741 DWORD WINAPI GetFileAttributesA( LPCSTR name )
742 {
743     DOS_FULL_NAME full_name;
744     BY_HANDLE_FILE_INFORMATION info;
745
746     if (name == NULL)
747     {
748         SetLastError( ERROR_INVALID_PARAMETER );
749         return -1;
750     }
751     if (!DOSFS_GetFullName( name, TRUE, &full_name) )
752         return -1;
753     if (!FILE_Stat( full_name.long_name, &info )) return -1;
754     return info.dwFileAttributes;
755 }
756
757
758 /**************************************************************************
759  *           GetFileAttributesW   (KERNEL32.@)
760  */
761 DWORD WINAPI GetFileAttributesW( LPCWSTR name )
762 {
763     LPSTR nameA = HEAP_strdupWtoA( GetProcessHeap(), 0, name );
764     DWORD res = GetFileAttributesA( nameA );
765     HeapFree( GetProcessHeap(), 0, nameA );
766     return res;
767 }
768
769
770 /**************************************************************************
771  *              SetFileAttributes       (KERNEL.421)
772  */
773 BOOL16 WINAPI SetFileAttributes16( LPCSTR lpFileName, DWORD attributes )
774 {
775     return SetFileAttributesA( lpFileName, attributes );
776 }
777
778
779 /**************************************************************************
780  *              SetFileAttributesA      (KERNEL32.@)
781  */
782 BOOL WINAPI SetFileAttributesA(LPCSTR lpFileName, DWORD attributes)
783 {
784     struct stat buf;
785     DOS_FULL_NAME full_name;
786
787     if (!DOSFS_GetFullName( lpFileName, TRUE, &full_name ))
788         return FALSE;
789
790     TRACE("(%s,%lx)\n",lpFileName,attributes);
791     if(stat(full_name.long_name,&buf)==-1)
792     {
793         FILE_SetDosError();
794         return FALSE;
795     }
796     if (attributes & FILE_ATTRIBUTE_READONLY)
797     {
798         if(S_ISDIR(buf.st_mode))
799             /* FIXME */
800             WARN("FILE_ATTRIBUTE_READONLY ignored for directory.\n");
801         else
802             buf.st_mode &= ~0222; /* octal!, clear write permission bits */
803         attributes &= ~FILE_ATTRIBUTE_READONLY;
804     }
805     else
806     {
807         /* add write permission */
808         buf.st_mode |= (0600 | ((buf.st_mode & 044) >> 1)) & (~FILE_umask);
809     }
810     if (attributes & FILE_ATTRIBUTE_DIRECTORY)
811     {
812         if (!S_ISDIR(buf.st_mode))
813             FIXME("SetFileAttributes expected the file '%s' to be a directory\n",
814                   lpFileName);
815         attributes &= ~FILE_ATTRIBUTE_DIRECTORY;
816     }
817     attributes &= ~(FILE_ATTRIBUTE_NORMAL|FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_HIDDEN|FILE_ATTRIBUTE_SYSTEM);
818     if (attributes)
819         FIXME("(%s):%lx attribute(s) not implemented.\n", lpFileName,attributes);
820     if (-1==chmod(full_name.long_name,buf.st_mode))
821     {
822         if(GetDriveTypeA(lpFileName) == DRIVE_CDROM) {
823            SetLastError( ERROR_ACCESS_DENIED );
824            return FALSE;
825         }
826
827         /*
828         * FIXME: We don't return FALSE here because of differences between
829         *        Linux and Windows privileges. Under Linux only the owner of
830         *        the file is allowed to change file attributes. Under Windows,
831         *        applications expect that if you can write to a file, you can also
832         *        change its attributes (see GENERIC_WRITE). We could try to be
833         *        clever here but that would break multi-user installations where
834         *        users share read-only DLLs. This is because some installers like
835         *        to change attributes of already installed DLLs.
836         */
837         FIXME("Couldn't set file attributes for existing file \"%s\".\n"
838               "Check permissions or set VFAT \"quiet\" mount flag\n", full_name.long_name);
839     }
840     return TRUE;
841 }
842
843
844 /**************************************************************************
845  *              SetFileAttributesW      (KERNEL32.@)
846  */
847 BOOL WINAPI SetFileAttributesW(LPCWSTR lpFileName, DWORD attributes)
848 {
849     BOOL res;
850     DWORD len = WideCharToMultiByte( CP_ACP, 0, lpFileName, -1, NULL, 0, NULL, NULL );
851     LPSTR afn = HeapAlloc( GetProcessHeap(), 0, len );
852
853     WideCharToMultiByte( CP_ACP, 0, lpFileName, -1, afn, len, NULL, NULL );
854     res = SetFileAttributesA( afn, attributes );
855     HeapFree( GetProcessHeap(), 0, afn );
856     return res;
857 }
858
859
860 /***********************************************************************
861  *           GetFileSize   (KERNEL32.@)
862  */
863 DWORD WINAPI GetFileSize( HANDLE hFile, LPDWORD filesizehigh )
864 {
865     BY_HANDLE_FILE_INFORMATION info;
866     if (!GetFileInformationByHandle( hFile, &info )) return -1;
867     if (filesizehigh) *filesizehigh = info.nFileSizeHigh;
868     return info.nFileSizeLow;
869 }
870
871
872 /***********************************************************************
873  *           GetFileTime   (KERNEL32.@)
874  */
875 BOOL WINAPI GetFileTime( HANDLE hFile, FILETIME *lpCreationTime,
876                            FILETIME *lpLastAccessTime,
877                            FILETIME *lpLastWriteTime )
878 {
879     BY_HANDLE_FILE_INFORMATION info;
880     if (!GetFileInformationByHandle( hFile, &info )) return FALSE;
881     if (lpCreationTime)   *lpCreationTime   = info.ftCreationTime;
882     if (lpLastAccessTime) *lpLastAccessTime = info.ftLastAccessTime;
883     if (lpLastWriteTime)  *lpLastWriteTime  = info.ftLastWriteTime;
884     return TRUE;
885 }
886
887 /***********************************************************************
888  *           CompareFileTime   (KERNEL32.@)
889  */
890 INT WINAPI CompareFileTime( LPFILETIME x, LPFILETIME y )
891 {
892         if (!x || !y) return -1;
893
894         if (x->dwHighDateTime > y->dwHighDateTime)
895                 return 1;
896         if (x->dwHighDateTime < y->dwHighDateTime)
897                 return -1;
898         if (x->dwLowDateTime > y->dwLowDateTime)
899                 return 1;
900         if (x->dwLowDateTime < y->dwLowDateTime)
901                 return -1;
902         return 0;
903 }
904
905 /***********************************************************************
906  *           FILE_GetTempFileName : utility for GetTempFileName
907  */
908 static UINT FILE_GetTempFileName( LPCSTR path, LPCSTR prefix, UINT unique,
909                                   LPSTR buffer, BOOL isWin16 )
910 {
911     static UINT unique_temp;
912     DOS_FULL_NAME full_name;
913     int i;
914     LPSTR p;
915     UINT num;
916
917     if ( !path || !prefix || !buffer ) return 0;
918
919     if (!unique_temp) unique_temp = time(NULL) & 0xffff;
920     num = unique ? (unique & 0xffff) : (unique_temp++ & 0xffff);
921
922     strcpy( buffer, path );
923     p = buffer + strlen(buffer);
924
925     /* add a \, if there isn't one and path is more than just the drive letter ... */
926     if ( !((strlen(buffer) == 2) && (buffer[1] == ':'))
927         && ((p == buffer) || (p[-1] != '\\'))) *p++ = '\\';
928
929     if (isWin16) *p++ = '~';
930     for (i = 3; (i > 0) && (*prefix); i--) *p++ = *prefix++;
931     sprintf( p, "%04x.tmp", num );
932
933     /* Now try to create it */
934
935     if (!unique)
936     {
937         do
938         {
939             HFILE handle = CreateFileA( buffer, GENERIC_WRITE, 0, NULL,
940                                             CREATE_NEW, FILE_ATTRIBUTE_NORMAL, 0 );
941             if (handle != INVALID_HANDLE_VALUE)
942             {  /* We created it */
943                 TRACE("created %s\n",
944                               buffer);
945                 CloseHandle( handle );
946                 break;
947             }
948             if (GetLastError() != ERROR_FILE_EXISTS)
949                 break;  /* No need to go on */
950             num++;
951             sprintf( p, "%04x.tmp", num );
952         } while (num != (unique & 0xffff));
953     }
954
955     /* Get the full path name */
956
957     if (DOSFS_GetFullName( buffer, FALSE, &full_name ))
958     {
959         /* Check if we have write access in the directory */
960         if ((p = strrchr( full_name.long_name, '/' ))) *p = '\0';
961         if (access( full_name.long_name, W_OK ) == -1)
962             WARN("returns '%s', which doesn't seem to be writeable.\n",
963                  buffer);
964     }
965     TRACE("returning %s\n", buffer );
966     return unique ? unique : num;
967 }
968
969
970 /***********************************************************************
971  *           GetTempFileNameA   (KERNEL32.@)
972  */
973 UINT WINAPI GetTempFileNameA( LPCSTR path, LPCSTR prefix, UINT unique,
974                                   LPSTR buffer)
975 {
976     return FILE_GetTempFileName(path, prefix, unique, buffer, FALSE);
977 }
978
979 /***********************************************************************
980  *           GetTempFileNameW   (KERNEL32.@)
981  */
982 UINT WINAPI GetTempFileNameW( LPCWSTR path, LPCWSTR prefix, UINT unique,
983                                   LPWSTR buffer )
984 {
985     LPSTR   patha,prefixa;
986     char    buffera[144];
987     UINT  ret;
988
989     if (!path) return 0;
990     patha   = HEAP_strdupWtoA( GetProcessHeap(), 0, path );
991     prefixa = HEAP_strdupWtoA( GetProcessHeap(), 0, prefix );
992     ret     = FILE_GetTempFileName( patha, prefixa, unique, buffera, FALSE );
993     MultiByteToWideChar( CP_ACP, 0, buffera, -1, buffer, MAX_PATH );
994     HeapFree( GetProcessHeap(), 0, patha );
995     HeapFree( GetProcessHeap(), 0, prefixa );
996     return ret;
997 }
998
999
1000 /***********************************************************************
1001  *           GetTempFileName   (KERNEL.97)
1002  */
1003 UINT16 WINAPI GetTempFileName16( BYTE drive, LPCSTR prefix, UINT16 unique,
1004                                  LPSTR buffer )
1005 {
1006     char temppath[144];
1007
1008     if (!(drive & ~TF_FORCEDRIVE)) /* drive 0 means current default drive */
1009         drive |= DRIVE_GetCurrentDrive() + 'A';
1010
1011     if ((drive & TF_FORCEDRIVE) &&
1012         !DRIVE_IsValid( toupper(drive & ~TF_FORCEDRIVE) - 'A' ))
1013     {
1014         drive &= ~TF_FORCEDRIVE;
1015         WARN("invalid drive %d specified\n", drive );
1016     }
1017
1018     if (drive & TF_FORCEDRIVE)
1019         sprintf(temppath,"%c:", drive & ~TF_FORCEDRIVE );
1020     else
1021         GetTempPathA( 132, temppath );
1022     return (UINT16)FILE_GetTempFileName( temppath, prefix, unique, buffer, TRUE );
1023 }
1024
1025 /***********************************************************************
1026  *           FILE_DoOpenFile
1027  *
1028  * Implementation of OpenFile16() and OpenFile32().
1029  */
1030 static HFILE FILE_DoOpenFile( LPCSTR name, OFSTRUCT *ofs, UINT mode,
1031                                 BOOL win32 )
1032 {
1033     HFILE hFileRet;
1034     FILETIME filetime;
1035     WORD filedatetime[2];
1036     DOS_FULL_NAME full_name;
1037     DWORD access, sharing;
1038     char *p;
1039
1040     if (!ofs) return HFILE_ERROR;
1041
1042     TRACE("%s %s %s %s%s%s%s%s%s%s%s%s\n",name,
1043           ((mode & 0x3 )==OF_READ)?"OF_READ":
1044           ((mode & 0x3 )==OF_WRITE)?"OF_WRITE":
1045           ((mode & 0x3 )==OF_READWRITE)?"OF_READWRITE":"unknown",
1046           ((mode & 0x70 )==OF_SHARE_COMPAT)?"OF_SHARE_COMPAT":
1047           ((mode & 0x70 )==OF_SHARE_DENY_NONE)?"OF_SHARE_DENY_NONE":
1048           ((mode & 0x70 )==OF_SHARE_DENY_READ)?"OF_SHARE_DENY_READ":
1049           ((mode & 0x70 )==OF_SHARE_DENY_WRITE)?"OF_SHARE_DENY_WRITE":
1050           ((mode & 0x70 )==OF_SHARE_EXCLUSIVE)?"OF_SHARE_EXCLUSIVE":"unknown",
1051           ((mode & OF_PARSE )==OF_PARSE)?"OF_PARSE ":"",
1052           ((mode & OF_DELETE )==OF_DELETE)?"OF_DELETE ":"",
1053           ((mode & OF_VERIFY )==OF_VERIFY)?"OF_VERIFY ":"",
1054           ((mode & OF_SEARCH )==OF_SEARCH)?"OF_SEARCH ":"",
1055           ((mode & OF_CANCEL )==OF_CANCEL)?"OF_CANCEL ":"",
1056           ((mode & OF_CREATE )==OF_CREATE)?"OF_CREATE ":"",
1057           ((mode & OF_PROMPT )==OF_PROMPT)?"OF_PROMPT ":"",
1058           ((mode & OF_EXIST )==OF_EXIST)?"OF_EXIST ":"",
1059           ((mode & OF_REOPEN )==OF_REOPEN)?"OF_REOPEN ":""
1060           );
1061
1062
1063     ofs->cBytes = sizeof(OFSTRUCT);
1064     ofs->nErrCode = 0;
1065     if (mode & OF_REOPEN) name = ofs->szPathName;
1066
1067     if (!name) {
1068         ERR("called with `name' set to NULL ! Please debug.\n");
1069         return HFILE_ERROR;
1070     }
1071
1072     TRACE("%s %04x\n", name, mode );
1073
1074     /* the watcom 10.6 IDE relies on a valid path returned in ofs->szPathName
1075        Are there any cases where getting the path here is wrong?
1076        Uwe Bonnes 1997 Apr 2 */
1077     if (!GetFullPathNameA( name, sizeof(ofs->szPathName),
1078                              ofs->szPathName, NULL )) goto error;
1079     FILE_ConvertOFMode( mode, &access, &sharing );
1080
1081     /* OF_PARSE simply fills the structure */
1082
1083     if (mode & OF_PARSE)
1084     {
1085         ofs->fFixedDisk = (GetDriveType16( ofs->szPathName[0]-'A' )
1086                            != DRIVE_REMOVABLE);
1087         TRACE("(%s): OF_PARSE, res = '%s'\n",
1088                       name, ofs->szPathName );
1089         return 0;
1090     }
1091
1092     /* OF_CREATE is completely different from all other options, so
1093        handle it first */
1094
1095     if (mode & OF_CREATE)
1096     {
1097         if ((hFileRet = CreateFileA( name, GENERIC_READ | GENERIC_WRITE,
1098                                        sharing, NULL, CREATE_ALWAYS,
1099                                        FILE_ATTRIBUTE_NORMAL, 0 ))== INVALID_HANDLE_VALUE)
1100             goto error;
1101         goto success;
1102     }
1103
1104     /* If OF_SEARCH is set, ignore the given path */
1105
1106     if ((mode & OF_SEARCH) && !(mode & OF_REOPEN))
1107     {
1108         /* First try the file name as is */
1109         if (DOSFS_GetFullName( name, TRUE, &full_name )) goto found;
1110         /* Now remove the path */
1111         if (name[0] && (name[1] == ':')) name += 2;
1112         if ((p = strrchr( name, '\\' ))) name = p + 1;
1113         if ((p = strrchr( name, '/' ))) name = p + 1;
1114         if (!name[0]) goto not_found;
1115     }
1116
1117     /* Now look for the file */
1118
1119     if (!DIR_SearchPath( NULL, name, NULL, &full_name, win32 )) goto not_found;
1120
1121 found:
1122     TRACE("found %s = %s\n",
1123                   full_name.long_name, full_name.short_name );
1124     lstrcpynA( ofs->szPathName, full_name.short_name,
1125                  sizeof(ofs->szPathName) );
1126
1127     if (mode & OF_SHARE_EXCLUSIVE)
1128       /* Some InstallShield version uses OF_SHARE_EXCLUSIVE
1129          on the file <tempdir>/_ins0432._mp to determine how
1130          far installation has proceeded.
1131          _ins0432._mp is an executable and while running the
1132          application expects the open with OF_SHARE_ to fail*/
1133       /* Probable FIXME:
1134          As our loader closes the files after loading the executable,
1135          we can't find the running executable with FILE_InUse.
1136          The loader should keep the file open, as Windows does that, too.
1137        */
1138       {
1139         char *last = strrchr(full_name.long_name,'/');
1140         if (!last)
1141           last = full_name.long_name - 1;
1142         if (GetModuleHandle16(last+1))
1143           {
1144             TRACE("Denying shared open for %s\n",full_name.long_name);
1145             return HFILE_ERROR;
1146           }
1147       }
1148
1149     if (mode & OF_DELETE)
1150     {
1151         if (unlink( full_name.long_name ) == -1) goto not_found;
1152         TRACE("(%s): OF_DELETE return = OK\n", name);
1153         return 1;
1154     }
1155
1156     hFileRet = FILE_CreateFile( full_name.long_name, access, sharing,
1157                                 NULL, OPEN_EXISTING, 0, 0,
1158                                 DRIVE_GetFlags(full_name.drive) & DRIVE_FAIL_READ_ONLY,
1159                                 GetDriveTypeA( full_name.short_name ) );
1160     if (!hFileRet) goto not_found;
1161
1162     GetFileTime( hFileRet, NULL, NULL, &filetime );
1163     FileTimeToDosDateTime( &filetime, &filedatetime[0], &filedatetime[1] );
1164     if ((mode & OF_VERIFY) && (mode & OF_REOPEN))
1165     {
1166         if (memcmp( ofs->reserved, filedatetime, sizeof(ofs->reserved) ))
1167         {
1168             CloseHandle( hFileRet );
1169             WARN("(%s): OF_VERIFY failed\n", name );
1170             /* FIXME: what error here? */
1171             SetLastError( ERROR_FILE_NOT_FOUND );
1172             goto error;
1173         }
1174     }
1175     memcpy( ofs->reserved, filedatetime, sizeof(ofs->reserved) );
1176
1177 success:  /* We get here if the open was successful */
1178     TRACE("(%s): OK, return = %d\n", name, hFileRet );
1179     if (win32)
1180     {
1181         if (mode & OF_EXIST) /* Return the handle, but close it first */
1182             CloseHandle( hFileRet );
1183     }
1184     else
1185     {
1186         hFileRet = Win32HandleToDosFileHandle( hFileRet );
1187         if (hFileRet == HFILE_ERROR16) goto error;
1188         if (mode & OF_EXIST) /* Return the handle, but close it first */
1189             _lclose16( hFileRet );
1190     }
1191     return hFileRet;
1192
1193 not_found:  /* We get here if the file does not exist */
1194     WARN("'%s' not found or sharing violation\n", name );
1195     SetLastError( ERROR_FILE_NOT_FOUND );
1196     /* fall through */
1197
1198 error:  /* We get here if there was an error opening the file */
1199     ofs->nErrCode = GetLastError();
1200     WARN("(%s): return = HFILE_ERROR error= %d\n",
1201                   name,ofs->nErrCode );
1202     return HFILE_ERROR;
1203 }
1204
1205
1206 /***********************************************************************
1207  *           OpenFile   (KERNEL.74)
1208  *           OpenFileEx (KERNEL.360)
1209  */
1210 HFILE16 WINAPI OpenFile16( LPCSTR name, OFSTRUCT *ofs, UINT16 mode )
1211 {
1212     return FILE_DoOpenFile( name, ofs, mode, FALSE );
1213 }
1214
1215
1216 /***********************************************************************
1217  *           OpenFile   (KERNEL32.@)
1218  */
1219 HFILE WINAPI OpenFile( LPCSTR name, OFSTRUCT *ofs, UINT mode )
1220 {
1221     return FILE_DoOpenFile( name, ofs, mode, TRUE );
1222 }
1223
1224
1225 /***********************************************************************
1226  *           FILE_InitProcessDosHandles
1227  *
1228  * Allocates the default DOS handles for a process. Called either by
1229  * Win32HandleToDosFileHandle below or by the DOSVM stuff.
1230  */
1231 static void FILE_InitProcessDosHandles( void )
1232 {
1233     dos_handles[0] = GetStdHandle(STD_INPUT_HANDLE);
1234     dos_handles[1] = GetStdHandle(STD_OUTPUT_HANDLE);
1235     dos_handles[2] = GetStdHandle(STD_ERROR_HANDLE);
1236     dos_handles[3] = GetStdHandle(STD_ERROR_HANDLE);
1237     dos_handles[4] = GetStdHandle(STD_ERROR_HANDLE);
1238 }
1239
1240 /***********************************************************************
1241  *           Win32HandleToDosFileHandle   (KERNEL32.21)
1242  *
1243  * Allocate a DOS handle for a Win32 handle. The Win32 handle is no
1244  * longer valid after this function (even on failure).
1245  *
1246  * Note: this is not exactly right, since on Win95 the Win32 handles
1247  *       are on top of DOS handles and we do it the other way
1248  *       around. Should be good enough though.
1249  */
1250 HFILE WINAPI Win32HandleToDosFileHandle( HANDLE handle )
1251 {
1252     int i;
1253
1254     if (!handle || (handle == INVALID_HANDLE_VALUE))
1255         return HFILE_ERROR;
1256
1257     for (i = 5; i < DOS_TABLE_SIZE; i++)
1258         if (!dos_handles[i])
1259         {
1260             dos_handles[i] = handle;
1261             TRACE("Got %d for h32 %d\n", i, handle );
1262             return (HFILE)i;
1263         }
1264     CloseHandle( handle );
1265     SetLastError( ERROR_TOO_MANY_OPEN_FILES );
1266     return HFILE_ERROR;
1267 }
1268
1269
1270 /***********************************************************************
1271  *           DosFileHandleToWin32Handle   (KERNEL32.20)
1272  *
1273  * Return the Win32 handle for a DOS handle.
1274  *
1275  * Note: this is not exactly right, since on Win95 the Win32 handles
1276  *       are on top of DOS handles and we do it the other way
1277  *       around. Should be good enough though.
1278  */
1279 HANDLE WINAPI DosFileHandleToWin32Handle( HFILE handle )
1280 {
1281     HFILE16 hfile = (HFILE16)handle;
1282     if (hfile < 5 && !dos_handles[hfile]) FILE_InitProcessDosHandles();
1283     if ((hfile >= DOS_TABLE_SIZE) || !dos_handles[hfile])
1284     {
1285         SetLastError( ERROR_INVALID_HANDLE );
1286         return INVALID_HANDLE_VALUE;
1287     }
1288     return dos_handles[hfile];
1289 }
1290
1291
1292 /***********************************************************************
1293  *           DisposeLZ32Handle   (KERNEL32.22)
1294  *
1295  * Note: this is not entirely correct, we should only close the
1296  *       32-bit handle and not the 16-bit one, but we cannot do
1297  *       this because of the way our DOS handles are implemented.
1298  *       It shouldn't break anything though.
1299  */
1300 void WINAPI DisposeLZ32Handle( HANDLE handle )
1301 {
1302     int i;
1303
1304     if (!handle || (handle == INVALID_HANDLE_VALUE)) return;
1305
1306     for (i = 5; i < DOS_TABLE_SIZE; i++)
1307         if (dos_handles[i] == handle)
1308         {
1309             dos_handles[i] = 0;
1310             CloseHandle( handle );
1311             break;
1312         }
1313 }
1314
1315
1316 /***********************************************************************
1317  *           FILE_Dup2
1318  *
1319  * dup2() function for DOS handles.
1320  */
1321 HFILE16 FILE_Dup2( HFILE16 hFile1, HFILE16 hFile2 )
1322 {
1323     HANDLE new_handle;
1324
1325     if (hFile1 < 5 && !dos_handles[hFile1]) FILE_InitProcessDosHandles();
1326
1327     if ((hFile1 >= DOS_TABLE_SIZE) || (hFile2 >= DOS_TABLE_SIZE) || !dos_handles[hFile1])
1328     {
1329         SetLastError( ERROR_INVALID_HANDLE );
1330         return HFILE_ERROR16;
1331     }
1332     if (hFile2 < 5)
1333     {
1334         FIXME("stdio handle closed, need proper conversion\n" );
1335         SetLastError( ERROR_INVALID_HANDLE );
1336         return HFILE_ERROR16;
1337     }
1338     if (!DuplicateHandle( GetCurrentProcess(), dos_handles[hFile1],
1339                           GetCurrentProcess(), &new_handle,
1340                           0, FALSE, DUPLICATE_SAME_ACCESS ))
1341         return HFILE_ERROR16;
1342     if (dos_handles[hFile2]) CloseHandle( dos_handles[hFile2] );
1343     dos_handles[hFile2] = new_handle;
1344     return hFile2;
1345 }
1346
1347
1348 /***********************************************************************
1349  *           _lclose   (KERNEL.81)
1350  */
1351 HFILE16 WINAPI _lclose16( HFILE16 hFile )
1352 {
1353     if (hFile < 5)
1354     {
1355         FIXME("stdio handle closed, need proper conversion\n" );
1356         SetLastError( ERROR_INVALID_HANDLE );
1357         return HFILE_ERROR16;
1358     }
1359     if ((hFile >= DOS_TABLE_SIZE) || !dos_handles[hFile])
1360     {
1361         SetLastError( ERROR_INVALID_HANDLE );
1362         return HFILE_ERROR16;
1363     }
1364     TRACE("%d (handle32=%d)\n", hFile, dos_handles[hFile] );
1365     CloseHandle( dos_handles[hFile] );
1366     dos_handles[hFile] = 0;
1367     return 0;
1368 }
1369
1370
1371 /***********************************************************************
1372  *           _lclose   (KERNEL32.@)
1373  */
1374 HFILE WINAPI _lclose( HFILE hFile )
1375 {
1376     TRACE("handle %d\n", hFile );
1377     return CloseHandle( hFile ) ? 0 : HFILE_ERROR;
1378 }
1379
1380 /***********************************************************************
1381  *              GetOverlappedResult     (KERNEL32.@)
1382  *
1383  * Check the result of an Asynchronous data transfer from a file.
1384  *
1385  * RETURNS
1386  *   TRUE on success
1387  *   FALSE on failure
1388  *
1389  *  If successful (and relevant) lpTransferred will hold the number of
1390  *   bytes transferred during the async operation.
1391  *
1392  * BUGS
1393  *
1394  * Currently only works for WaitCommEvent, ReadFile, WriteFile
1395  *   with communications ports.
1396  *
1397  */
1398 BOOL WINAPI GetOverlappedResult(
1399     HANDLE hFile,              /* [in] handle of file to check on */
1400     LPOVERLAPPED lpOverlapped, /* [in/out] pointer to overlapped  */
1401     LPDWORD lpTransferred,     /* [in/out] number of bytes transferred  */
1402     BOOL bWait                 /* [in] wait for the transfer to complete ? */
1403 ) {
1404     DWORD r;
1405
1406     TRACE("(%d %p %p %x)\n", hFile, lpOverlapped, lpTransferred, bWait);
1407
1408     if(lpOverlapped==NULL)
1409     {
1410         ERR("lpOverlapped was null\n");
1411         return FALSE;
1412     }
1413     if(!lpOverlapped->hEvent)
1414     {
1415         ERR("lpOverlapped->hEvent was null\n");
1416         return FALSE;
1417     }
1418
1419     do {
1420         TRACE("waiting on %p\n",lpOverlapped);
1421         r = WaitForSingleObjectEx(lpOverlapped->hEvent, bWait?INFINITE:0, TRUE);
1422         TRACE("wait on %p returned %ld\n",lpOverlapped,r);
1423     } while (r==STATUS_USER_APC);
1424
1425     if(lpTransferred)
1426         *lpTransferred = lpOverlapped->InternalHigh;
1427
1428     SetLastError ( lpOverlapped->Internal == STATUS_PENDING ?
1429                    ERROR_IO_INCOMPLETE : RtlNtStatusToDosError ( lpOverlapped->Internal ) );
1430
1431     return (r==WAIT_OBJECT_0);
1432 }
1433
1434 /***********************************************************************
1435  *             CancelIo                   (KERNEL32.@)
1436  */
1437 BOOL WINAPI CancelIo(HANDLE handle)
1438 {
1439     async_private *ovp,*t;
1440
1441     TRACE("handle = %x\n",handle);
1442
1443     for (ovp = NtCurrentTeb()->pending_list; ovp; ovp = t)
1444     {
1445         t = ovp->next;
1446         if ( ovp->handle == handle )
1447              cancel_async ( ovp );
1448     }
1449     WaitForMultipleObjectsEx(0,NULL,FALSE,1,TRUE);
1450     return TRUE;
1451 }
1452
1453 /***********************************************************************
1454  *             FILE_AsyncReadService      (INTERNAL)
1455  *
1456  *  This function is called while the client is waiting on the
1457  *  server, so we can't make any server calls here.
1458  */
1459 static void FILE_AsyncReadService(async_private *ovp)
1460 {
1461     async_fileio *fileio = (async_fileio*) ovp;
1462     LPOVERLAPPED lpOverlapped = fileio->lpOverlapped;
1463     int result, r;
1464     int already = lpOverlapped->InternalHigh;
1465
1466     TRACE("%p %p\n", lpOverlapped, fileio->buffer );
1467
1468     /* check to see if the data is ready (non-blocking) */
1469
1470     if ( fileio->fd_type == FD_TYPE_SOCKET )
1471         result = read (ovp->fd, &fileio->buffer[already], fileio->count - already);
1472     else
1473     {
1474         result = pread (ovp->fd, &fileio->buffer[already], fileio->count - already,
1475                         OVERLAPPED_OFFSET (lpOverlapped) + already);
1476         if ((result < 0) && (errno == ESPIPE))
1477             result = read (ovp->fd, &fileio->buffer[already], fileio->count - already);
1478     }
1479
1480     if ( (result<0) && ((errno == EAGAIN) || (errno == EINTR)))
1481     {
1482         TRACE("Deferred read %d\n",errno);
1483         r = STATUS_PENDING;
1484         goto async_end;
1485     }
1486
1487     /* check to see if the transfer is complete */
1488     if(result<0)
1489     {
1490         r = FILE_GetNtStatus ();
1491         goto async_end;
1492     }
1493
1494     lpOverlapped->InternalHigh += result;
1495     TRACE("read %d more bytes %ld/%d so far\n",result,lpOverlapped->InternalHigh,fileio->count);
1496
1497     if(lpOverlapped->InternalHigh >= fileio->count || fileio->fd_type == FD_TYPE_SOCKET )
1498         r = STATUS_SUCCESS;
1499     else
1500         r = STATUS_PENDING;
1501
1502 async_end:
1503     lpOverlapped->Internal = r;
1504 }
1505
1506 /***********************************************************************
1507  *              FILE_ReadFileEx                (INTERNAL)
1508  */
1509 static BOOL FILE_ReadFileEx(HANDLE hFile, LPVOID buffer, DWORD bytesToRead,
1510                          LPOVERLAPPED overlapped,
1511                          LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine,
1512                          HANDLE hEvent)
1513 {
1514     async_fileio *ovp;
1515     int fd;
1516     int flags;
1517     enum fd_type type;
1518
1519     TRACE("file %d to buf %p num %ld %p func %p\n",
1520           hFile, buffer, bytesToRead, overlapped, lpCompletionRoutine);
1521
1522     /* check that there is an overlapped struct */
1523     if (overlapped==NULL)
1524     {
1525         SetLastError(ERROR_INVALID_PARAMETER);
1526         return FALSE;
1527     }
1528
1529     fd = FILE_GetUnixHandleType ( hFile, GENERIC_READ, &type, &flags);
1530     if ( fd < 0 )
1531     {
1532         WARN ( "Couldn't get FD\n" );
1533         return FALSE;
1534     }
1535
1536     ovp = (async_fileio*) HeapAlloc(GetProcessHeap(), 0, sizeof (async_fileio));
1537     if(!ovp)
1538     {
1539         TRACE("HeapAlloc Failed\n");
1540         SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1541         goto error;
1542     }
1543
1544     ovp->async.ops = ( lpCompletionRoutine ? &fileio_async_ops : &fileio_nocomp_async_ops );
1545     ovp->async.handle = hFile;
1546     ovp->async.fd = fd;
1547     ovp->async.type = ASYNC_TYPE_READ;
1548     ovp->async.func = FILE_AsyncReadService;
1549     ovp->async.event = hEvent;
1550     ovp->lpOverlapped = overlapped;
1551     ovp->count = bytesToRead;
1552     ovp->completion_func = lpCompletionRoutine;
1553     ovp->buffer = buffer;
1554     ovp->fd_type = type;
1555
1556     return !register_new_async (&ovp->async);
1557
1558 error:
1559     close (fd);
1560     return FALSE;
1561
1562 }
1563
1564 /***********************************************************************
1565  *              ReadFileEx                (KERNEL32.@)
1566  */
1567 BOOL WINAPI ReadFileEx(HANDLE hFile, LPVOID buffer, DWORD bytesToRead,
1568                          LPOVERLAPPED overlapped,
1569                          LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine)
1570 {
1571     overlapped->InternalHigh = 0;
1572     return FILE_ReadFileEx(hFile,buffer,bytesToRead,overlapped,lpCompletionRoutine, INVALID_HANDLE_VALUE);
1573 }
1574
1575 static BOOL FILE_TimeoutRead(HANDLE hFile, LPVOID buffer, DWORD bytesToRead, LPDWORD bytesRead)
1576 {
1577     OVERLAPPED ov;
1578     BOOL r = FALSE;
1579
1580     TRACE("%d %p %ld %p\n", hFile, buffer, bytesToRead, bytesRead );
1581
1582     ZeroMemory(&ov, sizeof (OVERLAPPED));
1583     if(STATUS_SUCCESS==NtCreateEvent(&ov.hEvent, SYNCHRONIZE, NULL, 0, 0))
1584     {
1585         if(FILE_ReadFileEx(hFile, buffer, bytesToRead, &ov, NULL, ov.hEvent))
1586         {
1587             r = GetOverlappedResult(hFile, &ov, bytesRead, TRUE);
1588         }
1589     }
1590     CloseHandle(ov.hEvent);
1591     return r;
1592 }
1593
1594 /***********************************************************************
1595  *              ReadFile                (KERNEL32.@)
1596  */
1597 BOOL WINAPI ReadFile( HANDLE hFile, LPVOID buffer, DWORD bytesToRead,
1598                         LPDWORD bytesRead, LPOVERLAPPED overlapped )
1599 {
1600     int unix_handle, result, flags;
1601     enum fd_type type;
1602
1603     TRACE("%d %p %ld %p %p\n", hFile, buffer, bytesToRead,
1604           bytesRead, overlapped );
1605
1606     if (bytesRead) *bytesRead = 0;  /* Do this before anything else */
1607     if (!bytesToRead) return TRUE;
1608
1609     unix_handle = FILE_GetUnixHandleType( hFile, GENERIC_READ, &type, &flags );
1610
1611     if (flags & FD_FLAG_OVERLAPPED)
1612     {
1613         if (unix_handle == -1) return FALSE;
1614         if ( (overlapped==NULL) || NtResetEvent( overlapped->hEvent, NULL ) )
1615         {
1616             TRACE("Overlapped not specified or invalid event flag\n");
1617             close(unix_handle);
1618             SetLastError(ERROR_INVALID_PARAMETER);
1619             return FALSE;
1620         }
1621
1622         close(unix_handle);
1623         overlapped->InternalHigh = 0;
1624
1625         if(!FILE_ReadFileEx(hFile, buffer, bytesToRead, overlapped, NULL, overlapped->hEvent))
1626             return FALSE;
1627
1628         if ( !GetOverlappedResult (hFile, overlapped, bytesRead, FALSE) )
1629         {
1630             if ( GetLastError() == ERROR_IO_INCOMPLETE )
1631                 SetLastError ( ERROR_IO_PENDING );
1632             return FALSE;
1633         }
1634
1635         return TRUE;
1636     }
1637     if (flags & FD_FLAG_TIMEOUT)
1638     {
1639         close(unix_handle);
1640         return FILE_TimeoutRead(hFile, buffer, bytesToRead, bytesRead);
1641     }
1642     switch(type)
1643     {
1644     case FD_TYPE_SMB:
1645         return SMB_ReadFile(hFile, buffer, bytesToRead, bytesRead, NULL);
1646     case FD_TYPE_CONSOLE:
1647         return ReadConsoleA(hFile, buffer, bytesToRead, bytesRead, NULL);
1648
1649     default:
1650         /* normal unix files */
1651         if (unix_handle == -1)
1652             return FALSE;
1653         if (overlapped)
1654         {
1655             close(unix_handle);
1656             SetLastError(ERROR_INVALID_PARAMETER);
1657             return FALSE;
1658         }
1659         break;
1660     }
1661
1662     /* code for synchronous reads */
1663     while ((result = read( unix_handle, buffer, bytesToRead )) == -1)
1664     {
1665         if ((errno == EAGAIN) || (errno == EINTR)) continue;
1666         if ((errno == EFAULT) && !IsBadWritePtr( buffer, bytesToRead )) continue;
1667         FILE_SetDosError();
1668         break;
1669     }
1670     close( unix_handle );
1671     if (result == -1) return FALSE;
1672     if (bytesRead) *bytesRead = result;
1673     return TRUE;
1674 }
1675
1676
1677 /***********************************************************************
1678  *             FILE_AsyncWriteService      (INTERNAL)
1679  *
1680  *  This function is called while the client is waiting on the
1681  *  server, so we can't make any server calls here.
1682  */
1683 static void FILE_AsyncWriteService(struct async_private *ovp)
1684 {
1685     async_fileio *fileio = (async_fileio *) ovp;
1686     LPOVERLAPPED lpOverlapped = fileio->lpOverlapped;
1687     int result, r;
1688     int already = lpOverlapped->InternalHigh;
1689
1690     TRACE("(%p %p)\n",lpOverlapped,fileio->buffer);
1691
1692     /* write some data (non-blocking) */
1693
1694     if ( fileio->fd_type == FD_TYPE_SOCKET )
1695         result = write(ovp->fd, &fileio->buffer[already], fileio->count - already);
1696     else
1697     {
1698         result = pwrite(ovp->fd, &fileio->buffer[already], fileio->count - already,
1699                     OVERLAPPED_OFFSET (lpOverlapped) + already);
1700         if ((result < 0) && (errno == ESPIPE))
1701             result = write(ovp->fd, &fileio->buffer[already], fileio->count - already);
1702     }
1703
1704     if ( (result<0) && ((errno == EAGAIN) || (errno == EINTR)))
1705     {
1706         r = STATUS_PENDING;
1707         goto async_end;
1708     }
1709
1710     /* check to see if the transfer is complete */
1711     if(result<0)
1712     {
1713         r = FILE_GetNtStatus ();
1714         goto async_end;
1715     }
1716
1717     lpOverlapped->InternalHigh += result;
1718
1719     TRACE("wrote %d more bytes %ld/%d so far\n",result,lpOverlapped->InternalHigh,fileio->count);
1720
1721     if(lpOverlapped->InternalHigh < fileio->count)
1722         r = STATUS_PENDING;
1723     else
1724         r = STATUS_SUCCESS;
1725
1726 async_end:
1727     lpOverlapped->Internal = r;
1728 }
1729
1730 /***********************************************************************
1731  *              FILE_WriteFileEx
1732  */
1733 static BOOL FILE_WriteFileEx(HANDLE hFile, LPCVOID buffer, DWORD bytesToWrite,
1734                              LPOVERLAPPED overlapped,
1735                              LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine,
1736                              HANDLE hEvent)
1737 {
1738     async_fileio *ovp;
1739     int fd;
1740     int flags;
1741     enum fd_type type;
1742
1743     TRACE("file %d to buf %p num %ld %p func %p handle %d\n",
1744           hFile, buffer, bytesToWrite, overlapped, lpCompletionRoutine, hEvent);
1745
1746     if (overlapped == NULL)
1747     {
1748         SetLastError(ERROR_INVALID_PARAMETER);
1749         return FALSE;
1750     }
1751
1752     fd = FILE_GetUnixHandleType ( hFile, GENERIC_WRITE, &type, &flags );
1753     if ( fd < 0 )
1754     {
1755         TRACE( "Couldn't get FD\n" );
1756         return FALSE;
1757     }
1758
1759     ovp = (async_fileio*) HeapAlloc(GetProcessHeap(), 0, sizeof (async_fileio));
1760     if(!ovp)
1761     {
1762         TRACE("HeapAlloc Failed\n");
1763         SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1764         goto error;
1765     }
1766
1767     ovp->async.ops = ( lpCompletionRoutine ? &fileio_async_ops : &fileio_nocomp_async_ops );
1768     ovp->async.handle = hFile;
1769     ovp->async.fd = fd;
1770     ovp->async.type = ASYNC_TYPE_WRITE;
1771     ovp->async.func = FILE_AsyncWriteService;
1772     ovp->lpOverlapped = overlapped;
1773     ovp->async.event = hEvent;
1774     ovp->buffer = (LPVOID) buffer;
1775     ovp->count = bytesToWrite;
1776     ovp->completion_func = lpCompletionRoutine;
1777     ovp->fd_type = type;
1778
1779     return !register_new_async (&ovp->async);
1780
1781 error:
1782     close (fd);
1783     return FALSE;
1784 }
1785
1786 /***********************************************************************
1787  *              WriteFileEx                (KERNEL32.@)
1788  */
1789 BOOL WINAPI WriteFileEx(HANDLE hFile, LPCVOID buffer, DWORD bytesToWrite,
1790                          LPOVERLAPPED overlapped,
1791                          LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine)
1792 {
1793     overlapped->InternalHigh = 0;
1794
1795     return FILE_WriteFileEx(hFile, buffer, bytesToWrite, overlapped, lpCompletionRoutine, INVALID_HANDLE_VALUE);
1796 }
1797
1798 /***********************************************************************
1799  *             WriteFile               (KERNEL32.@)
1800  */
1801 BOOL WINAPI WriteFile( HANDLE hFile, LPCVOID buffer, DWORD bytesToWrite,
1802                          LPDWORD bytesWritten, LPOVERLAPPED overlapped )
1803 {
1804     int unix_handle, result, flags;
1805     enum fd_type type;
1806
1807     TRACE("%d %p %ld %p %p\n", hFile, buffer, bytesToWrite,
1808           bytesWritten, overlapped );
1809
1810     if (bytesWritten) *bytesWritten = 0;  /* Do this before anything else */
1811     if (!bytesToWrite) return TRUE;
1812
1813     unix_handle = FILE_GetUnixHandleType( hFile, GENERIC_WRITE, &type, &flags );
1814
1815     if (flags & FD_FLAG_OVERLAPPED)
1816     {
1817         if (unix_handle == -1) return FALSE;
1818         if ( (overlapped==NULL) || NtResetEvent( overlapped->hEvent, NULL ) )
1819         {
1820             TRACE("Overlapped not specified or invalid event flag\n");
1821             close(unix_handle);
1822             SetLastError(ERROR_INVALID_PARAMETER);
1823             return FALSE;
1824         }
1825
1826         close(unix_handle);
1827         overlapped->InternalHigh = 0;
1828
1829         if(!FILE_WriteFileEx(hFile, buffer, bytesToWrite, overlapped, NULL, overlapped->hEvent))
1830             return FALSE;
1831
1832         if ( !GetOverlappedResult (hFile, overlapped, bytesWritten, FALSE) )
1833         {
1834             if ( GetLastError() == ERROR_IO_INCOMPLETE )
1835                 SetLastError ( ERROR_IO_PENDING );
1836             return FALSE;
1837         }
1838
1839         return TRUE;
1840     }
1841
1842     switch(type)
1843     {
1844     case FD_TYPE_CONSOLE:
1845         TRACE("%d %s %ld %p %p\n", hFile, debugstr_an(buffer, bytesToWrite), bytesToWrite,
1846               bytesWritten, overlapped );
1847         return WriteConsoleA(hFile, buffer, bytesToWrite, bytesWritten, NULL);
1848     default:
1849         if (unix_handle == -1)
1850             return FALSE;
1851     }
1852
1853     /* synchronous file write */
1854     while ((result = write( unix_handle, buffer, bytesToWrite )) == -1)
1855     {
1856         if ((errno == EAGAIN) || (errno == EINTR)) continue;
1857         if ((errno == EFAULT) && !IsBadReadPtr( buffer, bytesToWrite )) continue;
1858         if (errno == ENOSPC)
1859             SetLastError( ERROR_DISK_FULL );
1860         else
1861         FILE_SetDosError();
1862         break;
1863     }
1864     close( unix_handle );
1865     if (result == -1) return FALSE;
1866     if (bytesWritten) *bytesWritten = result;
1867     return TRUE;
1868 }
1869
1870
1871 /***********************************************************************
1872  *           _hread (KERNEL.349)
1873  */
1874 LONG WINAPI WIN16_hread( HFILE16 hFile, SEGPTR buffer, LONG count )
1875 {
1876     LONG maxlen;
1877
1878     TRACE("%d %08lx %ld\n",
1879                   hFile, (DWORD)buffer, count );
1880
1881     /* Some programs pass a count larger than the allocated buffer */
1882     maxlen = GetSelectorLimit16( SELECTOROF(buffer) ) - OFFSETOF(buffer) + 1;
1883     if (count > maxlen) count = maxlen;
1884     return _lread(DosFileHandleToWin32Handle(hFile), MapSL(buffer), count );
1885 }
1886
1887
1888 /***********************************************************************
1889  *           _lread (KERNEL.82)
1890  */
1891 UINT16 WINAPI WIN16_lread( HFILE16 hFile, SEGPTR buffer, UINT16 count )
1892 {
1893     return (UINT16)WIN16_hread( hFile, buffer, (LONG)count );
1894 }
1895
1896
1897 /***********************************************************************
1898  *           _lread   (KERNEL32.@)
1899  */
1900 UINT WINAPI _lread( HFILE handle, LPVOID buffer, UINT count )
1901 {
1902     DWORD result;
1903     if (!ReadFile( handle, buffer, count, &result, NULL )) return -1;
1904     return result;
1905 }
1906
1907
1908 /***********************************************************************
1909  *           _lread16   (KERNEL.82)
1910  */
1911 UINT16 WINAPI _lread16( HFILE16 hFile, LPVOID buffer, UINT16 count )
1912 {
1913     return (UINT16)_lread(DosFileHandleToWin32Handle(hFile), buffer, (LONG)count );
1914 }
1915
1916
1917 /***********************************************************************
1918  *           _lcreat   (KERNEL.83)
1919  */
1920 HFILE16 WINAPI _lcreat16( LPCSTR path, INT16 attr )
1921 {
1922     return Win32HandleToDosFileHandle( _lcreat( path, attr ) );
1923 }
1924
1925
1926 /***********************************************************************
1927  *           _lcreat   (KERNEL32.@)
1928  */
1929 HFILE WINAPI _lcreat( LPCSTR path, INT attr )
1930 {
1931     /* Mask off all flags not explicitly allowed by the doc */
1932     attr &= FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM;
1933     TRACE("%s %02x\n", path, attr );
1934     return CreateFileA( path, GENERIC_READ | GENERIC_WRITE,
1935                         FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
1936                         CREATE_ALWAYS, attr, 0 );
1937 }
1938
1939
1940 /***********************************************************************
1941  *           SetFilePointer   (KERNEL32.@)
1942  */
1943 DWORD WINAPI SetFilePointer( HANDLE hFile, LONG distance, LONG *highword,
1944                              DWORD method )
1945 {
1946     DWORD ret = 0xffffffff;
1947
1948     TRACE("handle %d offset %ld high %ld origin %ld\n",
1949           hFile, distance, highword?*highword:0, method );
1950
1951     SERVER_START_REQ( set_file_pointer )
1952     {
1953         req->handle = hFile;
1954         req->low = distance;
1955         req->high = highword ? *highword : (distance >= 0) ? 0 : -1;
1956         /* FIXME: assumes 1:1 mapping between Windows and Unix seek constants */
1957         req->whence = method;
1958         SetLastError( 0 );
1959         if (!wine_server_call_err( req ))
1960         {
1961             ret = reply->new_low;
1962             if (highword) *highword = reply->new_high;
1963         }
1964     }
1965     SERVER_END_REQ;
1966     return ret;
1967 }
1968
1969
1970 /***********************************************************************
1971  *           _llseek   (KERNEL.84)
1972  *
1973  * FIXME:
1974  *   Seeking before the start of the file should be allowed for _llseek16,
1975  *   but cause subsequent I/O operations to fail (cf. interrupt list)
1976  *
1977  */
1978 LONG WINAPI _llseek16( HFILE16 hFile, LONG lOffset, INT16 nOrigin )
1979 {
1980     return SetFilePointer( DosFileHandleToWin32Handle(hFile), lOffset, NULL, nOrigin );
1981 }
1982
1983
1984 /***********************************************************************
1985  *           _llseek   (KERNEL32.@)
1986  */
1987 LONG WINAPI _llseek( HFILE hFile, LONG lOffset, INT nOrigin )
1988 {
1989     return SetFilePointer( hFile, lOffset, NULL, nOrigin );
1990 }
1991
1992
1993 /***********************************************************************
1994  *           _lopen   (KERNEL.85)
1995  */
1996 HFILE16 WINAPI _lopen16( LPCSTR path, INT16 mode )
1997 {
1998     return Win32HandleToDosFileHandle( _lopen( path, mode ) );
1999 }
2000
2001
2002 /***********************************************************************
2003  *           _lopen   (KERNEL32.@)
2004  */
2005 HFILE WINAPI _lopen( LPCSTR path, INT mode )
2006 {
2007     DWORD access, sharing;
2008
2009     TRACE("('%s',%04x)\n", path, mode );
2010     FILE_ConvertOFMode( mode, &access, &sharing );
2011     return CreateFileA( path, access, sharing, NULL, OPEN_EXISTING, 0, 0 );
2012 }
2013
2014
2015 /***********************************************************************
2016  *           _lwrite   (KERNEL.86)
2017  */
2018 UINT16 WINAPI _lwrite16( HFILE16 hFile, LPCSTR buffer, UINT16 count )
2019 {
2020     return (UINT16)_hwrite( DosFileHandleToWin32Handle(hFile), buffer, (LONG)count );
2021 }
2022
2023 /***********************************************************************
2024  *           _lwrite   (KERNEL32.@)
2025  */
2026 UINT WINAPI _lwrite( HFILE hFile, LPCSTR buffer, UINT count )
2027 {
2028     return (UINT)_hwrite( hFile, buffer, (LONG)count );
2029 }
2030
2031
2032 /***********************************************************************
2033  *           _hread16   (KERNEL.349)
2034  */
2035 LONG WINAPI _hread16( HFILE16 hFile, LPVOID buffer, LONG count)
2036 {
2037     return _lread( DosFileHandleToWin32Handle(hFile), buffer, count );
2038 }
2039
2040
2041 /***********************************************************************
2042  *           _hread   (KERNEL32.@)
2043  */
2044 LONG WINAPI _hread( HFILE hFile, LPVOID buffer, LONG count)
2045 {
2046     return _lread( hFile, buffer, count );
2047 }
2048
2049
2050 /***********************************************************************
2051  *           _hwrite   (KERNEL.350)
2052  */
2053 LONG WINAPI _hwrite16( HFILE16 hFile, LPCSTR buffer, LONG count )
2054 {
2055     return _hwrite( DosFileHandleToWin32Handle(hFile), buffer, count );
2056 }
2057
2058
2059 /***********************************************************************
2060  *           _hwrite   (KERNEL32.@)
2061  *
2062  *      experimentation yields that _lwrite:
2063  *              o truncates the file at the current position with
2064  *                a 0 len write
2065  *              o returns 0 on a 0 length write
2066  *              o works with console handles
2067  *
2068  */
2069 LONG WINAPI _hwrite( HFILE handle, LPCSTR buffer, LONG count )
2070 {
2071     DWORD result;
2072
2073     TRACE("%d %p %ld\n", handle, buffer, count );
2074
2075     if (!count)
2076     {
2077         /* Expand or truncate at current position */
2078         if (!SetEndOfFile( handle )) return HFILE_ERROR;
2079         return 0;
2080     }
2081     if (!WriteFile( handle, buffer, count, &result, NULL ))
2082         return HFILE_ERROR;
2083     return result;
2084 }
2085
2086
2087 /***********************************************************************
2088  *           SetHandleCount   (KERNEL.199)
2089  */
2090 UINT16 WINAPI SetHandleCount16( UINT16 count )
2091 {
2092     return SetHandleCount( count );
2093 }
2094
2095
2096 /*************************************************************************
2097  *           SetHandleCount   (KERNEL32.@)
2098  */
2099 UINT WINAPI SetHandleCount( UINT count )
2100 {
2101     return min( 256, count );
2102 }
2103
2104
2105 /***********************************************************************
2106  *           FlushFileBuffers   (KERNEL32.@)
2107  */
2108 BOOL WINAPI FlushFileBuffers( HANDLE hFile )
2109 {
2110     BOOL ret;
2111     SERVER_START_REQ( flush_file )
2112     {
2113         req->handle = hFile;
2114         ret = !wine_server_call_err( req );
2115     }
2116     SERVER_END_REQ;
2117     return ret;
2118 }
2119
2120
2121 /**************************************************************************
2122  *           SetEndOfFile   (KERNEL32.@)
2123  */
2124 BOOL WINAPI SetEndOfFile( HANDLE hFile )
2125 {
2126     BOOL ret;
2127     SERVER_START_REQ( truncate_file )
2128     {
2129         req->handle = hFile;
2130         ret = !wine_server_call_err( req );
2131     }
2132     SERVER_END_REQ;
2133     return ret;
2134 }
2135
2136
2137 /***********************************************************************
2138  *           DeleteFile   (KERNEL.146)
2139  */
2140 BOOL16 WINAPI DeleteFile16( LPCSTR path )
2141 {
2142     return DeleteFileA( path );
2143 }
2144
2145
2146 /***********************************************************************
2147  *           DeleteFileA   (KERNEL32.@)
2148  */
2149 BOOL WINAPI DeleteFileA( LPCSTR path )
2150 {
2151     DOS_FULL_NAME full_name;
2152     HANDLE hFile;
2153
2154     if (!path)
2155     {
2156         SetLastError(ERROR_INVALID_PARAMETER);
2157         return FALSE;
2158     }
2159     TRACE("'%s'\n", path );
2160
2161     if (!*path)
2162     {
2163         ERR("Empty path passed\n");
2164         return FALSE;
2165     }
2166     if (DOSFS_GetDevice( path ))
2167     {
2168         WARN("cannot remove DOS device '%s'!\n", path);
2169         SetLastError( ERROR_FILE_NOT_FOUND );
2170         return FALSE;
2171     }
2172
2173     if (!DOSFS_GetFullName( path, TRUE, &full_name )) return FALSE;
2174
2175     /* check if we are allowed to delete the source */
2176     hFile = FILE_CreateFile( full_name.long_name, GENERIC_READ|GENERIC_WRITE, 0,
2177                              NULL, OPEN_EXISTING, 0, 0, TRUE,
2178                              GetDriveTypeA( full_name.short_name ) );
2179     if (!hFile) return FALSE;
2180
2181     if (unlink( full_name.long_name ) == -1)
2182     {
2183         FILE_SetDosError();
2184         CloseHandle(hFile);
2185         return FALSE;
2186     }
2187     CloseHandle(hFile);
2188     return TRUE;
2189 }
2190
2191
2192 /***********************************************************************
2193  *           DeleteFileW   (KERNEL32.@)
2194  */
2195 BOOL WINAPI DeleteFileW( LPCWSTR path )
2196 {
2197     LPSTR xpath = HEAP_strdupWtoA( GetProcessHeap(), 0, path );
2198     BOOL ret = DeleteFileA( xpath );
2199     HeapFree( GetProcessHeap(), 0, xpath );
2200     return ret;
2201 }
2202
2203
2204 /***********************************************************************
2205  *           GetFileType   (KERNEL32.@)
2206  */
2207 DWORD WINAPI GetFileType( HANDLE hFile )
2208 {
2209     DWORD ret = FILE_TYPE_UNKNOWN;
2210     SERVER_START_REQ( get_file_info )
2211     {
2212         req->handle = hFile;
2213         if (!wine_server_call_err( req )) ret = reply->type;
2214     }
2215     SERVER_END_REQ;
2216     return ret;
2217 }
2218
2219
2220 /* check if a file name is for an executable file (.exe or .com) */
2221 inline static BOOL is_executable( const char *name )
2222 {
2223     int len = strlen(name);
2224
2225     if (len < 4) return FALSE;
2226     return (!strcasecmp( name + len - 4, ".exe" ) ||
2227             !strcasecmp( name + len - 4, ".com" ));
2228 }
2229
2230
2231 /***********************************************************************
2232  *           FILE_AddBootRenameEntry
2233  *
2234  * Adds an entry to the registry that is loaded when windows boots and
2235  * checks if there are some files to be removed or renamed/moved.
2236  * <fn1> has to be valid and <fn2> may be NULL. If both pointers are
2237  * non-NULL then the file is moved, otherwise it is deleted.  The
2238  * entry of the registrykey is always appended with two zero
2239  * terminated strings. If <fn2> is NULL then the second entry is
2240  * simply a single 0-byte. Otherwise the second filename goes
2241  * there. The entries are prepended with \??\ before the path and the
2242  * second filename gets also a '!' as the first character if
2243  * MOVEFILE_REPLACE_EXISTING is set. After the final string another
2244  * 0-byte follows to indicate the end of the strings.
2245  * i.e.:
2246  * \??\D:\test\file1[0]
2247  * !\??\D:\test\file1_renamed[0]
2248  * \??\D:\Test|delete[0]
2249  * [0]                        <- file is to be deleted, second string empty
2250  * \??\D:\test\file2[0]
2251  * !\??\D:\test\file2_renamed[0]
2252  * [0]                        <- indicates end of strings
2253  *
2254  * or:
2255  * \??\D:\test\file1[0]
2256  * !\??\D:\test\file1_renamed[0]
2257  * \??\D:\Test|delete[0]
2258  * [0]                        <- file is to be deleted, second string empty
2259  * [0]                        <- indicates end of strings
2260  *
2261  */
2262 static BOOL FILE_AddBootRenameEntry( const char *fn1, const char *fn2, DWORD flags )
2263 {
2264     static const char PreString[] = "\\??\\";
2265     static const char ValueName[] = "PendingFileRenameOperations";
2266
2267     BOOL rc = FALSE;
2268     HKEY Reboot = 0;
2269     DWORD Type, len1, len2, l;
2270     DWORD DataSize = 0;
2271     BYTE *Buffer = NULL;
2272
2273     if(RegCreateKeyA(HKEY_LOCAL_MACHINE, "SYSTEM\\CurrentControlSet\\Control\\Session Manager",
2274                      &Reboot) != ERROR_SUCCESS)
2275     {
2276         WARN("Error creating key for reboot managment [%s]\n",
2277              "SYSTEM\\CurrentControlSet\\Control\\Session Manager");
2278         return FALSE;
2279     }
2280
2281     l = strlen(PreString);
2282     len1 = strlen(fn1) + l + 1;
2283     if (fn2)
2284     {
2285         len2 = strlen(fn2) + l + 1;
2286         if (flags & MOVEFILE_REPLACE_EXISTING) len2++; /* Plus 1 because of the leading '!' */
2287     }
2288     else len2 = 1; /* minimum is the 0 byte for the empty second string */
2289
2290     /* First we check if the key exists and if so how many bytes it already contains. */
2291     if (RegQueryValueExA(Reboot, ValueName, NULL, &Type, NULL, &DataSize) == ERROR_SUCCESS)
2292     {
2293         if (Type != REG_MULTI_SZ) goto Quit;
2294         if (!(Buffer = HeapAlloc( GetProcessHeap(), 0, DataSize + len1 + len2 + 1 ))) goto Quit;
2295         if (RegQueryValueExA(Reboot, ValueName, NULL, &Type, Buffer, &DataSize) != ERROR_SUCCESS)
2296             goto Quit;
2297         if (DataSize) DataSize--;  /* remove terminating null (will be added back later) */
2298     }
2299     else
2300     {
2301         if (!(Buffer = HeapAlloc( GetProcessHeap(), 0, len1 + len2 + 1 ))) goto Quit;
2302         DataSize = 0;
2303     }
2304     sprintf( Buffer + DataSize, "%s%s", PreString, fn1 );
2305     DataSize += len1;
2306     if (fn2)
2307     {
2308         sprintf( Buffer + DataSize, "%s%s%s",
2309                  (flags & MOVEFILE_REPLACE_EXISTING) ? "!" : "", PreString, fn2 );
2310         DataSize += len2;
2311     }
2312     else Buffer[DataSize++] = 0;
2313
2314     Buffer[DataSize++] = 0;  /* add final null */
2315     rc = !RegSetValueExA( Reboot, ValueName, 0, REG_MULTI_SZ, Buffer, DataSize );
2316
2317  Quit:
2318     if (Reboot) RegCloseKey(Reboot);
2319     if (Buffer) HeapFree( GetProcessHeap(), 0, Buffer );
2320     return(rc);
2321 }
2322
2323
2324 /**************************************************************************
2325  *           MoveFileExA   (KERNEL32.@)
2326  */
2327 BOOL WINAPI MoveFileExA( LPCSTR fn1, LPCSTR fn2, DWORD flag )
2328 {
2329     DOS_FULL_NAME full_name1, full_name2;
2330     HANDLE hFile;
2331
2332     TRACE("(%s,%s,%04lx)\n", fn1, fn2, flag);
2333
2334     /* FIXME: <Gerhard W. Gruber>sparhawk@gmx.at
2335        In case of W9x and lesser this function should return 120 (ERROR_CALL_NOT_IMPLEMENTED)
2336        to be really compatible. Most programs wont have any problems though. In case
2337        you encounter one, this is what you should return here. I don't know what's up
2338        with NT 3.5. Is this function available there or not?
2339        Does anybody really care about 3.5? :)
2340     */
2341
2342     /* Filename1 has to be always set to a valid path. Filename2 may be NULL
2343        if the source file has to be deleted.
2344     */
2345     if (!fn1) {
2346         SetLastError(ERROR_INVALID_PARAMETER);
2347         return FALSE;
2348     }
2349
2350     /* This function has to be run through in order to process the name properly.
2351        If the BOOTDELAY flag is set, the file doesn't need to exist though. At least
2352        that is the behaviour on NT 4.0. The operation accepts the filenames as
2353        they are given but it can't reply with a reasonable returncode. Success
2354        means in that case success for entering the values into the registry.
2355     */
2356     if(!DOSFS_GetFullName( fn1, TRUE, &full_name1 ))
2357     {
2358         if(!(flag & MOVEFILE_DELAY_UNTIL_REBOOT))
2359             return FALSE;
2360     }
2361
2362     if (fn2)  /* !fn2 means delete fn1 */
2363     {
2364         if (DOSFS_GetFullName( fn2, TRUE, &full_name2 ))
2365         {
2366             if(!(flag & MOVEFILE_DELAY_UNTIL_REBOOT))
2367             {
2368                 /* target exists, check if we may overwrite */
2369                 if (!(flag & MOVEFILE_REPLACE_EXISTING))
2370                 {
2371                     /* FIXME: Use right error code */
2372                     SetLastError( ERROR_ACCESS_DENIED );
2373                     return FALSE;
2374                 }
2375             }
2376         }
2377         else
2378         {
2379             if (!DOSFS_GetFullName( fn2, FALSE, &full_name2 ))
2380             {
2381                 if(!(flag & MOVEFILE_DELAY_UNTIL_REBOOT))
2382                     return FALSE;
2383             }
2384         }
2385
2386         /* Source name and target path are valid */
2387
2388         if (flag & MOVEFILE_DELAY_UNTIL_REBOOT)
2389         {
2390             /* FIXME: (bon@elektron.ikp.physik.th-darmstadt.de 970706)
2391                Perhaps we should queue these command and execute it
2392                when exiting... What about using on_exit(2)
2393             */
2394             FIXME("Please move existing file '%s' to file '%s' when Wine has finished\n",
2395                   fn1, fn2);
2396             return FILE_AddBootRenameEntry( fn1, fn2, flag );
2397         }
2398
2399         /* check if we are allowed to delete the source */
2400         hFile = FILE_CreateFile( full_name1.long_name, GENERIC_READ|GENERIC_WRITE, 0,
2401                                  NULL, OPEN_EXISTING, 0, 0, TRUE,
2402                                  GetDriveTypeA( full_name1.short_name ) );
2403         if (!hFile) return FALSE;
2404         CloseHandle(hFile);
2405
2406         /* check, if we are allowed to delete the destination,
2407         **     (but the file not being there is fine) */
2408         hFile = FILE_CreateFile( full_name2.long_name, GENERIC_READ|GENERIC_WRITE, 0,
2409                                  NULL, OPEN_EXISTING, 0, 0, TRUE,
2410                                  GetDriveTypeA( full_name2.short_name ) );
2411         if(!hFile && GetLastError() != ERROR_FILE_NOT_FOUND) return FALSE;
2412         CloseHandle(hFile);
2413
2414         if (full_name1.drive != full_name2.drive)
2415         {
2416             /* use copy, if allowed */
2417             if (!(flag & MOVEFILE_COPY_ALLOWED))
2418             {
2419                 /* FIXME: Use right error code */
2420                 SetLastError( ERROR_FILE_EXISTS );
2421                 return FALSE;
2422             }
2423             return CopyFileA( fn1, fn2, !(flag & MOVEFILE_REPLACE_EXISTING) );
2424         }
2425         if (rename( full_name1.long_name, full_name2.long_name ) == -1)
2426         {
2427             FILE_SetDosError();
2428             return FALSE;
2429         }
2430         if (is_executable( full_name1.long_name ) != is_executable( full_name2.long_name ))
2431         {
2432             struct stat fstat;
2433             if (stat( full_name2.long_name, &fstat ) != -1)
2434             {
2435                 if (is_executable( full_name2.long_name ))
2436                     /* set executable bit where read bit is set */
2437                     fstat.st_mode |= (fstat.st_mode & 0444) >> 2;
2438                 else
2439                     fstat.st_mode &= ~0111;
2440                 chmod( full_name2.long_name, fstat.st_mode );
2441             }
2442         }
2443         return TRUE;
2444     }
2445     else /* fn2 == NULL means delete source */
2446     {
2447         if (flag & MOVEFILE_DELAY_UNTIL_REBOOT)
2448         {
2449             if (flag & MOVEFILE_COPY_ALLOWED) {
2450                 WARN("Illegal flag\n");
2451                 SetLastError( ERROR_GEN_FAILURE );
2452                 return FALSE;
2453             }
2454             /* FIXME: (bon@elektron.ikp.physik.th-darmstadt.de 970706)
2455                Perhaps we should queue these command and execute it
2456                when exiting... What about using on_exit(2)
2457             */
2458             FIXME("Please delete file '%s' when Wine has finished\n", fn1);
2459             return FILE_AddBootRenameEntry( fn1, NULL, flag );
2460         }
2461
2462         if (unlink( full_name1.long_name ) == -1)
2463         {
2464             FILE_SetDosError();
2465             return FALSE;
2466         }
2467         return TRUE; /* successfully deleted */
2468     }
2469 }
2470
2471 /**************************************************************************
2472  *           MoveFileExW   (KERNEL32.@)
2473  */
2474 BOOL WINAPI MoveFileExW( LPCWSTR fn1, LPCWSTR fn2, DWORD flag )
2475 {
2476     LPSTR afn1 = HEAP_strdupWtoA( GetProcessHeap(), 0, fn1 );
2477     LPSTR afn2 = HEAP_strdupWtoA( GetProcessHeap(), 0, fn2 );
2478     BOOL res = MoveFileExA( afn1, afn2, flag );
2479     HeapFree( GetProcessHeap(), 0, afn1 );
2480     HeapFree( GetProcessHeap(), 0, afn2 );
2481     return res;
2482 }
2483
2484
2485 /**************************************************************************
2486  *           MoveFileA   (KERNEL32.@)
2487  *
2488  *  Move file or directory
2489  */
2490 BOOL WINAPI MoveFileA( LPCSTR fn1, LPCSTR fn2 )
2491 {
2492     DOS_FULL_NAME full_name1, full_name2;
2493     struct stat fstat;
2494
2495     TRACE("(%s,%s)\n", fn1, fn2 );
2496
2497     if (!DOSFS_GetFullName( fn1, TRUE, &full_name1 )) return FALSE;
2498     if (DOSFS_GetFullName( fn2, TRUE, &full_name2 ))  {
2499       /* The new name must not already exist */
2500       SetLastError(ERROR_ALREADY_EXISTS);
2501       return FALSE;
2502     }
2503     if (!DOSFS_GetFullName( fn2, FALSE, &full_name2 )) return FALSE;
2504
2505     if (full_name1.drive == full_name2.drive) /* move */
2506         return MoveFileExA( fn1, fn2, MOVEFILE_COPY_ALLOWED );
2507
2508     /* copy */
2509     if (stat( full_name1.long_name, &fstat ))
2510     {
2511         WARN("Invalid source file %s\n",
2512              full_name1.long_name);
2513         FILE_SetDosError();
2514         return FALSE;
2515     }
2516     if (S_ISDIR(fstat.st_mode)) {
2517         /* No Move for directories across file systems */
2518         /* FIXME: Use right error code */
2519         SetLastError( ERROR_GEN_FAILURE );
2520         return FALSE;
2521     }
2522     return CopyFileA(fn1, fn2, TRUE); /*fail, if exist */
2523 }
2524
2525
2526 /**************************************************************************
2527  *           MoveFileW   (KERNEL32.@)
2528  */
2529 BOOL WINAPI MoveFileW( LPCWSTR fn1, LPCWSTR fn2 )
2530 {
2531     LPSTR afn1 = HEAP_strdupWtoA( GetProcessHeap(), 0, fn1 );
2532     LPSTR afn2 = HEAP_strdupWtoA( GetProcessHeap(), 0, fn2 );
2533     BOOL res = MoveFileA( afn1, afn2 );
2534     HeapFree( GetProcessHeap(), 0, afn1 );
2535     HeapFree( GetProcessHeap(), 0, afn2 );
2536     return res;
2537 }
2538
2539
2540 /**************************************************************************
2541  *           CopyFileA   (KERNEL32.@)
2542  */
2543 BOOL WINAPI CopyFileA( LPCSTR source, LPCSTR dest, BOOL fail_if_exists )
2544 {
2545     HFILE h1, h2;
2546     BY_HANDLE_FILE_INFORMATION info;
2547     UINT count;
2548     BOOL ret = FALSE;
2549     int mode;
2550     char buffer[2048];
2551
2552     if ((h1 = _lopen( source, OF_READ )) == HFILE_ERROR) return FALSE;
2553     if (!GetFileInformationByHandle( h1, &info ))
2554     {
2555         CloseHandle( h1 );
2556         return FALSE;
2557     }
2558     mode = (info.dwFileAttributes & FILE_ATTRIBUTE_READONLY) ? 0444 : 0666;
2559     if ((h2 = CreateFileA( dest, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
2560                              fail_if_exists ? CREATE_NEW : CREATE_ALWAYS,
2561                              info.dwFileAttributes, h1 )) == INVALID_HANDLE_VALUE)
2562     {
2563         CloseHandle( h1 );
2564         return FALSE;
2565     }
2566     while ((count = _lread( h1, buffer, sizeof(buffer) )) > 0)
2567     {
2568         char *p = buffer;
2569         while (count > 0)
2570         {
2571             INT res = _lwrite( h2, p, count );
2572             if (res <= 0) goto done;
2573             p += res;
2574             count -= res;
2575         }
2576     }
2577     ret =  TRUE;
2578 done:
2579     CloseHandle( h1 );
2580     CloseHandle( h2 );
2581     return ret;
2582 }
2583
2584
2585 /**************************************************************************
2586  *           CopyFileW   (KERNEL32.@)
2587  */
2588 BOOL WINAPI CopyFileW( LPCWSTR source, LPCWSTR dest, BOOL fail_if_exists)
2589 {
2590     LPSTR sourceA = HEAP_strdupWtoA( GetProcessHeap(), 0, source );
2591     LPSTR destA   = HEAP_strdupWtoA( GetProcessHeap(), 0, dest );
2592     BOOL ret = CopyFileA( sourceA, destA, fail_if_exists );
2593     HeapFree( GetProcessHeap(), 0, sourceA );
2594     HeapFree( GetProcessHeap(), 0, destA );
2595     return ret;
2596 }
2597
2598
2599 /**************************************************************************
2600  *           CopyFileExA   (KERNEL32.@)
2601  *
2602  * This implementation ignores most of the extra parameters passed-in into
2603  * the "ex" version of the method and calls the CopyFile method.
2604  * It will have to be fixed eventually.
2605  */
2606 BOOL WINAPI CopyFileExA(LPCSTR             sourceFilename,
2607                            LPCSTR             destFilename,
2608                            LPPROGRESS_ROUTINE progressRoutine,
2609                            LPVOID             appData,
2610                            LPBOOL           cancelFlagPointer,
2611                            DWORD              copyFlags)
2612 {
2613   BOOL failIfExists = FALSE;
2614
2615   /*
2616    * Interpret the only flag that CopyFile can interpret.
2617    */
2618   if ( (copyFlags & COPY_FILE_FAIL_IF_EXISTS) != 0)
2619   {
2620     failIfExists = TRUE;
2621   }
2622
2623   return CopyFileA(sourceFilename, destFilename, failIfExists);
2624 }
2625
2626 /**************************************************************************
2627  *           CopyFileExW   (KERNEL32.@)
2628  */
2629 BOOL WINAPI CopyFileExW(LPCWSTR            sourceFilename,
2630                            LPCWSTR            destFilename,
2631                            LPPROGRESS_ROUTINE progressRoutine,
2632                            LPVOID             appData,
2633                            LPBOOL           cancelFlagPointer,
2634                            DWORD              copyFlags)
2635 {
2636     LPSTR sourceA = HEAP_strdupWtoA( GetProcessHeap(), 0, sourceFilename );
2637     LPSTR destA   = HEAP_strdupWtoA( GetProcessHeap(), 0, destFilename );
2638
2639     BOOL ret = CopyFileExA(sourceA,
2640                               destA,
2641                               progressRoutine,
2642                               appData,
2643                               cancelFlagPointer,
2644                               copyFlags);
2645
2646     HeapFree( GetProcessHeap(), 0, sourceA );
2647     HeapFree( GetProcessHeap(), 0, destA );
2648
2649     return ret;
2650 }
2651
2652
2653 /***********************************************************************
2654  *              SetFileTime   (KERNEL32.@)
2655  */
2656 BOOL WINAPI SetFileTime( HANDLE hFile,
2657                            const FILETIME *lpCreationTime,
2658                            const FILETIME *lpLastAccessTime,
2659                            const FILETIME *lpLastWriteTime )
2660 {
2661     BOOL ret;
2662     SERVER_START_REQ( set_file_time )
2663     {
2664         req->handle = hFile;
2665         if (lpLastAccessTime)
2666             RtlTimeToSecondsSince1970( lpLastAccessTime, (DWORD *)&req->access_time );
2667         else
2668             req->access_time = 0; /* FIXME */
2669         if (lpLastWriteTime)
2670             RtlTimeToSecondsSince1970( lpLastWriteTime, (DWORD *)&req->write_time );
2671         else
2672             req->write_time = 0; /* FIXME */
2673         ret = !wine_server_call_err( req );
2674     }
2675     SERVER_END_REQ;
2676     return ret;
2677 }
2678
2679
2680 /**************************************************************************
2681  *           LockFile   (KERNEL32.@)
2682  */
2683 BOOL WINAPI LockFile( HANDLE hFile, DWORD dwFileOffsetLow, DWORD dwFileOffsetHigh,
2684                         DWORD nNumberOfBytesToLockLow, DWORD nNumberOfBytesToLockHigh )
2685 {
2686     BOOL ret;
2687     SERVER_START_REQ( lock_file )
2688     {
2689         req->handle      = hFile;
2690         req->offset_low  = dwFileOffsetLow;
2691         req->offset_high = dwFileOffsetHigh;
2692         req->count_low   = nNumberOfBytesToLockLow;
2693         req->count_high  = nNumberOfBytesToLockHigh;
2694         ret = !wine_server_call_err( req );
2695     }
2696     SERVER_END_REQ;
2697     return ret;
2698 }
2699
2700 /**************************************************************************
2701  * LockFileEx [KERNEL32.@]
2702  *
2703  * Locks a byte range within an open file for shared or exclusive access.
2704  *
2705  * RETURNS
2706  *   success: TRUE
2707  *   failure: FALSE
2708  *
2709  * NOTES
2710  * Per Microsoft docs, the third parameter (reserved) must be set to 0.
2711  */
2712 BOOL WINAPI LockFileEx( HANDLE hFile, DWORD flags, DWORD reserved,
2713                       DWORD nNumberOfBytesToLockLow, DWORD nNumberOfBytesToLockHigh,
2714                       LPOVERLAPPED pOverlapped )
2715 {
2716     FIXME("hFile=%d,flags=%ld,reserved=%ld,lowbytes=%ld,highbytes=%ld,overlapped=%p: stub.\n",
2717           hFile, flags, reserved, nNumberOfBytesToLockLow, nNumberOfBytesToLockHigh,
2718           pOverlapped);
2719     if (reserved == 0)
2720         SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
2721     else
2722     {
2723         ERR("reserved == %ld: Supposed to be 0??\n", reserved);
2724         SetLastError(ERROR_INVALID_PARAMETER);
2725     }
2726
2727     return FALSE;
2728 }
2729
2730
2731 /**************************************************************************
2732  *           UnlockFile   (KERNEL32.@)
2733  */
2734 BOOL WINAPI UnlockFile( HANDLE hFile, DWORD dwFileOffsetLow, DWORD dwFileOffsetHigh,
2735                           DWORD nNumberOfBytesToUnlockLow, DWORD nNumberOfBytesToUnlockHigh )
2736 {
2737     BOOL ret;
2738     SERVER_START_REQ( unlock_file )
2739     {
2740         req->handle      = hFile;
2741         req->offset_low  = dwFileOffsetLow;
2742         req->offset_high = dwFileOffsetHigh;
2743         req->count_low   = nNumberOfBytesToUnlockLow;
2744         req->count_high  = nNumberOfBytesToUnlockHigh;
2745         ret = !wine_server_call_err( req );
2746     }
2747     SERVER_END_REQ;
2748     return ret;
2749 }
2750
2751
2752 /**************************************************************************
2753  *           UnlockFileEx   (KERNEL32.@)
2754  */
2755 BOOL WINAPI UnlockFileEx(
2756                 HFILE hFile,
2757                 DWORD dwReserved,
2758                 DWORD nNumberOfBytesToUnlockLow,
2759                 DWORD nNumberOfBytesToUnlockHigh,
2760                 LPOVERLAPPED lpOverlapped
2761 )
2762 {
2763         FIXME("hFile=%d,reserved=%ld,lowbytes=%ld,highbytes=%ld,overlapped=%p: stub.\n",
2764           hFile, dwReserved, nNumberOfBytesToUnlockLow, nNumberOfBytesToUnlockHigh,
2765           lpOverlapped);
2766         if (dwReserved == 0)
2767                 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
2768         else
2769         {
2770                 ERR("reserved == %ld: Supposed to be 0??\n", dwReserved);
2771                 SetLastError(ERROR_INVALID_PARAMETER);
2772         }
2773
2774         return FALSE;
2775 }
2776
2777
2778 #if 0
2779
2780 struct DOS_FILE_LOCK {
2781   struct DOS_FILE_LOCK *        next;
2782   DWORD                         base;
2783   DWORD                         len;
2784   DWORD                         processId;
2785   FILE_OBJECT *                 dos_file;
2786 /*  char *                      unix_name;*/
2787 };
2788
2789 typedef struct DOS_FILE_LOCK DOS_FILE_LOCK;
2790
2791 static DOS_FILE_LOCK *locks = NULL;
2792 static void DOS_RemoveFileLocks(FILE_OBJECT *file);
2793
2794
2795 /* Locks need to be mirrored because unix file locking is based
2796  * on the pid. Inside of wine there can be multiple WINE processes
2797  * that share the same unix pid.
2798  * Read's and writes should check these locks also - not sure
2799  * how critical that is at this point (FIXME).
2800  */
2801
2802 static BOOL DOS_AddLock(FILE_OBJECT *file, struct flock *f)
2803 {
2804   DOS_FILE_LOCK *curr;
2805   DWORD         processId;
2806
2807   processId = GetCurrentProcessId();
2808
2809   /* check if lock overlaps a current lock for the same file */
2810 #if 0
2811   for (curr = locks; curr; curr = curr->next) {
2812     if (strcmp(curr->unix_name, file->unix_name) == 0) {
2813       if ((f->l_start == curr->base) && (f->l_len == curr->len))
2814         return TRUE;/* region is identic */
2815       if ((f->l_start < (curr->base + curr->len)) &&
2816           ((f->l_start + f->l_len) > curr->base)) {
2817         /* region overlaps */
2818         return FALSE;
2819       }
2820     }
2821   }
2822 #endif
2823
2824   curr = HeapAlloc( GetProcessHeap(), 0, sizeof(DOS_FILE_LOCK) );
2825   curr->processId = GetCurrentProcessId();
2826   curr->base = f->l_start;
2827   curr->len = f->l_len;
2828 /*  curr->unix_name = HEAP_strdupA( GetProcessHeap(), 0, file->unix_name);*/
2829   curr->next = locks;
2830   curr->dos_file = file;
2831   locks = curr;
2832   return TRUE;
2833 }
2834
2835 static void DOS_RemoveFileLocks(FILE_OBJECT *file)
2836 {
2837   DWORD         processId;
2838   DOS_FILE_LOCK **curr;
2839   DOS_FILE_LOCK *rem;
2840
2841   processId = GetCurrentProcessId();
2842   curr = &locks;
2843   while (*curr) {
2844     if ((*curr)->dos_file == file) {
2845       rem = *curr;
2846       *curr = (*curr)->next;
2847 /*      HeapFree( GetProcessHeap(), 0, rem->unix_name );*/
2848       HeapFree( GetProcessHeap(), 0, rem );
2849     }
2850     else
2851       curr = &(*curr)->next;
2852   }
2853 }
2854
2855 static BOOL DOS_RemoveLock(FILE_OBJECT *file, struct flock *f)
2856 {
2857   DWORD         processId;
2858   DOS_FILE_LOCK **curr;
2859   DOS_FILE_LOCK *rem;
2860
2861   processId = GetCurrentProcessId();
2862   for (curr = &locks; *curr; curr = &(*curr)->next) {
2863     if ((*curr)->processId == processId &&
2864         (*curr)->dos_file == file &&
2865         (*curr)->base == f->l_start &&
2866         (*curr)->len == f->l_len) {
2867       /* this is the same lock */
2868       rem = *curr;
2869       *curr = (*curr)->next;
2870 /*      HeapFree( GetProcessHeap(), 0, rem->unix_name );*/
2871       HeapFree( GetProcessHeap(), 0, rem );
2872       return TRUE;
2873     }
2874   }
2875   /* no matching lock found */
2876   return FALSE;
2877 }
2878
2879
2880 /**************************************************************************
2881  *           LockFile   (KERNEL32.@)
2882  */
2883 BOOL WINAPI LockFile(
2884         HFILE hFile,DWORD dwFileOffsetLow,DWORD dwFileOffsetHigh,
2885         DWORD nNumberOfBytesToLockLow,DWORD nNumberOfBytesToLockHigh )
2886 {
2887   struct flock f;
2888   FILE_OBJECT *file;
2889
2890   TRACE("handle %d offsetlow=%ld offsethigh=%ld nbyteslow=%ld nbyteshigh=%ld\n",
2891                hFile, dwFileOffsetLow, dwFileOffsetHigh,
2892                nNumberOfBytesToLockLow, nNumberOfBytesToLockHigh);
2893
2894   if (dwFileOffsetHigh || nNumberOfBytesToLockHigh) {
2895     FIXME("Unimplemented bytes > 32bits\n");
2896     return FALSE;
2897   }
2898
2899   f.l_start = dwFileOffsetLow;
2900   f.l_len = nNumberOfBytesToLockLow;
2901   f.l_whence = SEEK_SET;
2902   f.l_pid = 0;
2903   f.l_type = F_WRLCK;
2904
2905   if (!(file = FILE_GetFile(hFile,0,NULL))) return FALSE;
2906
2907   /* shadow locks internally */
2908   if (!DOS_AddLock(file, &f)) {
2909     SetLastError( ERROR_LOCK_VIOLATION );
2910     return FALSE;
2911   }
2912
2913   /* FIXME: Unix locking commented out for now, doesn't work with Excel */
2914 #ifdef USE_UNIX_LOCKS
2915   if (fcntl(file->unix_handle, F_SETLK, &f) == -1) {
2916     if (errno == EACCES || errno == EAGAIN) {
2917       SetLastError( ERROR_LOCK_VIOLATION );
2918     }
2919     else {
2920       FILE_SetDosError();
2921     }
2922     /* remove our internal copy of the lock */
2923     DOS_RemoveLock(file, &f);
2924     return FALSE;
2925   }
2926 #endif
2927   return TRUE;
2928 }
2929
2930
2931 /**************************************************************************
2932  *           UnlockFile   (KERNEL32.@)
2933  */
2934 BOOL WINAPI UnlockFile(
2935         HFILE hFile,DWORD dwFileOffsetLow,DWORD dwFileOffsetHigh,
2936         DWORD nNumberOfBytesToUnlockLow,DWORD nNumberOfBytesToUnlockHigh )
2937 {
2938   FILE_OBJECT *file;
2939   struct flock f;
2940
2941   TRACE("handle %d offsetlow=%ld offsethigh=%ld nbyteslow=%ld nbyteshigh=%ld\n",
2942                hFile, dwFileOffsetLow, dwFileOffsetHigh,
2943                nNumberOfBytesToUnlockLow, nNumberOfBytesToUnlockHigh);
2944
2945   if (dwFileOffsetHigh || nNumberOfBytesToUnlockHigh) {
2946     WARN("Unimplemented bytes > 32bits\n");
2947     return FALSE;
2948   }
2949
2950   f.l_start = dwFileOffsetLow;
2951   f.l_len = nNumberOfBytesToUnlockLow;
2952   f.l_whence = SEEK_SET;
2953   f.l_pid = 0;
2954   f.l_type = F_UNLCK;
2955
2956   if (!(file = FILE_GetFile(hFile,0,NULL))) return FALSE;
2957
2958   DOS_RemoveLock(file, &f);     /* ok if fails - may be another wine */
2959
2960   /* FIXME: Unix locking commented out for now, doesn't work with Excel */
2961 #ifdef USE_UNIX_LOCKS
2962   if (fcntl(file->unix_handle, F_SETLK, &f) == -1) {
2963     FILE_SetDosError();
2964     return FALSE;
2965   }
2966 #endif
2967   return TRUE;
2968 }
2969 #endif
2970
2971 /**************************************************************************
2972  * GetFileAttributesExA [KERNEL32.@]
2973  */
2974 BOOL WINAPI GetFileAttributesExA(
2975         LPCSTR lpFileName, GET_FILEEX_INFO_LEVELS fInfoLevelId,
2976         LPVOID lpFileInformation)
2977 {
2978     DOS_FULL_NAME full_name;
2979     BY_HANDLE_FILE_INFORMATION info;
2980
2981     if (lpFileName == NULL) return FALSE;
2982     if (lpFileInformation == NULL) return FALSE;
2983
2984     if (fInfoLevelId == GetFileExInfoStandard) {
2985         LPWIN32_FILE_ATTRIBUTE_DATA lpFad =
2986             (LPWIN32_FILE_ATTRIBUTE_DATA) lpFileInformation;
2987         if (!DOSFS_GetFullName( lpFileName, TRUE, &full_name )) return FALSE;
2988         if (!FILE_Stat( full_name.long_name, &info )) return FALSE;
2989
2990         lpFad->dwFileAttributes = info.dwFileAttributes;
2991         lpFad->ftCreationTime   = info.ftCreationTime;
2992         lpFad->ftLastAccessTime = info.ftLastAccessTime;
2993         lpFad->ftLastWriteTime  = info.ftLastWriteTime;
2994         lpFad->nFileSizeHigh    = info.nFileSizeHigh;
2995         lpFad->nFileSizeLow     = info.nFileSizeLow;
2996     }
2997     else {
2998         FIXME("invalid info level %d!\n", fInfoLevelId);
2999         return FALSE;
3000     }
3001
3002     return TRUE;
3003 }
3004
3005
3006 /**************************************************************************
3007  * GetFileAttributesExW [KERNEL32.@]
3008  */
3009 BOOL WINAPI GetFileAttributesExW(
3010         LPCWSTR lpFileName, GET_FILEEX_INFO_LEVELS fInfoLevelId,
3011         LPVOID lpFileInformation)
3012 {
3013     LPSTR nameA = HEAP_strdupWtoA( GetProcessHeap(), 0, lpFileName );
3014     BOOL res =
3015         GetFileAttributesExA( nameA, fInfoLevelId, lpFileInformation);
3016     HeapFree( GetProcessHeap(), 0, nameA );
3017     return res;
3018 }