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