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