Fixed mismatches between the Wine headers and the Microsoft headers.
[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 (ofs->Reserved1 != filedatetime[0] || ofs->Reserved2 != filedatetime[1] )
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     ofs->Reserved1 = filedatetime[0];
1339     ofs->Reserved2 = filedatetime[1];
1340
1341 success:  /* We get here if the open was successful */
1342     TRACE("(%s): OK, return = %x\n", name, handle );
1343     if (win32)
1344     {
1345         hFileRet = (HFILE)handle;
1346         if (mode & OF_EXIST) /* Return the handle, but close it first */
1347             CloseHandle( handle );
1348     }
1349     else
1350     {
1351         hFileRet = Win32HandleToDosFileHandle( handle );
1352         if (hFileRet == HFILE_ERROR16) goto error;
1353         if (mode & OF_EXIST) /* Return the handle, but close it first */
1354             _lclose16( hFileRet );
1355     }
1356     return hFileRet;
1357
1358 not_found:  /* We get here if the file does not exist */
1359     WARN("'%s' not found or sharing violation\n", name );
1360     SetLastError( ERROR_FILE_NOT_FOUND );
1361     /* fall through */
1362
1363 error:  /* We get here if there was an error opening the file */
1364     ofs->nErrCode = GetLastError();
1365     WARN("(%s): return = HFILE_ERROR error= %d\n",
1366                   name,ofs->nErrCode );
1367     return HFILE_ERROR;
1368 }
1369
1370
1371 /***********************************************************************
1372  *           OpenFile   (KERNEL.74)
1373  *           OpenFileEx (KERNEL.360)
1374  */
1375 HFILE16 WINAPI OpenFile16( LPCSTR name, OFSTRUCT *ofs, UINT16 mode )
1376 {
1377     return FILE_DoOpenFile( name, ofs, mode, FALSE );
1378 }
1379
1380
1381 /***********************************************************************
1382  *           OpenFile   (KERNEL32.@)
1383  */
1384 HFILE WINAPI OpenFile( LPCSTR name, OFSTRUCT *ofs, UINT mode )
1385 {
1386     return FILE_DoOpenFile( name, ofs, mode, TRUE );
1387 }
1388
1389
1390 /***********************************************************************
1391  *           FILE_InitProcessDosHandles
1392  *
1393  * Allocates the default DOS handles for a process. Called either by
1394  * Win32HandleToDosFileHandle below or by the DOSVM stuff.
1395  */
1396 static void FILE_InitProcessDosHandles( void )
1397 {
1398     HANDLE cp = GetCurrentProcess();
1399     DuplicateHandle(cp, GetStdHandle(STD_INPUT_HANDLE), cp, &dos_handles[0],
1400                     0, TRUE, DUPLICATE_SAME_ACCESS);
1401     DuplicateHandle(cp, GetStdHandle(STD_OUTPUT_HANDLE), cp, &dos_handles[1],
1402                     0, TRUE, DUPLICATE_SAME_ACCESS);
1403     DuplicateHandle(cp, GetStdHandle(STD_ERROR_HANDLE), cp, &dos_handles[2],
1404                     0, TRUE, DUPLICATE_SAME_ACCESS);
1405     DuplicateHandle(cp, GetStdHandle(STD_ERROR_HANDLE), cp, &dos_handles[3],
1406                     0, TRUE, DUPLICATE_SAME_ACCESS);
1407     DuplicateHandle(cp, GetStdHandle(STD_ERROR_HANDLE), cp, &dos_handles[4],
1408                     0, TRUE, DUPLICATE_SAME_ACCESS);
1409 }
1410
1411 /***********************************************************************
1412  *           Win32HandleToDosFileHandle   (KERNEL32.21)
1413  *
1414  * Allocate a DOS handle for a Win32 handle. The Win32 handle is no
1415  * longer valid after this function (even on failure).
1416  *
1417  * Note: this is not exactly right, since on Win95 the Win32 handles
1418  *       are on top of DOS handles and we do it the other way
1419  *       around. Should be good enough though.
1420  */
1421 HFILE WINAPI Win32HandleToDosFileHandle( HANDLE handle )
1422 {
1423     int i;
1424
1425     if (!handle || (handle == INVALID_HANDLE_VALUE))
1426         return HFILE_ERROR;
1427
1428     for (i = 5; i < DOS_TABLE_SIZE; i++)
1429         if (!dos_handles[i])
1430         {
1431             dos_handles[i] = handle;
1432             TRACE("Got %d for h32 %d\n", i, handle );
1433             return (HFILE)i;
1434         }
1435     CloseHandle( handle );
1436     SetLastError( ERROR_TOO_MANY_OPEN_FILES );
1437     return HFILE_ERROR;
1438 }
1439
1440
1441 /***********************************************************************
1442  *           DosFileHandleToWin32Handle   (KERNEL32.20)
1443  *
1444  * Return the Win32 handle for a DOS handle.
1445  *
1446  * Note: this is not exactly right, since on Win95 the Win32 handles
1447  *       are on top of DOS handles and we do it the other way
1448  *       around. Should be good enough though.
1449  */
1450 HANDLE WINAPI DosFileHandleToWin32Handle( HFILE handle )
1451 {
1452     HFILE16 hfile = (HFILE16)handle;
1453     if (hfile < 5 && !dos_handles[hfile]) FILE_InitProcessDosHandles();
1454     if ((hfile >= DOS_TABLE_SIZE) || !dos_handles[hfile])
1455     {
1456         SetLastError( ERROR_INVALID_HANDLE );
1457         return INVALID_HANDLE_VALUE;
1458     }
1459     return dos_handles[hfile];
1460 }
1461
1462
1463 /***********************************************************************
1464  *           DisposeLZ32Handle   (KERNEL32.22)
1465  *
1466  * Note: this is not entirely correct, we should only close the
1467  *       32-bit handle and not the 16-bit one, but we cannot do
1468  *       this because of the way our DOS handles are implemented.
1469  *       It shouldn't break anything though.
1470  */
1471 void WINAPI DisposeLZ32Handle( HANDLE handle )
1472 {
1473     int i;
1474
1475     if (!handle || (handle == INVALID_HANDLE_VALUE)) return;
1476
1477     for (i = 5; i < DOS_TABLE_SIZE; i++)
1478         if (dos_handles[i] == handle)
1479         {
1480             dos_handles[i] = 0;
1481             CloseHandle( handle );
1482             break;
1483         }
1484 }
1485
1486
1487 /***********************************************************************
1488  *           FILE_Dup2
1489  *
1490  * dup2() function for DOS handles.
1491  */
1492 HFILE16 FILE_Dup2( HFILE16 hFile1, HFILE16 hFile2 )
1493 {
1494     HANDLE new_handle;
1495
1496     if (hFile1 < 5 && !dos_handles[hFile1]) FILE_InitProcessDosHandles();
1497
1498     if ((hFile1 >= DOS_TABLE_SIZE) || (hFile2 >= DOS_TABLE_SIZE) || !dos_handles[hFile1])
1499     {
1500         SetLastError( ERROR_INVALID_HANDLE );
1501         return HFILE_ERROR16;
1502     }
1503     if (!DuplicateHandle( GetCurrentProcess(), dos_handles[hFile1],
1504                           GetCurrentProcess(), &new_handle,
1505                           0, FALSE, DUPLICATE_SAME_ACCESS ))
1506         return HFILE_ERROR16;
1507     if (dos_handles[hFile2]) CloseHandle( dos_handles[hFile2] );
1508     dos_handles[hFile2] = new_handle;
1509     return hFile2;
1510 }
1511
1512
1513 /***********************************************************************
1514  *           _lclose   (KERNEL.81)
1515  */
1516 HFILE16 WINAPI _lclose16( HFILE16 hFile )
1517 {
1518     if ((hFile >= DOS_TABLE_SIZE) || !dos_handles[hFile])
1519     {
1520         SetLastError( ERROR_INVALID_HANDLE );
1521         return HFILE_ERROR16;
1522     }
1523     TRACE("%d (handle32=%d)\n", hFile, dos_handles[hFile] );
1524     CloseHandle( dos_handles[hFile] );
1525     dos_handles[hFile] = 0;
1526     return 0;
1527 }
1528
1529
1530 /***********************************************************************
1531  *           _lclose   (KERNEL32.@)
1532  */
1533 HFILE WINAPI _lclose( HFILE hFile )
1534 {
1535     TRACE("handle %d\n", hFile );
1536     return CloseHandle( (HANDLE)hFile ) ? 0 : HFILE_ERROR;
1537 }
1538
1539 /***********************************************************************
1540  *              GetOverlappedResult     (KERNEL32.@)
1541  *
1542  * Check the result of an Asynchronous data transfer from a file.
1543  *
1544  * RETURNS
1545  *   TRUE on success
1546  *   FALSE on failure
1547  *
1548  *  If successful (and relevant) lpTransferred will hold the number of
1549  *   bytes transferred during the async operation.
1550  *
1551  * BUGS
1552  *
1553  * Currently only works for WaitCommEvent, ReadFile, WriteFile
1554  *   with communications ports.
1555  *
1556  */
1557 BOOL WINAPI GetOverlappedResult(
1558     HANDLE hFile,              /* [in] handle of file to check on */
1559     LPOVERLAPPED lpOverlapped, /* [in/out] pointer to overlapped  */
1560     LPDWORD lpTransferred,     /* [in/out] number of bytes transferred  */
1561     BOOL bWait                 /* [in] wait for the transfer to complete ? */
1562 ) {
1563     DWORD r;
1564
1565     TRACE("(%d %p %p %x)\n", hFile, lpOverlapped, lpTransferred, bWait);
1566
1567     if(lpOverlapped==NULL)
1568     {
1569         ERR("lpOverlapped was null\n");
1570         return FALSE;
1571     }
1572     if(!lpOverlapped->hEvent)
1573     {
1574         ERR("lpOverlapped->hEvent was null\n");
1575         return FALSE;
1576     }
1577
1578     if ( bWait )
1579     {
1580         do {
1581             TRACE("waiting on %p\n",lpOverlapped);
1582             r = WaitForSingleObjectEx(lpOverlapped->hEvent, INFINITE, TRUE);
1583             TRACE("wait on %p returned %ld\n",lpOverlapped,r);
1584         } while (r==STATUS_USER_APC);
1585     }
1586     else if ( lpOverlapped->Internal == STATUS_PENDING )
1587     {
1588         /* Wait in order to give APCs a chance to run. */
1589         /* This is cheating, so we must set the event again in case of success -
1590            it may be a non-manual reset event. */
1591         do {
1592             TRACE("waiting on %p\n",lpOverlapped);
1593             r = WaitForSingleObjectEx(lpOverlapped->hEvent, 0, TRUE);
1594             TRACE("wait on %p returned %ld\n",lpOverlapped,r);
1595         } while (r==STATUS_USER_APC);
1596         if ( r == WAIT_OBJECT_0 )
1597             NtSetEvent ( lpOverlapped->hEvent, NULL );
1598     }
1599
1600     if(lpTransferred)
1601         *lpTransferred = lpOverlapped->InternalHigh;
1602
1603     switch ( lpOverlapped->Internal )
1604     {
1605     case STATUS_SUCCESS:
1606         return TRUE;
1607     case STATUS_PENDING:
1608         SetLastError ( ERROR_IO_INCOMPLETE );
1609         if ( bWait ) ERR ("PENDING status after waiting!\n");
1610         return FALSE;
1611     default:
1612         SetLastError ( RtlNtStatusToDosError ( lpOverlapped->Internal ) );
1613         return FALSE;
1614     }
1615 }
1616
1617 /***********************************************************************
1618  *             CancelIo                   (KERNEL32.@)
1619  */
1620 BOOL WINAPI CancelIo(HANDLE handle)
1621 {
1622     async_private *ovp,*t;
1623
1624     TRACE("handle = %x\n",handle);
1625
1626     for (ovp = NtCurrentTeb()->pending_list; ovp; ovp = t)
1627     {
1628         t = ovp->next;
1629         if ( ovp->handle == handle )
1630              cancel_async ( ovp );
1631     }
1632     WaitForMultipleObjectsEx(0,NULL,FALSE,1,TRUE);
1633     return TRUE;
1634 }
1635
1636 /***********************************************************************
1637  *             FILE_AsyncReadService      (INTERNAL)
1638  *
1639  *  This function is called while the client is waiting on the
1640  *  server, so we can't make any server calls here.
1641  */
1642 static void FILE_AsyncReadService(async_private *ovp)
1643 {
1644     async_fileio *fileio = (async_fileio*) ovp;
1645     LPOVERLAPPED lpOverlapped = fileio->lpOverlapped;
1646     int result, r;
1647     int already = lpOverlapped->InternalHigh;
1648
1649     TRACE("%p %p\n", lpOverlapped, fileio->buffer );
1650
1651     /* check to see if the data is ready (non-blocking) */
1652
1653     if ( fileio->fd_type == FD_TYPE_SOCKET )
1654         result = read (ovp->fd, &fileio->buffer[already], fileio->count - already);
1655     else
1656     {
1657         result = pread (ovp->fd, &fileio->buffer[already], fileio->count - already,
1658                         OVERLAPPED_OFFSET (lpOverlapped) + already);
1659         if ((result < 0) && (errno == ESPIPE))
1660             result = read (ovp->fd, &fileio->buffer[already], fileio->count - already);
1661     }
1662
1663     if ( (result<0) && ((errno == EAGAIN) || (errno == EINTR)))
1664     {
1665         TRACE("Deferred read %d\n",errno);
1666         r = STATUS_PENDING;
1667         goto async_end;
1668     }
1669
1670     /* check to see if the transfer is complete */
1671     if(result<0)
1672     {
1673         r = FILE_GetNtStatus ();
1674         goto async_end;
1675     }
1676
1677     lpOverlapped->InternalHigh += result;
1678     TRACE("read %d more bytes %ld/%d so far\n",result,lpOverlapped->InternalHigh,fileio->count);
1679
1680     if(lpOverlapped->InternalHigh >= fileio->count || fileio->fd_type == FD_TYPE_SOCKET )
1681         r = STATUS_SUCCESS;
1682     else
1683         r = STATUS_PENDING;
1684
1685 async_end:
1686     lpOverlapped->Internal = r;
1687 }
1688
1689 /***********************************************************************
1690  *              FILE_ReadFileEx                (INTERNAL)
1691  */
1692 static BOOL FILE_ReadFileEx(HANDLE hFile, LPVOID buffer, DWORD bytesToRead,
1693                          LPOVERLAPPED overlapped,
1694                          LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine,
1695                          HANDLE hEvent)
1696 {
1697     async_fileio *ovp;
1698     int fd;
1699     int flags;
1700     enum fd_type type;
1701
1702     TRACE("file %d to buf %p num %ld %p func %p\n",
1703           hFile, buffer, bytesToRead, overlapped, lpCompletionRoutine);
1704
1705     /* check that there is an overlapped struct */
1706     if (overlapped==NULL)
1707     {
1708         SetLastError(ERROR_INVALID_PARAMETER);
1709         return FALSE;
1710     }
1711
1712     fd = FILE_GetUnixHandleType ( hFile, GENERIC_READ, &type, &flags);
1713     if ( fd < 0 )
1714     {
1715         WARN ( "Couldn't get FD\n" );
1716         return FALSE;
1717     }
1718
1719     ovp = (async_fileio*) HeapAlloc(GetProcessHeap(), 0, sizeof (async_fileio));
1720     if(!ovp)
1721     {
1722         TRACE("HeapAlloc Failed\n");
1723         SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1724         goto error;
1725     }
1726
1727     ovp->async.ops = ( lpCompletionRoutine ? &fileio_async_ops : &fileio_nocomp_async_ops );
1728     ovp->async.handle = hFile;
1729     ovp->async.fd = fd;
1730     ovp->async.type = ASYNC_TYPE_READ;
1731     ovp->async.func = FILE_AsyncReadService;
1732     ovp->async.event = hEvent;
1733     ovp->lpOverlapped = overlapped;
1734     ovp->count = bytesToRead;
1735     ovp->completion_func = lpCompletionRoutine;
1736     ovp->buffer = buffer;
1737     ovp->fd_type = type;
1738
1739     return !register_new_async (&ovp->async);
1740
1741 error:
1742     close (fd);
1743     return FALSE;
1744
1745 }
1746
1747 /***********************************************************************
1748  *              ReadFileEx                (KERNEL32.@)
1749  */
1750 BOOL WINAPI ReadFileEx(HANDLE hFile, LPVOID buffer, DWORD bytesToRead,
1751                          LPOVERLAPPED overlapped,
1752                          LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine)
1753 {
1754     overlapped->InternalHigh = 0;
1755     return FILE_ReadFileEx(hFile,buffer,bytesToRead,overlapped,lpCompletionRoutine, INVALID_HANDLE_VALUE);
1756 }
1757
1758 static BOOL FILE_TimeoutRead(HANDLE hFile, LPVOID buffer, DWORD bytesToRead, LPDWORD bytesRead)
1759 {
1760     OVERLAPPED ov;
1761     BOOL r = FALSE;
1762
1763     TRACE("%d %p %ld %p\n", hFile, buffer, bytesToRead, bytesRead );
1764
1765     ZeroMemory(&ov, sizeof (OVERLAPPED));
1766     if(STATUS_SUCCESS==NtCreateEvent(&ov.hEvent, SYNCHRONIZE, NULL, 0, 0))
1767     {
1768         if(FILE_ReadFileEx(hFile, buffer, bytesToRead, &ov, NULL, ov.hEvent))
1769         {
1770             r = GetOverlappedResult(hFile, &ov, bytesRead, TRUE);
1771         }
1772     }
1773     CloseHandle(ov.hEvent);
1774     return r;
1775 }
1776
1777 /***********************************************************************
1778  *              ReadFile                (KERNEL32.@)
1779  */
1780 BOOL WINAPI ReadFile( HANDLE hFile, LPVOID buffer, DWORD bytesToRead,
1781                         LPDWORD bytesRead, LPOVERLAPPED overlapped )
1782 {
1783     int unix_handle, result, flags;
1784     enum fd_type type;
1785
1786     TRACE("%d %p %ld %p %p\n", hFile, buffer, bytesToRead,
1787           bytesRead, overlapped );
1788
1789     if (bytesRead) *bytesRead = 0;  /* Do this before anything else */
1790     if (!bytesToRead) return TRUE;
1791
1792     unix_handle = FILE_GetUnixHandleType( hFile, GENERIC_READ, &type, &flags );
1793
1794     if (flags & FD_FLAG_OVERLAPPED)
1795     {
1796         if (unix_handle == -1) return FALSE;
1797         if ( (overlapped==NULL) || NtResetEvent( overlapped->hEvent, NULL ) )
1798         {
1799             TRACE("Overlapped not specified or invalid event flag\n");
1800             close(unix_handle);
1801             SetLastError(ERROR_INVALID_PARAMETER);
1802             return FALSE;
1803         }
1804
1805         close(unix_handle);
1806         overlapped->InternalHigh = 0;
1807
1808         if(!FILE_ReadFileEx(hFile, buffer, bytesToRead, overlapped, NULL, overlapped->hEvent))
1809             return FALSE;
1810
1811         if ( !GetOverlappedResult (hFile, overlapped, bytesRead, FALSE) )
1812         {
1813             if ( GetLastError() == ERROR_IO_INCOMPLETE )
1814                 SetLastError ( ERROR_IO_PENDING );
1815             return FALSE;
1816         }
1817
1818         return TRUE;
1819     }
1820     if (flags & FD_FLAG_TIMEOUT)
1821     {
1822         close(unix_handle);
1823         return FILE_TimeoutRead(hFile, buffer, bytesToRead, bytesRead);
1824     }
1825     switch(type)
1826     {
1827     case FD_TYPE_SMB:
1828         return SMB_ReadFile(hFile, buffer, bytesToRead, bytesRead, NULL);
1829
1830     case FD_TYPE_CONSOLE:
1831         return FILE_ReadConsole(hFile, buffer, bytesToRead, bytesRead, NULL);
1832
1833     case FD_TYPE_DEFAULT:
1834         /* normal unix files */
1835         if (unix_handle == -1) return FALSE;
1836         if (overlapped)
1837         {
1838             DWORD highOffset = overlapped->OffsetHigh;
1839             if ( (INVALID_SET_FILE_POINTER == SetFilePointer(hFile, overlapped->Offset,
1840                                                              &highOffset, FILE_BEGIN)) &&
1841                  (GetLastError() != NO_ERROR) )
1842             {
1843               close(unix_handle);
1844               return FALSE;
1845             }
1846         }
1847         break;
1848
1849     default:
1850         if (unix_handle == -1)
1851             return FALSE;
1852     }
1853
1854     if(overlapped)
1855     {
1856         off_t offset = OVERLAPPED_OFFSET(overlapped);
1857         if(lseek(unix_handle, offset, SEEK_SET) == -1)
1858         {
1859             close(unix_handle);
1860             SetLastError(ERROR_INVALID_PARAMETER);
1861             return FALSE;
1862         }
1863     }
1864
1865     /* code for synchronous reads */
1866     while ((result = read( unix_handle, buffer, bytesToRead )) == -1)
1867     {
1868         if ((errno == EAGAIN) || (errno == EINTR)) continue;
1869         if ((errno == EFAULT) && !IsBadWritePtr( buffer, bytesToRead )) continue;
1870         FILE_SetDosError();
1871         break;
1872     }
1873     close( unix_handle );
1874     if (result == -1) return FALSE;
1875     if (bytesRead) *bytesRead = result;
1876     return TRUE;
1877 }
1878
1879
1880 /***********************************************************************
1881  *             FILE_AsyncWriteService      (INTERNAL)
1882  *
1883  *  This function is called while the client is waiting on the
1884  *  server, so we can't make any server calls here.
1885  */
1886 static void FILE_AsyncWriteService(struct async_private *ovp)
1887 {
1888     async_fileio *fileio = (async_fileio *) ovp;
1889     LPOVERLAPPED lpOverlapped = fileio->lpOverlapped;
1890     int result, r;
1891     int already = lpOverlapped->InternalHigh;
1892
1893     TRACE("(%p %p)\n",lpOverlapped,fileio->buffer);
1894
1895     /* write some data (non-blocking) */
1896
1897     if ( fileio->fd_type == FD_TYPE_SOCKET )
1898         result = write(ovp->fd, &fileio->buffer[already], fileio->count - already);
1899     else
1900     {
1901         result = pwrite(ovp->fd, &fileio->buffer[already], fileio->count - already,
1902                     OVERLAPPED_OFFSET (lpOverlapped) + already);
1903         if ((result < 0) && (errno == ESPIPE))
1904             result = write(ovp->fd, &fileio->buffer[already], fileio->count - already);
1905     }
1906
1907     if ( (result<0) && ((errno == EAGAIN) || (errno == EINTR)))
1908     {
1909         r = STATUS_PENDING;
1910         goto async_end;
1911     }
1912
1913     /* check to see if the transfer is complete */
1914     if(result<0)
1915     {
1916         r = FILE_GetNtStatus ();
1917         goto async_end;
1918     }
1919
1920     lpOverlapped->InternalHigh += result;
1921
1922     TRACE("wrote %d more bytes %ld/%d so far\n",result,lpOverlapped->InternalHigh,fileio->count);
1923
1924     if(lpOverlapped->InternalHigh < fileio->count)
1925         r = STATUS_PENDING;
1926     else
1927         r = STATUS_SUCCESS;
1928
1929 async_end:
1930     lpOverlapped->Internal = r;
1931 }
1932
1933 /***********************************************************************
1934  *              FILE_WriteFileEx
1935  */
1936 static BOOL FILE_WriteFileEx(HANDLE hFile, LPCVOID buffer, DWORD bytesToWrite,
1937                              LPOVERLAPPED overlapped,
1938                              LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine,
1939                              HANDLE hEvent)
1940 {
1941     async_fileio *ovp;
1942     int fd;
1943     int flags;
1944     enum fd_type type;
1945
1946     TRACE("file %d to buf %p num %ld %p func %p handle %d\n",
1947           hFile, buffer, bytesToWrite, overlapped, lpCompletionRoutine, hEvent);
1948
1949     if (overlapped == NULL)
1950     {
1951         SetLastError(ERROR_INVALID_PARAMETER);
1952         return FALSE;
1953     }
1954
1955     fd = FILE_GetUnixHandleType ( hFile, GENERIC_WRITE, &type, &flags );
1956     if ( fd < 0 )
1957     {
1958         TRACE( "Couldn't get FD\n" );
1959         return FALSE;
1960     }
1961
1962     ovp = (async_fileio*) HeapAlloc(GetProcessHeap(), 0, sizeof (async_fileio));
1963     if(!ovp)
1964     {
1965         TRACE("HeapAlloc Failed\n");
1966         SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1967         goto error;
1968     }
1969
1970     ovp->async.ops = ( lpCompletionRoutine ? &fileio_async_ops : &fileio_nocomp_async_ops );
1971     ovp->async.handle = hFile;
1972     ovp->async.fd = fd;
1973     ovp->async.type = ASYNC_TYPE_WRITE;
1974     ovp->async.func = FILE_AsyncWriteService;
1975     ovp->lpOverlapped = overlapped;
1976     ovp->async.event = hEvent;
1977     ovp->buffer = (LPVOID) buffer;
1978     ovp->count = bytesToWrite;
1979     ovp->completion_func = lpCompletionRoutine;
1980     ovp->fd_type = type;
1981
1982     return !register_new_async (&ovp->async);
1983
1984 error:
1985     close (fd);
1986     return FALSE;
1987 }
1988
1989 /***********************************************************************
1990  *              WriteFileEx                (KERNEL32.@)
1991  */
1992 BOOL WINAPI WriteFileEx(HANDLE hFile, LPCVOID buffer, DWORD bytesToWrite,
1993                          LPOVERLAPPED overlapped,
1994                          LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine)
1995 {
1996     overlapped->InternalHigh = 0;
1997
1998     return FILE_WriteFileEx(hFile, buffer, bytesToWrite, overlapped, lpCompletionRoutine, INVALID_HANDLE_VALUE);
1999 }
2000
2001 /***********************************************************************
2002  *             WriteFile               (KERNEL32.@)
2003  */
2004 BOOL WINAPI WriteFile( HANDLE hFile, LPCVOID buffer, DWORD bytesToWrite,
2005                          LPDWORD bytesWritten, LPOVERLAPPED overlapped )
2006 {
2007     int unix_handle, result, flags;
2008     enum fd_type type;
2009
2010     TRACE("%d %p %ld %p %p\n", hFile, buffer, bytesToWrite,
2011           bytesWritten, overlapped );
2012
2013     if (bytesWritten) *bytesWritten = 0;  /* Do this before anything else */
2014     if (!bytesToWrite) return TRUE;
2015
2016     unix_handle = FILE_GetUnixHandleType( hFile, GENERIC_WRITE, &type, &flags );
2017
2018     if (flags & FD_FLAG_OVERLAPPED)
2019     {
2020         if (unix_handle == -1) return FALSE;
2021         if ( (overlapped==NULL) || NtResetEvent( overlapped->hEvent, NULL ) )
2022         {
2023             TRACE("Overlapped not specified or invalid event flag\n");
2024             close(unix_handle);
2025             SetLastError(ERROR_INVALID_PARAMETER);
2026             return FALSE;
2027         }
2028
2029         close(unix_handle);
2030         overlapped->InternalHigh = 0;
2031
2032         if(!FILE_WriteFileEx(hFile, buffer, bytesToWrite, overlapped, NULL, overlapped->hEvent))
2033             return FALSE;
2034
2035         if ( !GetOverlappedResult (hFile, overlapped, bytesWritten, FALSE) )
2036         {
2037             if ( GetLastError() == ERROR_IO_INCOMPLETE )
2038                 SetLastError ( ERROR_IO_PENDING );
2039             return FALSE;
2040         }
2041
2042         return TRUE;
2043     }
2044
2045     switch(type)
2046     {
2047     case FD_TYPE_CONSOLE:
2048         TRACE("%d %s %ld %p %p\n", hFile, debugstr_an(buffer, bytesToWrite), bytesToWrite,
2049               bytesWritten, overlapped );
2050         return FILE_WriteConsole(hFile, buffer, bytesToWrite, bytesWritten, NULL);
2051
2052     case FD_TYPE_DEFAULT:
2053         if (unix_handle == -1) return FALSE;
2054
2055         if(overlapped)
2056         {
2057             DWORD highOffset = overlapped->OffsetHigh;
2058             if ( (INVALID_SET_FILE_POINTER == SetFilePointer(hFile, overlapped->Offset,
2059                                                              &highOffset, FILE_BEGIN)) &&
2060                  (GetLastError() != NO_ERROR) )
2061             {
2062               close(unix_handle);
2063               return FALSE;
2064             }
2065         }
2066         break;
2067
2068     default:
2069         if (unix_handle == -1)
2070             return FALSE;
2071         if (overlapped)
2072         {
2073             close(unix_handle);
2074             SetLastError(ERROR_INVALID_PARAMETER);
2075             return FALSE;
2076         }
2077         break;
2078     }
2079
2080     if(overlapped)
2081     {
2082         off_t offset = OVERLAPPED_OFFSET(overlapped);
2083         if(lseek(unix_handle, offset, SEEK_SET) == -1)
2084         {
2085             close(unix_handle);
2086             SetLastError(ERROR_INVALID_PARAMETER);
2087             return FALSE;
2088         }
2089     }
2090
2091     /* synchronous file write */
2092     while ((result = write( unix_handle, buffer, bytesToWrite )) == -1)
2093     {
2094         if ((errno == EAGAIN) || (errno == EINTR)) continue;
2095         if ((errno == EFAULT) && !IsBadReadPtr( buffer, bytesToWrite )) continue;
2096         if (errno == ENOSPC)
2097             SetLastError( ERROR_DISK_FULL );
2098         else
2099         FILE_SetDosError();
2100         break;
2101     }
2102     close( unix_handle );
2103     if (result == -1) return FALSE;
2104     if (bytesWritten) *bytesWritten = result;
2105     return TRUE;
2106 }
2107
2108
2109 /***********************************************************************
2110  *           _hread (KERNEL.349)
2111  */
2112 LONG WINAPI WIN16_hread( HFILE16 hFile, SEGPTR buffer, LONG count )
2113 {
2114     LONG maxlen;
2115
2116     TRACE("%d %08lx %ld\n",
2117                   hFile, (DWORD)buffer, count );
2118
2119     /* Some programs pass a count larger than the allocated buffer */
2120     maxlen = GetSelectorLimit16( SELECTOROF(buffer) ) - OFFSETOF(buffer) + 1;
2121     if (count > maxlen) count = maxlen;
2122     return _lread((HFILE)DosFileHandleToWin32Handle(hFile), MapSL(buffer), count );
2123 }
2124
2125
2126 /***********************************************************************
2127  *           _lread (KERNEL.82)
2128  */
2129 UINT16 WINAPI WIN16_lread( HFILE16 hFile, SEGPTR buffer, UINT16 count )
2130 {
2131     return (UINT16)WIN16_hread( hFile, buffer, (LONG)count );
2132 }
2133
2134
2135 /***********************************************************************
2136  *           _lread   (KERNEL32.@)
2137  */
2138 UINT WINAPI _lread( HFILE handle, LPVOID buffer, UINT count )
2139 {
2140     DWORD result;
2141     if (!ReadFile( (HANDLE)handle, buffer, count, &result, NULL )) return -1;
2142     return result;
2143 }
2144
2145
2146 /***********************************************************************
2147  *           _lread16   (KERNEL.82)
2148  */
2149 UINT16 WINAPI _lread16( HFILE16 hFile, LPVOID buffer, UINT16 count )
2150 {
2151     return (UINT16)_lread((HFILE)DosFileHandleToWin32Handle(hFile), buffer, (LONG)count );
2152 }
2153
2154
2155 /***********************************************************************
2156  *           _lcreat   (KERNEL.83)
2157  */
2158 HFILE16 WINAPI _lcreat16( LPCSTR path, INT16 attr )
2159 {
2160     return Win32HandleToDosFileHandle( (HANDLE)_lcreat( path, attr ) );
2161 }
2162
2163
2164 /***********************************************************************
2165  *           _lcreat   (KERNEL32.@)
2166  */
2167 HFILE WINAPI _lcreat( LPCSTR path, INT attr )
2168 {
2169     /* Mask off all flags not explicitly allowed by the doc */
2170     attr &= FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM;
2171     TRACE("%s %02x\n", path, attr );
2172     return (HFILE)CreateFileA( path, GENERIC_READ | GENERIC_WRITE,
2173                                FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
2174                                CREATE_ALWAYS, attr, 0 );
2175 }
2176
2177
2178 /***********************************************************************
2179  *           SetFilePointer   (KERNEL32.@)
2180  */
2181 DWORD WINAPI SetFilePointer( HANDLE hFile, LONG distance, LONG *highword,
2182                              DWORD method )
2183 {
2184     DWORD ret = INVALID_SET_FILE_POINTER;
2185
2186     TRACE("handle %d offset %ld high %ld origin %ld\n",
2187           hFile, distance, highword?*highword:0, method );
2188
2189     SERVER_START_REQ( set_file_pointer )
2190     {
2191         req->handle = hFile;
2192         req->low = distance;
2193         req->high = highword ? *highword : (distance >= 0) ? 0 : -1;
2194         /* FIXME: assumes 1:1 mapping between Windows and Unix seek constants */
2195         req->whence = method;
2196         SetLastError( 0 );
2197         if (!wine_server_call_err( req ))
2198         {
2199             ret = reply->new_low;
2200             if (highword) *highword = reply->new_high;
2201         }
2202     }
2203     SERVER_END_REQ;
2204     return ret;
2205 }
2206
2207
2208 /***********************************************************************
2209  *           _llseek   (KERNEL.84)
2210  *
2211  * FIXME:
2212  *   Seeking before the start of the file should be allowed for _llseek16,
2213  *   but cause subsequent I/O operations to fail (cf. interrupt list)
2214  *
2215  */
2216 LONG WINAPI _llseek16( HFILE16 hFile, LONG lOffset, INT16 nOrigin )
2217 {
2218     return SetFilePointer( DosFileHandleToWin32Handle(hFile), lOffset, NULL, nOrigin );
2219 }
2220
2221
2222 /***********************************************************************
2223  *           _llseek   (KERNEL32.@)
2224  */
2225 LONG WINAPI _llseek( HFILE hFile, LONG lOffset, INT nOrigin )
2226 {
2227     return SetFilePointer( (HANDLE)hFile, lOffset, NULL, nOrigin );
2228 }
2229
2230
2231 /***********************************************************************
2232  *           _lopen   (KERNEL.85)
2233  */
2234 HFILE16 WINAPI _lopen16( LPCSTR path, INT16 mode )
2235 {
2236     return Win32HandleToDosFileHandle( (HANDLE)_lopen( path, mode ) );
2237 }
2238
2239
2240 /***********************************************************************
2241  *           _lopen   (KERNEL32.@)
2242  */
2243 HFILE WINAPI _lopen( LPCSTR path, INT mode )
2244 {
2245     DWORD access, sharing;
2246
2247     TRACE("('%s',%04x)\n", path, mode );
2248     FILE_ConvertOFMode( mode, &access, &sharing );
2249     return (HFILE)CreateFileA( path, access, sharing, NULL, OPEN_EXISTING, 0, 0 );
2250 }
2251
2252
2253 /***********************************************************************
2254  *           _lwrite   (KERNEL.86)
2255  */
2256 UINT16 WINAPI _lwrite16( HFILE16 hFile, LPCSTR buffer, UINT16 count )
2257 {
2258     return (UINT16)_hwrite( (HFILE)DosFileHandleToWin32Handle(hFile), buffer, (LONG)count );
2259 }
2260
2261 /***********************************************************************
2262  *           _lwrite   (KERNEL32.@)
2263  */
2264 UINT WINAPI _lwrite( HFILE hFile, LPCSTR buffer, UINT count )
2265 {
2266     return (UINT)_hwrite( hFile, buffer, (LONG)count );
2267 }
2268
2269
2270 /***********************************************************************
2271  *           _hread16   (KERNEL.349)
2272  */
2273 LONG WINAPI _hread16( HFILE16 hFile, LPVOID buffer, LONG count)
2274 {
2275     return _lread( (HFILE)DosFileHandleToWin32Handle(hFile), buffer, count );
2276 }
2277
2278
2279 /***********************************************************************
2280  *           _hread   (KERNEL32.@)
2281  */
2282 LONG WINAPI _hread( HFILE hFile, LPVOID buffer, LONG count)
2283 {
2284     return _lread( hFile, buffer, count );
2285 }
2286
2287
2288 /***********************************************************************
2289  *           _hwrite   (KERNEL.350)
2290  */
2291 LONG WINAPI _hwrite16( HFILE16 hFile, LPCSTR buffer, LONG count )
2292 {
2293     return _hwrite( (HFILE)DosFileHandleToWin32Handle(hFile), buffer, count );
2294 }
2295
2296
2297 /***********************************************************************
2298  *           _hwrite   (KERNEL32.@)
2299  *
2300  *      experimentation yields that _lwrite:
2301  *              o truncates the file at the current position with
2302  *                a 0 len write
2303  *              o returns 0 on a 0 length write
2304  *              o works with console handles
2305  *
2306  */
2307 LONG WINAPI _hwrite( HFILE handle, LPCSTR buffer, LONG count )
2308 {
2309     DWORD result;
2310
2311     TRACE("%d %p %ld\n", handle, buffer, count );
2312
2313     if (!count)
2314     {
2315         /* Expand or truncate at current position */
2316         if (!SetEndOfFile( (HANDLE)handle )) return HFILE_ERROR;
2317         return 0;
2318     }
2319     if (!WriteFile( (HANDLE)handle, buffer, count, &result, NULL ))
2320         return HFILE_ERROR;
2321     return result;
2322 }
2323
2324
2325 /***********************************************************************
2326  *           SetHandleCount   (KERNEL.199)
2327  */
2328 UINT16 WINAPI SetHandleCount16( UINT16 count )
2329 {
2330     return SetHandleCount( count );
2331 }
2332
2333
2334 /*************************************************************************
2335  *           SetHandleCount   (KERNEL32.@)
2336  */
2337 UINT WINAPI SetHandleCount( UINT count )
2338 {
2339     return min( 256, count );
2340 }
2341
2342
2343 /***********************************************************************
2344  *           FlushFileBuffers   (KERNEL32.@)
2345  */
2346 BOOL WINAPI FlushFileBuffers( HANDLE hFile )
2347 {
2348     BOOL ret;
2349     SERVER_START_REQ( flush_file )
2350     {
2351         req->handle = hFile;
2352         ret = !wine_server_call_err( req );
2353     }
2354     SERVER_END_REQ;
2355     return ret;
2356 }
2357
2358
2359 /**************************************************************************
2360  *           SetEndOfFile   (KERNEL32.@)
2361  */
2362 BOOL WINAPI SetEndOfFile( HANDLE hFile )
2363 {
2364     BOOL ret;
2365     SERVER_START_REQ( truncate_file )
2366     {
2367         req->handle = hFile;
2368         ret = !wine_server_call_err( req );
2369     }
2370     SERVER_END_REQ;
2371     return ret;
2372 }
2373
2374
2375 /***********************************************************************
2376  *           DeleteFile   (KERNEL.146)
2377  */
2378 BOOL16 WINAPI DeleteFile16( LPCSTR path )
2379 {
2380     return DeleteFileA( path );
2381 }
2382
2383
2384 /***********************************************************************
2385  *           DeleteFileW   (KERNEL32.@)
2386  */
2387 BOOL WINAPI DeleteFileW( LPCWSTR path )
2388 {
2389     DOS_FULL_NAME full_name;
2390     HANDLE hFile;
2391
2392     if (!path)
2393     {
2394         SetLastError(ERROR_INVALID_PARAMETER);
2395         return FALSE;
2396     }
2397     TRACE("%s\n", debugstr_w(path) );
2398
2399     if (!*path)
2400     {
2401         ERR("Empty path passed\n");
2402         return FALSE;
2403     }
2404     if (DOSFS_GetDevice( path ))
2405     {
2406         WARN("cannot remove DOS device %s!\n", debugstr_w(path));
2407         SetLastError( ERROR_FILE_NOT_FOUND );
2408         return FALSE;
2409     }
2410
2411     if (!DOSFS_GetFullName( path, TRUE, &full_name )) return FALSE;
2412
2413     /* check if we are allowed to delete the source */
2414     hFile = FILE_CreateFile( full_name.long_name, GENERIC_READ|GENERIC_WRITE, 0,
2415                              NULL, OPEN_EXISTING, 0, 0, TRUE,
2416                              GetDriveTypeW( full_name.short_name ) );
2417     if (!hFile) return FALSE;
2418
2419     if (unlink( full_name.long_name ) == -1)
2420     {
2421         FILE_SetDosError();
2422         CloseHandle(hFile);
2423         return FALSE;
2424     }
2425     CloseHandle(hFile);
2426     return TRUE;
2427 }
2428
2429
2430 /***********************************************************************
2431  *           DeleteFileA   (KERNEL32.@)
2432  */
2433 BOOL WINAPI DeleteFileA( LPCSTR path )
2434 {
2435     UNICODE_STRING pathW;
2436     BOOL ret = FALSE;
2437
2438     if (!path)
2439     {
2440         SetLastError(ERROR_INVALID_PARAMETER);
2441         return FALSE;
2442     }
2443
2444     if (RtlCreateUnicodeStringFromAsciiz(&pathW, path))
2445     {
2446         ret = DeleteFileW(pathW.Buffer);
2447         RtlFreeUnicodeString(&pathW);
2448     }
2449     else
2450         SetLastError(ERROR_NOT_ENOUGH_MEMORY);
2451     return ret;
2452 }
2453
2454
2455 /***********************************************************************
2456  *           GetFileType   (KERNEL32.@)
2457  */
2458 DWORD WINAPI GetFileType( HANDLE hFile )
2459 {
2460     DWORD ret = FILE_TYPE_UNKNOWN;
2461     SERVER_START_REQ( get_file_info )
2462     {
2463         req->handle = hFile;
2464         if (!wine_server_call_err( req )) ret = reply->type;
2465     }
2466     SERVER_END_REQ;
2467     return ret;
2468 }
2469
2470
2471 /* check if a file name is for an executable file (.exe or .com) */
2472 inline static BOOL is_executable( const char *name )
2473 {
2474     int len = strlen(name);
2475
2476     if (len < 4) return FALSE;
2477     return (!strcasecmp( name + len - 4, ".exe" ) ||
2478             !strcasecmp( name + len - 4, ".com" ));
2479 }
2480
2481
2482 /***********************************************************************
2483  *           FILE_AddBootRenameEntry
2484  *
2485  * Adds an entry to the registry that is loaded when windows boots and
2486  * checks if there are some files to be removed or renamed/moved.
2487  * <fn1> has to be valid and <fn2> may be NULL. If both pointers are
2488  * non-NULL then the file is moved, otherwise it is deleted.  The
2489  * entry of the registrykey is always appended with two zero
2490  * terminated strings. If <fn2> is NULL then the second entry is
2491  * simply a single 0-byte. Otherwise the second filename goes
2492  * there. The entries are prepended with \??\ before the path and the
2493  * second filename gets also a '!' as the first character if
2494  * MOVEFILE_REPLACE_EXISTING is set. After the final string another
2495  * 0-byte follows to indicate the end of the strings.
2496  * i.e.:
2497  * \??\D:\test\file1[0]
2498  * !\??\D:\test\file1_renamed[0]
2499  * \??\D:\Test|delete[0]
2500  * [0]                        <- file is to be deleted, second string empty
2501  * \??\D:\test\file2[0]
2502  * !\??\D:\test\file2_renamed[0]
2503  * [0]                        <- indicates end of strings
2504  *
2505  * or:
2506  * \??\D:\test\file1[0]
2507  * !\??\D:\test\file1_renamed[0]
2508  * \??\D:\Test|delete[0]
2509  * [0]                        <- file is to be deleted, second string empty
2510  * [0]                        <- indicates end of strings
2511  *
2512  */
2513 static BOOL FILE_AddBootRenameEntry( LPCWSTR fn1, LPCWSTR fn2, DWORD flags )
2514 {
2515     static const WCHAR PreString[] = {'\\','?','?','\\',0};
2516     static const WCHAR ValueName[] = {'P','e','n','d','i','n','g',
2517                                       'F','i','l','e','R','e','n','a','m','e',
2518                                       'O','p','e','r','a','t','i','o','n','s',0};
2519     static const WCHAR SessionW[] = {'M','a','c','h','i','n','e','\\',
2520                                      'S','y','s','t','e','m','\\',
2521                                      'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
2522                                      'C','o','n','t','r','o','l','\\',
2523                                      'S','e','s','s','i','o','n',' ','M','a','n','a','g','e','r',0};
2524     static const int info_size = FIELD_OFFSET( KEY_VALUE_PARTIAL_INFORMATION, Data );
2525
2526     OBJECT_ATTRIBUTES attr;
2527     UNICODE_STRING nameW;
2528     KEY_VALUE_PARTIAL_INFORMATION *info;
2529     BOOL rc = FALSE;
2530     HKEY Reboot = 0;
2531     DWORD len0, len1, len2;
2532     DWORD DataSize = 0;
2533     BYTE *Buffer = NULL;
2534     WCHAR *p;
2535
2536     attr.Length = sizeof(attr);
2537     attr.RootDirectory = 0;
2538     attr.ObjectName = &nameW;
2539     attr.Attributes = 0;
2540     attr.SecurityDescriptor = NULL;
2541     attr.SecurityQualityOfService = NULL;
2542     RtlInitUnicodeString( &nameW, SessionW );
2543
2544     if (NtCreateKey( &Reboot, KEY_ALL_ACCESS, &attr, 0, NULL, 0, NULL ) != STATUS_SUCCESS)
2545     {
2546         WARN("Error creating key for reboot managment [%s]\n",
2547              "SYSTEM\\CurrentControlSet\\Control\\Session Manager");
2548         return FALSE;
2549     }
2550
2551     len0 = strlenW(PreString);
2552     len1 = strlenW(fn1) + len0 + 1;
2553     if (fn2)
2554     {
2555         len2 = strlenW(fn2) + len0 + 1;
2556         if (flags & MOVEFILE_REPLACE_EXISTING) len2++; /* Plus 1 because of the leading '!' */
2557     }
2558     else len2 = 1; /* minimum is the 0 characters for the empty second string */
2559
2560     /* convert characters to bytes */
2561     len0 *= sizeof(WCHAR);
2562     len1 *= sizeof(WCHAR);
2563     len2 *= sizeof(WCHAR);
2564
2565     RtlInitUnicodeString( &nameW, ValueName );
2566
2567     /* First we check if the key exists and if so how many bytes it already contains. */
2568     if (NtQueryValueKey( Reboot, &nameW, KeyValuePartialInformation,
2569                          NULL, 0, &DataSize ) == STATUS_BUFFER_OVERFLOW)
2570     {
2571         if (!(Buffer = HeapAlloc( GetProcessHeap(), 0, DataSize + len1 + len2 + sizeof(WCHAR) )))
2572             goto Quit;
2573         if (NtQueryValueKey( Reboot, &nameW, KeyValuePartialInformation,
2574                              Buffer, DataSize, &DataSize )) goto Quit;
2575         info = (KEY_VALUE_PARTIAL_INFORMATION *)Buffer;
2576         if (info->Type != REG_MULTI_SZ) goto Quit;
2577         if (DataSize > sizeof(info)) DataSize -= sizeof(WCHAR);  /* remove terminating null (will be added back later) */
2578     }
2579     else
2580     {
2581         DataSize = info_size;
2582         if (!(Buffer = HeapAlloc( GetProcessHeap(), 0, DataSize + len1 + len2 + sizeof(WCHAR) )))
2583             goto Quit;
2584     }
2585
2586     p = (WCHAR *)(Buffer + DataSize);
2587     strcpyW( p, PreString );
2588     strcatW( p, fn1 );
2589     DataSize += len1;
2590     if (fn2)
2591     {
2592         p = (WCHAR *)(Buffer + DataSize);
2593         if (flags & MOVEFILE_REPLACE_EXISTING)
2594             *p++ = '!';
2595         strcpyW( p, PreString );
2596         strcatW( p, fn2 );
2597         DataSize += len2;
2598     }
2599     else
2600     {
2601         p = (WCHAR *)(Buffer + DataSize);
2602         *p = 0;
2603         DataSize += sizeof(WCHAR);
2604     }
2605
2606     /* add final null */
2607     p = (WCHAR *)(Buffer + DataSize);
2608     *p = 0;
2609     DataSize += sizeof(WCHAR);
2610
2611     rc = !NtSetValueKey(Reboot, &nameW, 0, REG_MULTI_SZ, Buffer + info_size, DataSize - info_size);
2612
2613  Quit:
2614     if (Reboot) NtClose(Reboot);
2615     if (Buffer) HeapFree( GetProcessHeap(), 0, Buffer );
2616     return(rc);
2617 }
2618
2619
2620 /**************************************************************************
2621  *           MoveFileExW   (KERNEL32.@)
2622  */
2623 BOOL WINAPI MoveFileExW( LPCWSTR fn1, LPCWSTR fn2, DWORD flag )
2624 {
2625     DOS_FULL_NAME full_name1, full_name2;
2626     HANDLE hFile;
2627     DWORD attr = INVALID_FILE_ATTRIBUTES;
2628
2629     TRACE("(%s,%s,%04lx)\n", debugstr_w(fn1), debugstr_w(fn2), flag);
2630
2631     /* FIXME: <Gerhard W. Gruber>sparhawk@gmx.at
2632        In case of W9x and lesser this function should return 120 (ERROR_CALL_NOT_IMPLEMENTED)
2633        to be really compatible. Most programs wont have any problems though. In case
2634        you encounter one, this is what you should return here. I don't know what's up
2635        with NT 3.5. Is this function available there or not?
2636        Does anybody really care about 3.5? :)
2637     */
2638
2639     /* Filename1 has to be always set to a valid path. Filename2 may be NULL
2640        if the source file has to be deleted.
2641     */
2642     if (!fn1) {
2643         SetLastError(ERROR_INVALID_PARAMETER);
2644         return FALSE;
2645     }
2646
2647     /* This function has to be run through in order to process the name properly.
2648        If the BOOTDELAY flag is set, the file doesn't need to exist though. At least
2649        that is the behaviour on NT 4.0. The operation accepts the filenames as
2650        they are given but it can't reply with a reasonable returncode. Success
2651        means in that case success for entering the values into the registry.
2652     */
2653     if(!DOSFS_GetFullName( fn1, TRUE, &full_name1 ))
2654     {
2655         if(!(flag & MOVEFILE_DELAY_UNTIL_REBOOT))
2656             return FALSE;
2657     }
2658
2659     if (fn2)  /* !fn2 means delete fn1 */
2660     {
2661         if (DOSFS_GetFullName( fn2, TRUE, &full_name2 ))
2662         {
2663             if(!(flag & MOVEFILE_DELAY_UNTIL_REBOOT))
2664             {
2665                 /* target exists, check if we may overwrite */
2666                 if (!(flag & MOVEFILE_REPLACE_EXISTING))
2667                 {
2668                     SetLastError( ERROR_FILE_EXISTS );
2669                     return FALSE;
2670                 }
2671             }
2672         }
2673         else
2674         {
2675             if (!DOSFS_GetFullName( fn2, FALSE, &full_name2 ))
2676             {
2677                 if(!(flag & MOVEFILE_DELAY_UNTIL_REBOOT))
2678                     return FALSE;
2679             }
2680         }
2681
2682         /* Source name and target path are valid */
2683
2684         if (flag & MOVEFILE_DELAY_UNTIL_REBOOT)
2685         {
2686             /* FIXME: (bon@elektron.ikp.physik.th-darmstadt.de 970706)
2687                Perhaps we should queue these command and execute it
2688                when exiting... What about using on_exit(2)
2689             */
2690             FIXME("Please move existing file %s to file %s when Wine has finished\n",
2691                   debugstr_w(fn1), debugstr_w(fn2));
2692             return FILE_AddBootRenameEntry( fn1, fn2, flag );
2693         }
2694
2695         attr = GetFileAttributesW( fn1 );
2696         if ( attr == INVALID_FILE_ATTRIBUTES ) return FALSE;
2697
2698         /* check if we are allowed to rename the source */
2699         hFile = FILE_CreateFile( full_name1.long_name, 0, 0,
2700                                  NULL, OPEN_EXISTING, 0, 0, TRUE,
2701                                  GetDriveTypeW( full_name1.short_name ) );
2702         if (!hFile)
2703         {
2704             if (GetLastError() != ERROR_ACCESS_DENIED) return FALSE;
2705             if ( !(attr & FILE_ATTRIBUTE_DIRECTORY) ) return FALSE;
2706             /* if it's a directory we can continue */
2707         }
2708         else CloseHandle(hFile);
2709
2710         /* check, if we are allowed to delete the destination,
2711         **     (but the file not being there is fine) */
2712         hFile = FILE_CreateFile( full_name2.long_name, GENERIC_READ|GENERIC_WRITE, 0,
2713                                  NULL, OPEN_EXISTING, 0, 0, TRUE,
2714                                  GetDriveTypeW( full_name2.short_name ) );
2715         if(!hFile && GetLastError() != ERROR_FILE_NOT_FOUND) return FALSE;
2716         CloseHandle(hFile);
2717
2718         if (full_name1.drive != full_name2.drive)
2719         {
2720             if (!(flag & MOVEFILE_COPY_ALLOWED))
2721             {
2722                 SetLastError( ERROR_NOT_SAME_DEVICE );
2723                 return FALSE;
2724             }
2725             else if ( attr & FILE_ATTRIBUTE_DIRECTORY )
2726             {
2727                 /* Strange, but that's what Windows returns */
2728                 SetLastError ( ERROR_ACCESS_DENIED );
2729                 return FALSE;
2730             }
2731         }
2732         if (rename( full_name1.long_name, full_name2.long_name ) == -1)
2733             /* Try copy/delete unless it's a directory. */
2734             /* FIXME: This does not handle the (unlikely) case that the two locations
2735                are on the same Wine drive, but on different Unix file systems. */
2736         {
2737             if ( attr & FILE_ATTRIBUTE_DIRECTORY )
2738             {
2739                 FILE_SetDosError();
2740                 return FALSE;
2741             }
2742             else
2743             {
2744                 if ( ! CopyFileW( fn1, fn2, !(flag & MOVEFILE_REPLACE_EXISTING) ))
2745                     return FALSE;
2746                 if ( ! DeleteFileW ( fn1 ) )
2747                     return FALSE;
2748             }
2749         }
2750         if (is_executable( full_name1.long_name ) != is_executable( full_name2.long_name ))
2751         {
2752             struct stat fstat;
2753             if (stat( full_name2.long_name, &fstat ) != -1)
2754             {
2755                 if (is_executable( full_name2.long_name ))
2756                     /* set executable bit where read bit is set */
2757                     fstat.st_mode |= (fstat.st_mode & 0444) >> 2;
2758                 else
2759                     fstat.st_mode &= ~0111;
2760                 chmod( full_name2.long_name, fstat.st_mode );
2761             }
2762         }
2763         return TRUE;
2764     }
2765     else /* fn2 == NULL means delete source */
2766     {
2767         if (flag & MOVEFILE_DELAY_UNTIL_REBOOT)
2768         {
2769             if (flag & MOVEFILE_COPY_ALLOWED) {
2770                 WARN("Illegal flag\n");
2771                 SetLastError( ERROR_GEN_FAILURE );
2772                 return FALSE;
2773             }
2774             /* FIXME: (bon@elektron.ikp.physik.th-darmstadt.de 970706)
2775                Perhaps we should queue these command and execute it
2776                when exiting... What about using on_exit(2)
2777             */
2778             FIXME("Please delete file %s when Wine has finished\n", debugstr_w(fn1));
2779             return FILE_AddBootRenameEntry( fn1, NULL, flag );
2780         }
2781
2782         if (unlink( full_name1.long_name ) == -1)
2783         {
2784             FILE_SetDosError();
2785             return FALSE;
2786         }
2787         return TRUE; /* successfully deleted */
2788     }
2789 }
2790
2791 /**************************************************************************
2792  *           MoveFileExA   (KERNEL32.@)
2793  */
2794 BOOL WINAPI MoveFileExA( LPCSTR fn1, LPCSTR fn2, DWORD flag )
2795 {
2796     UNICODE_STRING fn1W, fn2W;
2797     BOOL ret;
2798
2799     if (!fn1)
2800     {
2801         SetLastError(ERROR_INVALID_PARAMETER);
2802         return FALSE;
2803     }
2804
2805     RtlCreateUnicodeStringFromAsciiz(&fn1W, fn1);
2806     if (fn2) RtlCreateUnicodeStringFromAsciiz(&fn2W, fn2);
2807     else fn2W.Buffer = NULL;
2808
2809     ret = MoveFileExW( fn1W.Buffer, fn2W.Buffer, flag );
2810
2811     RtlFreeUnicodeString(&fn1W);
2812     RtlFreeUnicodeString(&fn2W);
2813     return ret;
2814 }
2815
2816
2817 /**************************************************************************
2818  *           MoveFileW   (KERNEL32.@)
2819  *
2820  *  Move file or directory
2821  */
2822 BOOL WINAPI MoveFileW( LPCWSTR fn1, LPCWSTR fn2 )
2823 {
2824     DOS_FULL_NAME full_name1, full_name2;
2825     struct stat fstat;
2826
2827     if (!fn1 || !fn2)
2828     {
2829         SetLastError(ERROR_INVALID_PARAMETER);
2830         return FALSE;
2831     }
2832
2833     TRACE("(%s,%s)\n", debugstr_w(fn1), debugstr_w(fn2) );
2834
2835     if (!DOSFS_GetFullName( fn1, TRUE, &full_name1 )) return FALSE;
2836     if (DOSFS_GetFullName( fn2, TRUE, &full_name2 ))  {
2837       /* The new name must not already exist */
2838       SetLastError(ERROR_ALREADY_EXISTS);
2839       return FALSE;
2840     }
2841     if (!DOSFS_GetFullName( fn2, FALSE, &full_name2 )) return FALSE;
2842
2843     if (full_name1.drive == full_name2.drive) /* move */
2844         return MoveFileExW( fn1, fn2, MOVEFILE_COPY_ALLOWED );
2845
2846     /* copy */
2847     if (stat( full_name1.long_name, &fstat ))
2848     {
2849         WARN("Invalid source file %s\n",
2850              full_name1.long_name);
2851         FILE_SetDosError();
2852         return FALSE;
2853     }
2854     if (S_ISDIR(fstat.st_mode)) {
2855         /* No Move for directories across file systems */
2856         /* FIXME: Use right error code */
2857         SetLastError( ERROR_GEN_FAILURE );
2858         return FALSE;
2859     }
2860     return CopyFileW(fn1, fn2, TRUE); /*fail, if exist */
2861 }
2862
2863
2864 /**************************************************************************
2865  *           MoveFileA   (KERNEL32.@)
2866  */
2867 BOOL WINAPI MoveFileA( LPCSTR fn1, LPCSTR fn2 )
2868 {
2869     UNICODE_STRING fn1W, fn2W;
2870     BOOL ret;
2871
2872     if (!fn1 || !fn2)
2873     {
2874         SetLastError(ERROR_INVALID_PARAMETER);
2875         return FALSE;
2876     }
2877
2878     RtlCreateUnicodeStringFromAsciiz(&fn1W, fn1);
2879     RtlCreateUnicodeStringFromAsciiz(&fn2W, fn2);
2880
2881     ret = MoveFileW( fn1W.Buffer, fn2W.Buffer );
2882
2883     RtlFreeUnicodeString(&fn1W);
2884     RtlFreeUnicodeString(&fn2W);
2885     return ret;
2886 }
2887
2888
2889 /**************************************************************************
2890  *           CopyFileW   (KERNEL32.@)
2891  */
2892 BOOL WINAPI CopyFileW( LPCWSTR source, LPCWSTR dest, BOOL fail_if_exists )
2893 {
2894     HANDLE h1, h2;
2895     BY_HANDLE_FILE_INFORMATION info;
2896     DWORD count;
2897     BOOL ret = FALSE;
2898     char buffer[2048];
2899
2900     if (!source || !dest)
2901     {
2902         SetLastError(ERROR_INVALID_PARAMETER);
2903         return FALSE;
2904     }
2905
2906     TRACE("%s -> %s\n", debugstr_w(source), debugstr_w(dest));
2907
2908     if ((h1 = CreateFileW(source, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE,
2909                      NULL, OPEN_EXISTING, 0, 0)) == INVALID_HANDLE_VALUE)
2910     {
2911         WARN("Unable to open source %s\n", debugstr_w(source));
2912         return FALSE;
2913     }
2914
2915     if (!GetFileInformationByHandle( h1, &info ))
2916     {
2917         WARN("GetFileInformationByHandle returned error for %s\n", debugstr_w(source));
2918         CloseHandle( h1 );
2919         return FALSE;
2920     }
2921
2922     if ((h2 = CreateFileW( dest, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
2923                              fail_if_exists ? CREATE_NEW : CREATE_ALWAYS,
2924                              info.dwFileAttributes, h1 )) == INVALID_HANDLE_VALUE)
2925     {
2926         WARN("Unable to open dest %s\n", debugstr_w(dest));
2927         CloseHandle( h1 );
2928         return FALSE;
2929     }
2930
2931     while (ReadFile( h1, buffer, sizeof(buffer), &count, NULL ) && count)
2932     {
2933         char *p = buffer;
2934         while (count != 0)
2935         {
2936             DWORD res;
2937             if (!WriteFile( h2, p, count, &res, NULL ) || !res) goto done;
2938             p += res;
2939             count -= res;
2940         }
2941     }
2942     ret =  TRUE;
2943 done:
2944     CloseHandle( h1 );
2945     CloseHandle( h2 );
2946     return ret;
2947 }
2948
2949
2950 /**************************************************************************
2951  *           CopyFileA   (KERNEL32.@)
2952  */
2953 BOOL WINAPI CopyFileA( LPCSTR source, LPCSTR dest, BOOL fail_if_exists)
2954 {
2955     UNICODE_STRING sourceW, destW;
2956     BOOL ret;
2957
2958     if (!source || !dest)
2959     {
2960         SetLastError(ERROR_INVALID_PARAMETER);
2961         return FALSE;
2962     }
2963
2964     RtlCreateUnicodeStringFromAsciiz(&sourceW, source);
2965     RtlCreateUnicodeStringFromAsciiz(&destW, dest);
2966
2967     ret = CopyFileW(sourceW.Buffer, destW.Buffer, fail_if_exists);
2968
2969     RtlFreeUnicodeString(&sourceW);
2970     RtlFreeUnicodeString(&destW);
2971     return ret;
2972 }
2973
2974
2975 /**************************************************************************
2976  *           CopyFileExW   (KERNEL32.@)
2977  *
2978  * This implementation ignores most of the extra parameters passed-in into
2979  * the "ex" version of the method and calls the CopyFile method.
2980  * It will have to be fixed eventually.
2981  */
2982 BOOL WINAPI CopyFileExW(LPCWSTR sourceFilename, LPCWSTR destFilename,
2983                         LPPROGRESS_ROUTINE progressRoutine, LPVOID appData,
2984                         LPBOOL cancelFlagPointer, DWORD copyFlags)
2985 {
2986     /*
2987      * Interpret the only flag that CopyFile can interpret.
2988      */
2989     return CopyFileW(sourceFilename, destFilename, (copyFlags & COPY_FILE_FAIL_IF_EXISTS) != 0);
2990 }
2991
2992 /**************************************************************************
2993  *           CopyFileExA   (KERNEL32.@)
2994  */
2995 BOOL WINAPI CopyFileExA(LPCSTR sourceFilename, LPCSTR destFilename,
2996                         LPPROGRESS_ROUTINE progressRoutine, LPVOID appData,
2997                         LPBOOL cancelFlagPointer, DWORD copyFlags)
2998 {
2999     UNICODE_STRING sourceW, destW;
3000     BOOL ret;
3001
3002     if (!sourceFilename || !destFilename)
3003     {
3004         SetLastError(ERROR_INVALID_PARAMETER);
3005         return FALSE;
3006     }
3007
3008     RtlCreateUnicodeStringFromAsciiz(&sourceW, sourceFilename);
3009     RtlCreateUnicodeStringFromAsciiz(&destW, destFilename);
3010
3011     ret = CopyFileExW(sourceW.Buffer, destW.Buffer, progressRoutine, appData,
3012                       cancelFlagPointer, copyFlags);
3013
3014     RtlFreeUnicodeString(&sourceW);
3015     RtlFreeUnicodeString(&destW);
3016     return ret;
3017 }
3018
3019
3020 /***********************************************************************
3021  *              SetFileTime   (KERNEL32.@)
3022  */
3023 BOOL WINAPI SetFileTime( HANDLE hFile,
3024                            const FILETIME *lpCreationTime,
3025                            const FILETIME *lpLastAccessTime,
3026                            const FILETIME *lpLastWriteTime )
3027 {
3028     BOOL ret;
3029     SERVER_START_REQ( set_file_time )
3030     {
3031         req->handle = hFile;
3032         if (lpLastAccessTime)
3033             RtlTimeToSecondsSince1970( (PLARGE_INTEGER) lpLastAccessTime, (DWORD *)&req->access_time );
3034         else
3035             req->access_time = 0; /* FIXME */
3036         if (lpLastWriteTime)
3037             RtlTimeToSecondsSince1970( (PLARGE_INTEGER) lpLastWriteTime, (DWORD *)&req->write_time );
3038         else
3039             req->write_time = 0; /* FIXME */
3040         ret = !wine_server_call_err( req );
3041     }
3042     SERVER_END_REQ;
3043     return ret;
3044 }
3045
3046
3047 /**************************************************************************
3048  *           LockFile   (KERNEL32.@)
3049  */
3050 BOOL WINAPI LockFile( HANDLE hFile, DWORD dwFileOffsetLow, DWORD dwFileOffsetHigh,
3051                         DWORD nNumberOfBytesToLockLow, DWORD nNumberOfBytesToLockHigh )
3052 {
3053     BOOL ret;
3054
3055     FIXME("not implemented in server\n");
3056
3057     SERVER_START_REQ( lock_file )
3058     {
3059         req->handle      = hFile;
3060         req->offset_low  = dwFileOffsetLow;
3061         req->offset_high = dwFileOffsetHigh;
3062         req->count_low   = nNumberOfBytesToLockLow;
3063         req->count_high  = nNumberOfBytesToLockHigh;
3064         ret = !wine_server_call_err( req );
3065     }
3066     SERVER_END_REQ;
3067     return ret;
3068 }
3069
3070 /**************************************************************************
3071  * LockFileEx [KERNEL32.@]
3072  *
3073  * Locks a byte range within an open file for shared or exclusive access.
3074  *
3075  * RETURNS
3076  *   success: TRUE
3077  *   failure: FALSE
3078  *
3079  * NOTES
3080  * Per Microsoft docs, the third parameter (reserved) must be set to 0.
3081  */
3082 BOOL WINAPI LockFileEx( HANDLE hFile, DWORD flags, DWORD reserved,
3083                       DWORD nNumberOfBytesToLockLow, DWORD nNumberOfBytesToLockHigh,
3084                       LPOVERLAPPED pOverlapped )
3085 {
3086     FIXME("hFile=%d,flags=%ld,reserved=%ld,lowbytes=%ld,highbytes=%ld,overlapped=%p: stub.\n",
3087           hFile, flags, reserved, nNumberOfBytesToLockLow, nNumberOfBytesToLockHigh,
3088           pOverlapped);
3089     if (reserved == 0)
3090         SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
3091     else
3092     {
3093         ERR("reserved == %ld: Supposed to be 0??\n", reserved);
3094         SetLastError(ERROR_INVALID_PARAMETER);
3095     }
3096
3097     return FALSE;
3098 }
3099
3100
3101 /**************************************************************************
3102  *           UnlockFile   (KERNEL32.@)
3103  */
3104 BOOL WINAPI UnlockFile( HANDLE hFile, DWORD dwFileOffsetLow, DWORD dwFileOffsetHigh,
3105                           DWORD nNumberOfBytesToUnlockLow, DWORD nNumberOfBytesToUnlockHigh )
3106 {
3107     BOOL ret;
3108
3109     FIXME("not implemented in server\n");
3110
3111     SERVER_START_REQ( unlock_file )
3112     {
3113         req->handle      = hFile;
3114         req->offset_low  = dwFileOffsetLow;
3115         req->offset_high = dwFileOffsetHigh;
3116         req->count_low   = nNumberOfBytesToUnlockLow;
3117         req->count_high  = nNumberOfBytesToUnlockHigh;
3118         ret = !wine_server_call_err( req );
3119     }
3120     SERVER_END_REQ;
3121     return ret;
3122 }
3123
3124
3125 /**************************************************************************
3126  *           UnlockFileEx   (KERNEL32.@)
3127  */
3128 BOOL WINAPI UnlockFileEx(
3129                 HANDLE hFile,
3130                 DWORD dwReserved,
3131                 DWORD nNumberOfBytesToUnlockLow,
3132                 DWORD nNumberOfBytesToUnlockHigh,
3133                 LPOVERLAPPED lpOverlapped
3134 )
3135 {
3136         FIXME("hFile=%d,reserved=%ld,lowbytes=%ld,highbytes=%ld,overlapped=%p: stub.\n",
3137           hFile, dwReserved, nNumberOfBytesToUnlockLow, nNumberOfBytesToUnlockHigh,
3138           lpOverlapped);
3139         if (dwReserved == 0)
3140                 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
3141         else
3142         {
3143                 ERR("reserved == %ld: Supposed to be 0??\n", dwReserved);
3144                 SetLastError(ERROR_INVALID_PARAMETER);
3145         }
3146
3147         return FALSE;
3148 }
3149
3150
3151 #if 0
3152
3153 struct DOS_FILE_LOCK {
3154   struct DOS_FILE_LOCK *        next;
3155   DWORD                         base;
3156   DWORD                         len;
3157   DWORD                         processId;
3158   FILE_OBJECT *                 dos_file;
3159 /*  char *                      unix_name;*/
3160 };
3161
3162 typedef struct DOS_FILE_LOCK DOS_FILE_LOCK;
3163
3164 static DOS_FILE_LOCK *locks = NULL;
3165 static void DOS_RemoveFileLocks(FILE_OBJECT *file);
3166
3167
3168 /* Locks need to be mirrored because unix file locking is based
3169  * on the pid. Inside of wine there can be multiple WINE processes
3170  * that share the same unix pid.
3171  * Read's and writes should check these locks also - not sure
3172  * how critical that is at this point (FIXME).
3173  */
3174
3175 static BOOL DOS_AddLock(FILE_OBJECT *file, struct flock *f)
3176 {
3177   DOS_FILE_LOCK *curr;
3178   DWORD         processId;
3179
3180   processId = GetCurrentProcessId();
3181
3182   /* check if lock overlaps a current lock for the same file */
3183 #if 0
3184   for (curr = locks; curr; curr = curr->next) {
3185     if (strcmp(curr->unix_name, file->unix_name) == 0) {
3186       if ((f->l_start == curr->base) && (f->l_len == curr->len))
3187         return TRUE;/* region is identic */
3188       if ((f->l_start < (curr->base + curr->len)) &&
3189           ((f->l_start + f->l_len) > curr->base)) {
3190         /* region overlaps */
3191         return FALSE;
3192       }
3193     }
3194   }
3195 #endif
3196
3197   curr = HeapAlloc( GetProcessHeap(), 0, sizeof(DOS_FILE_LOCK) );
3198   curr->processId = GetCurrentProcessId();
3199   curr->base = f->l_start;
3200   curr->len = f->l_len;
3201 /*  curr->unix_name = HEAP_strdupA( GetProcessHeap(), 0, file->unix_name);*/
3202   curr->next = locks;
3203   curr->dos_file = file;
3204   locks = curr;
3205   return TRUE;
3206 }
3207
3208 static void DOS_RemoveFileLocks(FILE_OBJECT *file)
3209 {
3210   DWORD         processId;
3211   DOS_FILE_LOCK **curr;
3212   DOS_FILE_LOCK *rem;
3213
3214   processId = GetCurrentProcessId();
3215   curr = &locks;
3216   while (*curr) {
3217     if ((*curr)->dos_file == file) {
3218       rem = *curr;
3219       *curr = (*curr)->next;
3220 /*      HeapFree( GetProcessHeap(), 0, rem->unix_name );*/
3221       HeapFree( GetProcessHeap(), 0, rem );
3222     }
3223     else
3224       curr = &(*curr)->next;
3225   }
3226 }
3227
3228 static BOOL DOS_RemoveLock(FILE_OBJECT *file, struct flock *f)
3229 {
3230   DWORD         processId;
3231   DOS_FILE_LOCK **curr;
3232   DOS_FILE_LOCK *rem;
3233
3234   processId = GetCurrentProcessId();
3235   for (curr = &locks; *curr; curr = &(*curr)->next) {
3236     if ((*curr)->processId == processId &&
3237         (*curr)->dos_file == file &&
3238         (*curr)->base == f->l_start &&
3239         (*curr)->len == f->l_len) {
3240       /* this is the same lock */
3241       rem = *curr;
3242       *curr = (*curr)->next;
3243 /*      HeapFree( GetProcessHeap(), 0, rem->unix_name );*/
3244       HeapFree( GetProcessHeap(), 0, rem );
3245       return TRUE;
3246     }
3247   }
3248   /* no matching lock found */
3249   return FALSE;
3250 }
3251
3252
3253 /**************************************************************************
3254  *           LockFile   (KERNEL32.@)
3255  */
3256 BOOL WINAPI LockFile(
3257         HANDLE hFile,DWORD dwFileOffsetLow,DWORD dwFileOffsetHigh,
3258         DWORD nNumberOfBytesToLockLow,DWORD nNumberOfBytesToLockHigh )
3259 {
3260   struct flock f;
3261   FILE_OBJECT *file;
3262
3263   TRACE("handle %d offsetlow=%ld offsethigh=%ld nbyteslow=%ld nbyteshigh=%ld\n",
3264                hFile, dwFileOffsetLow, dwFileOffsetHigh,
3265                nNumberOfBytesToLockLow, nNumberOfBytesToLockHigh);
3266
3267   if (dwFileOffsetHigh || nNumberOfBytesToLockHigh) {
3268     FIXME("Unimplemented bytes > 32bits\n");
3269     return FALSE;
3270   }
3271
3272   f.l_start = dwFileOffsetLow;
3273   f.l_len = nNumberOfBytesToLockLow;
3274   f.l_whence = SEEK_SET;
3275   f.l_pid = 0;
3276   f.l_type = F_WRLCK;
3277
3278   if (!(file = FILE_GetFile(hFile,0,NULL))) return FALSE;
3279
3280   /* shadow locks internally */
3281   if (!DOS_AddLock(file, &f)) {
3282     SetLastError( ERROR_LOCK_VIOLATION );
3283     return FALSE;
3284   }
3285
3286   /* FIXME: Unix locking commented out for now, doesn't work with Excel */
3287 #ifdef USE_UNIX_LOCKS
3288   if (fcntl(file->unix_handle, F_SETLK, &f) == -1) {
3289     if (errno == EACCES || errno == EAGAIN) {
3290       SetLastError( ERROR_LOCK_VIOLATION );
3291     }
3292     else {
3293       FILE_SetDosError();
3294     }
3295     /* remove our internal copy of the lock */
3296     DOS_RemoveLock(file, &f);
3297     return FALSE;
3298   }
3299 #endif
3300   return TRUE;
3301 }
3302
3303
3304 /**************************************************************************
3305  *           UnlockFile   (KERNEL32.@)
3306  */
3307 BOOL WINAPI UnlockFile(
3308         HANDLE hFile,DWORD dwFileOffsetLow,DWORD dwFileOffsetHigh,
3309         DWORD nNumberOfBytesToUnlockLow,DWORD nNumberOfBytesToUnlockHigh )
3310 {
3311   FILE_OBJECT *file;
3312   struct flock f;
3313
3314   TRACE("handle %d offsetlow=%ld offsethigh=%ld nbyteslow=%ld nbyteshigh=%ld\n",
3315                hFile, dwFileOffsetLow, dwFileOffsetHigh,
3316                nNumberOfBytesToUnlockLow, nNumberOfBytesToUnlockHigh);
3317
3318   if (dwFileOffsetHigh || nNumberOfBytesToUnlockHigh) {
3319     WARN("Unimplemented bytes > 32bits\n");
3320     return FALSE;
3321   }
3322
3323   f.l_start = dwFileOffsetLow;
3324   f.l_len = nNumberOfBytesToUnlockLow;
3325   f.l_whence = SEEK_SET;
3326   f.l_pid = 0;
3327   f.l_type = F_UNLCK;
3328
3329   if (!(file = FILE_GetFile(hFile,0,NULL))) return FALSE;
3330
3331   DOS_RemoveLock(file, &f);     /* ok if fails - may be another wine */
3332
3333   /* FIXME: Unix locking commented out for now, doesn't work with Excel */
3334 #ifdef USE_UNIX_LOCKS
3335   if (fcntl(file->unix_handle, F_SETLK, &f) == -1) {
3336     FILE_SetDosError();
3337     return FALSE;
3338   }
3339 #endif
3340   return TRUE;
3341 }
3342 #endif
3343
3344 /**************************************************************************
3345  *           GetFileAttributesExW   (KERNEL32.@)
3346  */
3347 BOOL WINAPI GetFileAttributesExW(
3348         LPCWSTR lpFileName, GET_FILEEX_INFO_LEVELS fInfoLevelId,
3349         LPVOID lpFileInformation)
3350 {
3351     DOS_FULL_NAME full_name;
3352     BY_HANDLE_FILE_INFORMATION info;
3353
3354     if (!lpFileName || !lpFileInformation)
3355     {
3356         SetLastError(ERROR_INVALID_PARAMETER);
3357         return FALSE;
3358     }
3359
3360     if (fInfoLevelId == GetFileExInfoStandard) {
3361         LPWIN32_FILE_ATTRIBUTE_DATA lpFad =
3362             (LPWIN32_FILE_ATTRIBUTE_DATA) lpFileInformation;
3363         if (!DOSFS_GetFullName( lpFileName, TRUE, &full_name )) return FALSE;
3364         if (!FILE_Stat( full_name.long_name, &info )) return FALSE;
3365
3366         lpFad->dwFileAttributes = info.dwFileAttributes;
3367         lpFad->ftCreationTime   = info.ftCreationTime;
3368         lpFad->ftLastAccessTime = info.ftLastAccessTime;
3369         lpFad->ftLastWriteTime  = info.ftLastWriteTime;
3370         lpFad->nFileSizeHigh    = info.nFileSizeHigh;
3371         lpFad->nFileSizeLow     = info.nFileSizeLow;
3372     }
3373     else {
3374         FIXME("invalid info level %d!\n", fInfoLevelId);
3375         return FALSE;
3376     }
3377
3378     return TRUE;
3379 }
3380
3381
3382 /**************************************************************************
3383  *           GetFileAttributesExA   (KERNEL32.@)
3384  */
3385 BOOL WINAPI GetFileAttributesExA(
3386         LPCSTR filename, GET_FILEEX_INFO_LEVELS fInfoLevelId,
3387         LPVOID lpFileInformation)
3388 {
3389     UNICODE_STRING filenameW;
3390     BOOL ret = FALSE;
3391
3392     if (!filename || !lpFileInformation)
3393     {
3394         SetLastError(ERROR_INVALID_PARAMETER);
3395         return FALSE;
3396     }
3397
3398     if (RtlCreateUnicodeStringFromAsciiz(&filenameW, filename))
3399     {
3400         ret = GetFileAttributesExW(filenameW.Buffer, fInfoLevelId, lpFileInformation);
3401         RtlFreeUnicodeString(&filenameW);
3402     }
3403     else
3404         SetLastError(ERROR_NOT_ENOUGH_MEMORY);
3405     return ret;
3406 }