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