Fix the BLT COLOR_FILL case.
[wine/multimedia.git] / files / file.c
blob99b739d878f008a08b45d7d951d16de1dd411f0a
1 /*
2 * File handling functions
4 * Copyright 1993 John Burton
5 * Copyright 1996 Alexandre Julliard
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.
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.
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
21 * TODO:
22 * Fix the CopyFileEx methods to implement the "extended" functionality.
23 * Right now, they simply call the CopyFile method.
26 #include "config.h"
27 #include "wine/port.h"
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
58 #define NONAMELESSUNION
59 #define NONAMELESSSTRUCT
60 #include "winerror.h"
61 #include "windef.h"
62 #include "winbase.h"
63 #include "winternl.h"
64 #include "wine/winbase16.h"
65 #include "wine/server.h"
67 #include "drive.h"
68 #include "file.h"
69 #include "async.h"
70 #include "heap.h"
71 #include "msdos.h"
72 #include "wincon.h"
74 #include "smb.h"
75 #include "wine/unicode.h"
76 #include "wine/debug.h"
78 WINE_DEFAULT_DEBUG_CHANNEL(file);
80 #if defined(MAP_ANONYMOUS) && !defined(MAP_ANON)
81 #define MAP_ANON MAP_ANONYMOUS
82 #endif
84 /* Size of per-process table of DOS handles */
85 #define DOS_TABLE_SIZE 256
87 /* Macro to derive file offset from OVERLAPPED struct */
88 #define OVERLAPPED_OFFSET(overlapped) ((off_t) (overlapped)->Offset + ((off_t) (overlapped)->OffsetHigh << 32))
90 static HANDLE dos_handles[DOS_TABLE_SIZE];
92 mode_t FILE_umask;
94 extern HANDLE WINAPI FILE_SmbOpen(LPCSTR name);
96 /***********************************************************************
97 * Asynchronous file I/O *
99 static DWORD fileio_get_async_status (const async_private *ovp);
100 static DWORD fileio_get_async_count (const async_private *ovp);
101 static void fileio_set_async_status (async_private *ovp, const DWORD status);
102 static void CALLBACK fileio_call_completion_func (ULONG_PTR data);
103 static void fileio_async_cleanup (async_private *ovp);
105 static async_ops fileio_async_ops =
107 fileio_get_async_status, /* get_status */
108 fileio_set_async_status, /* set_status */
109 fileio_get_async_count, /* get_count */
110 fileio_call_completion_func, /* call_completion */
111 fileio_async_cleanup /* cleanup */
114 static async_ops fileio_nocomp_async_ops =
116 fileio_get_async_status, /* get_status */
117 fileio_set_async_status, /* set_status */
118 fileio_get_async_count, /* get_count */
119 NULL, /* call_completion */
120 fileio_async_cleanup /* cleanup */
123 typedef struct async_fileio
125 struct async_private async;
126 LPOVERLAPPED lpOverlapped;
127 LPOVERLAPPED_COMPLETION_ROUTINE completion_func;
128 char *buffer;
129 unsigned int count;
130 enum fd_type fd_type;
131 } async_fileio;
133 static DWORD fileio_get_async_status (const struct async_private *ovp)
135 return ((async_fileio*) ovp)->lpOverlapped->Internal;
138 static void fileio_set_async_status (async_private *ovp, const DWORD status)
140 ((async_fileio*) ovp)->lpOverlapped->Internal = status;
143 static DWORD fileio_get_async_count (const struct async_private *ovp)
145 async_fileio *fileio = (async_fileio*) ovp;
147 if (fileio->count < fileio->lpOverlapped->InternalHigh)
148 return 0;
149 return fileio->count - fileio->lpOverlapped->InternalHigh;
152 static void CALLBACK fileio_call_completion_func (ULONG_PTR data)
154 async_fileio *ovp = (async_fileio*) data;
155 TRACE ("data: %p\n", ovp);
157 ovp->completion_func( RtlNtStatusToDosError ( ovp->lpOverlapped->Internal ),
158 ovp->lpOverlapped->InternalHigh,
159 ovp->lpOverlapped );
161 fileio_async_cleanup ( &ovp->async );
164 static void fileio_async_cleanup ( struct async_private *ovp )
166 HeapFree ( GetProcessHeap(), 0, ovp );
169 /***********************************************************************
170 * FILE_ConvertOFMode
172 * Convert OF_* mode into flags for CreateFile.
174 static void FILE_ConvertOFMode( INT mode, DWORD *access, DWORD *sharing )
176 switch(mode & 0x03)
178 case OF_READ: *access = GENERIC_READ; break;
179 case OF_WRITE: *access = GENERIC_WRITE; break;
180 case OF_READWRITE: *access = GENERIC_READ | GENERIC_WRITE; break;
181 default: *access = 0; break;
183 switch(mode & 0x70)
185 case OF_SHARE_EXCLUSIVE: *sharing = 0; break;
186 case OF_SHARE_DENY_WRITE: *sharing = FILE_SHARE_READ; break;
187 case OF_SHARE_DENY_READ: *sharing = FILE_SHARE_WRITE; break;
188 case OF_SHARE_DENY_NONE:
189 case OF_SHARE_COMPAT:
190 default: *sharing = FILE_SHARE_READ | FILE_SHARE_WRITE; break;
195 /***********************************************************************
196 * FILE_strcasecmp
198 * locale-independent case conversion for file I/O
200 int FILE_strcasecmp( const char *str1, const char *str2 )
202 int ret = 0;
203 for ( ; ; str1++, str2++)
204 if ((ret = FILE_toupper(*str1) - FILE_toupper(*str2)) || !*str1) break;
205 return ret;
209 /***********************************************************************
210 * FILE_strncasecmp
212 * locale-independent case conversion for file I/O
214 int FILE_strncasecmp( const char *str1, const char *str2, int len )
216 int ret = 0;
217 for ( ; len > 0; len--, str1++, str2++)
218 if ((ret = FILE_toupper(*str1) - FILE_toupper(*str2)) || !*str1) break;
219 return ret;
223 /***********************************************************************
224 * FILE_GetNtStatus(void)
226 * Retrieve the Nt Status code from errno.
227 * Try to be consistent with FILE_SetDosError().
229 DWORD FILE_GetNtStatus(void)
231 int err = errno;
232 DWORD nt;
233 TRACE ( "errno = %d\n", errno );
234 switch ( err )
236 case EAGAIN: nt = STATUS_SHARING_VIOLATION; break;
237 case EBADF: nt = STATUS_INVALID_HANDLE; break;
238 case ENOSPC: nt = STATUS_DISK_FULL; break;
239 case EPERM:
240 case EROFS:
241 case EACCES: nt = STATUS_ACCESS_DENIED; break;
242 case ENOENT: nt = STATUS_SHARING_VIOLATION; break;
243 case EISDIR: nt = STATUS_FILE_IS_A_DIRECTORY; break;
244 case EMFILE:
245 case ENFILE: nt = STATUS_NO_MORE_FILES; break;
246 case EINVAL:
247 case ENOTEMPTY: nt = STATUS_DIRECTORY_NOT_EMPTY; break;
248 case EPIPE: nt = STATUS_PIPE_BROKEN; break;
249 case ENOEXEC: /* ?? */
250 case ESPIPE: /* ?? */
251 case EEXIST: /* ?? */
252 default:
253 FIXME ( "Converting errno %d to STATUS_UNSUCCESSFUL\n", err );
254 nt = STATUS_UNSUCCESSFUL;
256 return nt;
259 /***********************************************************************
260 * FILE_SetDosError
262 * Set the DOS error code from errno.
264 void FILE_SetDosError(void)
266 int save_errno = errno; /* errno gets overwritten by printf */
268 TRACE("errno = %d %s\n", errno, strerror(errno));
269 switch (save_errno)
271 case EAGAIN:
272 SetLastError( ERROR_SHARING_VIOLATION );
273 break;
274 case EBADF:
275 SetLastError( ERROR_INVALID_HANDLE );
276 break;
277 case ENOSPC:
278 SetLastError( ERROR_HANDLE_DISK_FULL );
279 break;
280 case EACCES:
281 case EPERM:
282 case EROFS:
283 SetLastError( ERROR_ACCESS_DENIED );
284 break;
285 case EBUSY:
286 SetLastError( ERROR_LOCK_VIOLATION );
287 break;
288 case ENOENT:
289 SetLastError( ERROR_FILE_NOT_FOUND );
290 break;
291 case EISDIR:
292 SetLastError( ERROR_CANNOT_MAKE );
293 break;
294 case ENFILE:
295 case EMFILE:
296 SetLastError( ERROR_NO_MORE_FILES );
297 break;
298 case EEXIST:
299 SetLastError( ERROR_FILE_EXISTS );
300 break;
301 case EINVAL:
302 case ESPIPE:
303 SetLastError( ERROR_SEEK );
304 break;
305 case ENOTEMPTY:
306 SetLastError( ERROR_DIR_NOT_EMPTY );
307 break;
308 case ENOEXEC:
309 SetLastError( ERROR_BAD_FORMAT );
310 break;
311 default:
312 WARN("unknown file error: %s\n", strerror(save_errno) );
313 SetLastError( ERROR_GEN_FAILURE );
314 break;
316 errno = save_errno;
320 /***********************************************************************
321 * FILE_GetUnixHandleType
323 * Retrieve the Unix handle corresponding to a file handle.
324 * Returns -1 on failure.
326 static int FILE_GetUnixHandleType( HANDLE handle, DWORD access, enum fd_type *type, int *flags_ptr )
328 int ret, flags, fd = -1;
330 ret = wine_server_handle_to_fd( handle, access, &fd, type, &flags );
331 if (flags_ptr) *flags_ptr = flags;
332 if (ret) SetLastError( RtlNtStatusToDosError(ret) );
333 else if (((access & GENERIC_READ) && (flags & FD_FLAG_RECV_SHUTDOWN)) ||
334 ((access & GENERIC_WRITE) && (flags & FD_FLAG_SEND_SHUTDOWN)))
336 close (fd);
337 SetLastError ( ERROR_PIPE_NOT_CONNECTED );
338 return -1;
340 return fd;
343 /***********************************************************************
344 * FILE_GetUnixHandle
346 * Retrieve the Unix handle corresponding to a file handle.
347 * Returns -1 on failure.
349 int FILE_GetUnixHandle( HANDLE handle, DWORD access )
351 return FILE_GetUnixHandleType( handle, access, NULL, NULL );
354 /*************************************************************************
355 * FILE_OpenConsole
357 * Open a handle to the current process console.
358 * Returns 0 on failure.
360 static HANDLE FILE_OpenConsole( BOOL output, DWORD access, DWORD sharing, LPSECURITY_ATTRIBUTES sa )
362 HANDLE ret;
364 SERVER_START_REQ( open_console )
366 req->from = output;
367 req->access = access;
368 req->share = sharing;
369 req->inherit = (sa && (sa->nLength>=sizeof(*sa)) && sa->bInheritHandle);
370 SetLastError(0);
371 wine_server_call_err( req );
372 ret = reply->handle;
374 SERVER_END_REQ;
375 return ret;
378 /* FIXME: those routines defined as pointers are needed, because this file is
379 * currently compiled into NTDLL whereas it belongs to kernel32.
380 * this shall go away once all the DLL separation process is done
382 typedef BOOL (WINAPI* pRW)(HANDLE, const void*, DWORD, DWORD*, void*);
384 static BOOL FILE_ReadConsole(HANDLE hCon, void* buf, DWORD nb, DWORD* nr, void* p)
386 static HANDLE hKernel /* = 0 */;
387 static pRW pReadConsole /* = 0 */;
389 if ((!hKernel && !(hKernel = LoadLibraryA("kernel32"))) ||
390 (!pReadConsole &&
391 !(pReadConsole = GetProcAddress(hKernel, "ReadConsoleA"))))
393 *nr = 0;
394 return 0;
396 return (pReadConsole)(hCon, buf, nb, nr, p);
399 static BOOL FILE_WriteConsole(HANDLE hCon, const void* buf, DWORD nb, DWORD* nr, void* p)
401 static HANDLE hKernel /* = 0 */;
402 static pRW pWriteConsole /* = 0 */;
404 if ((!hKernel && !(hKernel = LoadLibraryA("kernel32"))) ||
405 (!pWriteConsole &&
406 !(pWriteConsole = GetProcAddress(hKernel, "WriteConsoleA"))))
408 *nr = 0;
409 return 0;
411 return (pWriteConsole)(hCon, buf, nb, nr, p);
413 /* end of FIXME */
415 /***********************************************************************
416 * FILE_CreateFile
418 * Implementation of CreateFile. Takes a Unix path name.
419 * Returns 0 on failure.
421 HANDLE FILE_CreateFile( LPCSTR filename, DWORD access, DWORD sharing,
422 LPSECURITY_ATTRIBUTES sa, DWORD creation,
423 DWORD attributes, HANDLE template, BOOL fail_read_only,
424 UINT drive_type )
426 unsigned int err;
427 HANDLE ret;
429 for (;;)
431 SERVER_START_REQ( create_file )
433 req->access = access;
434 req->inherit = (sa && (sa->nLength>=sizeof(*sa)) && sa->bInheritHandle);
435 req->sharing = sharing;
436 req->create = creation;
437 req->attrs = attributes;
438 req->drive_type = drive_type;
439 wine_server_add_data( req, filename, strlen(filename) );
440 SetLastError(0);
441 err = wine_server_call( req );
442 ret = reply->handle;
444 SERVER_END_REQ;
446 /* If write access failed, retry without GENERIC_WRITE */
448 if (!ret && !fail_read_only && (access & GENERIC_WRITE))
450 if ((err == STATUS_MEDIA_WRITE_PROTECTED) || (err == STATUS_ACCESS_DENIED))
452 TRACE("Write access failed for file '%s', trying without "
453 "write access\n", filename);
454 access &= ~GENERIC_WRITE;
455 continue;
459 if (err)
461 /* In the case file creation was rejected due to CREATE_NEW flag
462 * was specified and file with that name already exists, correct
463 * last error is ERROR_FILE_EXISTS and not ERROR_ALREADY_EXISTS.
464 * Note: RtlNtStatusToDosError is not the subject to blame here.
466 if (err == STATUS_OBJECT_NAME_COLLISION)
467 SetLastError( ERROR_FILE_EXISTS );
468 else
469 SetLastError( RtlNtStatusToDosError(err) );
472 if (!ret) WARN("Unable to create file '%s' (GLE %ld)\n", filename, GetLastError());
473 return ret;
478 /***********************************************************************
479 * FILE_CreateDevice
481 * Same as FILE_CreateFile but for a device
482 * Returns 0 on failure.
484 HANDLE FILE_CreateDevice( int client_id, DWORD access, LPSECURITY_ATTRIBUTES sa )
486 HANDLE ret;
487 SERVER_START_REQ( create_device )
489 req->access = access;
490 req->inherit = (sa && (sa->nLength>=sizeof(*sa)) && sa->bInheritHandle);
491 req->id = client_id;
492 SetLastError(0);
493 wine_server_call_err( req );
494 ret = reply->handle;
496 SERVER_END_REQ;
497 return ret;
500 static HANDLE FILE_OpenPipe(LPCWSTR name, DWORD access)
502 HANDLE ret;
503 DWORD len = 0;
505 if (name && (len = strlenW(name)) > MAX_PATH)
507 SetLastError( ERROR_FILENAME_EXCED_RANGE );
508 return 0;
510 SERVER_START_REQ( open_named_pipe )
512 req->access = access;
513 SetLastError(0);
514 wine_server_add_data( req, name, len * sizeof(WCHAR) );
515 wine_server_call_err( req );
516 ret = reply->handle;
518 SERVER_END_REQ;
519 TRACE("Returned %p\n",ret);
520 return ret;
523 /*************************************************************************
524 * CreateFileW [KERNEL32.@] Creates or opens a file or other object
526 * Creates or opens an object, and returns a handle that can be used to
527 * access that object.
529 * PARAMS
531 * filename [in] pointer to filename to be accessed
532 * access [in] access mode requested
533 * sharing [in] share mode
534 * sa [in] pointer to security attributes
535 * creation [in] how to create the file
536 * attributes [in] attributes for newly created file
537 * template [in] handle to file with extended attributes to copy
539 * RETURNS
540 * Success: Open handle to specified file
541 * Failure: INVALID_HANDLE_VALUE
543 * NOTES
544 * Should call SetLastError() on failure.
546 * BUGS
548 * Doesn't support character devices, template files, or a
549 * lot of the 'attributes' flags yet.
551 HANDLE WINAPI CreateFileW( LPCWSTR filename, DWORD access, DWORD sharing,
552 LPSECURITY_ATTRIBUTES sa, DWORD creation,
553 DWORD attributes, HANDLE template )
555 DOS_FULL_NAME full_name;
556 HANDLE ret;
557 static const WCHAR bkslashes_with_question_markW[] = {'\\','\\','?','\\',0};
558 static const WCHAR bkslashes_with_dotW[] = {'\\','\\','.','\\',0};
559 static const WCHAR bkslashesW[] = {'\\','\\',0};
560 static const WCHAR coninW[] = {'C','O','N','I','N','$',0};
561 static const WCHAR conoutW[] = {'C','O','N','O','U','T','$',0};
563 if (!filename)
565 SetLastError( ERROR_INVALID_PARAMETER );
566 return INVALID_HANDLE_VALUE;
568 TRACE("%s %s%s%s%s%s%s%s attributes 0x%lx\n", debugstr_w(filename),
569 ((access & GENERIC_READ)==GENERIC_READ)?"GENERIC_READ ":"",
570 ((access & GENERIC_WRITE)==GENERIC_WRITE)?"GENERIC_WRITE ":"",
571 (!access)?"QUERY_ACCESS ":"",
572 ((sharing & FILE_SHARE_READ)==FILE_SHARE_READ)?"FILE_SHARE_READ ":"",
573 ((sharing & FILE_SHARE_WRITE)==FILE_SHARE_WRITE)?"FILE_SHARE_WRITE ":"",
574 ((sharing & FILE_SHARE_DELETE)==FILE_SHARE_DELETE)?"FILE_SHARE_DELETE ":"",
575 (creation ==CREATE_NEW)?"CREATE_NEW":
576 (creation ==CREATE_ALWAYS)?"CREATE_ALWAYS ":
577 (creation ==OPEN_EXISTING)?"OPEN_EXISTING ":
578 (creation ==OPEN_ALWAYS)?"OPEN_ALWAYS ":
579 (creation ==TRUNCATE_EXISTING)?"TRUNCATE_EXISTING ":"", attributes);
581 /* If the name starts with '\\?\', ignore the first 4 chars. */
582 if (!strncmpW(filename, bkslashes_with_question_markW, 4))
584 static const WCHAR uncW[] = {'U','N','C','\\',0};
585 filename += 4;
586 if (!strncmpiW(filename, uncW, 4))
588 FIXME("UNC name (%s) not supported.\n", debugstr_w(filename) );
589 SetLastError( ERROR_PATH_NOT_FOUND );
590 return INVALID_HANDLE_VALUE;
594 if (!strncmpW(filename, bkslashes_with_dotW, 4))
596 static const WCHAR pipeW[] = {'P','I','P','E','\\',0};
597 if(!strncmpiW(filename + 4, pipeW, 5))
599 TRACE("Opening a pipe: %s\n", debugstr_w(filename));
600 ret = FILE_OpenPipe(filename,access);
601 goto done;
603 else if (isalphaW(filename[4]) && filename[5] == ':' && filename[6] == '\0')
605 ret = FILE_CreateDevice( (toupperW(filename[4]) - 'A') | 0x20000, access, sa );
606 goto done;
608 else if (!DOSFS_GetDevice( filename ))
610 ret = DEVICE_Open( filename+4, access, sa );
611 goto done;
613 else
614 filename+=4; /* fall into DOSFS_Device case below */
617 /* If the name still starts with '\\', it's a UNC name. */
618 if (!strncmpW(filename, bkslashesW, 2))
620 ret = SMB_CreateFileW(filename, access, sharing, sa, creation, attributes, template );
621 goto done;
624 /* If the name contains a DOS wild card (* or ?), do no create a file */
625 if(strchrW(filename, '*') || strchrW(filename, '?'))
627 SetLastError(ERROR_BAD_PATHNAME);
628 return INVALID_HANDLE_VALUE;
631 /* Open a console for CONIN$ or CONOUT$ */
632 if (!strcmpiW(filename, coninW))
634 ret = FILE_OpenConsole( FALSE, access, sharing, sa );
635 goto done;
637 if (!strcmpiW(filename, conoutW))
639 ret = FILE_OpenConsole( TRUE, access, sharing, sa );
640 goto done;
643 if (DOSFS_GetDevice( filename ))
645 TRACE("opening device %s\n", debugstr_w(filename) );
647 if (!(ret = DOSFS_OpenDevice( filename, access, attributes, sa )))
649 /* Do not silence this please. It is a critical error. -MM */
650 ERR("Couldn't open device %s!\n", debugstr_w(filename));
651 SetLastError( ERROR_FILE_NOT_FOUND );
653 goto done;
656 /* check for filename, don't check for last entry if creating */
657 if (!DOSFS_GetFullName( filename,
658 (creation == OPEN_EXISTING) ||
659 (creation == TRUNCATE_EXISTING),
660 &full_name )) {
661 WARN("Unable to get full filename from %s (GLE %ld)\n",
662 debugstr_w(filename), GetLastError());
663 return INVALID_HANDLE_VALUE;
666 ret = FILE_CreateFile( full_name.long_name, access, sharing,
667 sa, creation, attributes, template,
668 DRIVE_GetFlags(full_name.drive) & DRIVE_FAIL_READ_ONLY,
669 GetDriveTypeW( full_name.short_name ) );
670 done:
671 if (!ret) ret = INVALID_HANDLE_VALUE;
672 TRACE("returning %p\n", ret);
673 return ret;
678 /*************************************************************************
679 * CreateFileA (KERNEL32.@)
681 HANDLE WINAPI CreateFileA( LPCSTR filename, DWORD access, DWORD sharing,
682 LPSECURITY_ATTRIBUTES sa, DWORD creation,
683 DWORD attributes, HANDLE template)
685 UNICODE_STRING filenameW;
686 HANDLE ret = INVALID_HANDLE_VALUE;
688 if (!filename)
690 SetLastError( ERROR_INVALID_PARAMETER );
691 return INVALID_HANDLE_VALUE;
694 if (RtlCreateUnicodeStringFromAsciiz(&filenameW, filename))
696 ret = CreateFileW(filenameW.Buffer, access, sharing, sa, creation,
697 attributes, template);
698 RtlFreeUnicodeString(&filenameW);
700 else
701 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
702 return ret;
706 /***********************************************************************
707 * FILE_FillInfo
709 * Fill a file information from a struct stat.
711 static void FILE_FillInfo( struct stat *st, BY_HANDLE_FILE_INFORMATION *info )
713 if (S_ISDIR(st->st_mode))
714 info->dwFileAttributes = FILE_ATTRIBUTE_DIRECTORY;
715 else
716 info->dwFileAttributes = FILE_ATTRIBUTE_ARCHIVE;
717 if (!(st->st_mode & S_IWUSR))
718 info->dwFileAttributes |= FILE_ATTRIBUTE_READONLY;
720 RtlSecondsSince1970ToTime( st->st_mtime, (LARGE_INTEGER *)&info->ftCreationTime );
721 RtlSecondsSince1970ToTime( st->st_mtime, (LARGE_INTEGER *)&info->ftLastWriteTime );
722 RtlSecondsSince1970ToTime( st->st_atime, (LARGE_INTEGER *)&info->ftLastAccessTime );
724 info->dwVolumeSerialNumber = 0; /* FIXME */
725 info->nFileSizeHigh = 0;
726 info->nFileSizeLow = 0;
727 if (!S_ISDIR(st->st_mode)) {
728 info->nFileSizeHigh = st->st_size >> 32;
729 info->nFileSizeLow = st->st_size & 0xffffffff;
731 info->nNumberOfLinks = st->st_nlink;
732 info->nFileIndexHigh = 0;
733 info->nFileIndexLow = st->st_ino;
737 /***********************************************************************
738 * FILE_Stat
740 * Stat a Unix path name. Return TRUE if OK.
742 BOOL FILE_Stat( LPCSTR unixName, BY_HANDLE_FILE_INFORMATION *info, BOOL *is_symlink_ptr )
744 struct stat st;
745 int is_symlink;
746 LPCSTR p;
748 if (lstat( unixName, &st ) == -1)
750 FILE_SetDosError();
751 return FALSE;
753 is_symlink = S_ISLNK(st.st_mode);
754 if (is_symlink)
756 /* do a "real" stat to find out
757 about the type of the symlink destination */
758 if (stat( unixName, &st ) == -1)
760 FILE_SetDosError();
761 return FALSE;
765 /* fill in the information we gathered so far */
766 FILE_FillInfo( &st, info );
768 /* and now see if this is a hidden file, based on the name */
769 p = strrchr( unixName, '/');
770 p = p ? p + 1 : unixName;
771 if (*p == '.' && *(p+1) && (*(p+1) != '.' || *(p+2)))
773 static const WCHAR wineW[] = {'w','i','n','e',0};
774 static const WCHAR ShowDotFilesW[] = {'S','h','o','w','D','o','t','F','i','l','e','s',0};
775 static int show_dot_files = -1;
776 if (show_dot_files == -1)
777 show_dot_files = PROFILE_GetWineIniBool(wineW, ShowDotFilesW, 0);
778 if (!show_dot_files)
779 info->dwFileAttributes |= FILE_ATTRIBUTE_HIDDEN;
781 if (is_symlink_ptr) *is_symlink_ptr = is_symlink;
782 return TRUE;
786 /***********************************************************************
787 * GetFileInformationByHandle (KERNEL32.@)
789 DWORD WINAPI GetFileInformationByHandle( HANDLE hFile,
790 BY_HANDLE_FILE_INFORMATION *info )
792 DWORD ret;
793 if (!info) return 0;
795 TRACE("%p\n", hFile);
797 SERVER_START_REQ( get_file_info )
799 req->handle = hFile;
800 if ((ret = !wine_server_call_err( req )))
802 /* FIXME: which file types are supported ?
803 * Serial ports (FILE_TYPE_CHAR) are not,
804 * and MSDN also says that pipes are not supported.
805 * FILE_TYPE_REMOTE seems to be supported according to
806 * MSDN q234741.txt */
807 if ((reply->type == FILE_TYPE_DISK) || (reply->type == FILE_TYPE_REMOTE))
809 RtlSecondsSince1970ToTime( reply->write_time, (LARGE_INTEGER *)&info->ftCreationTime );
810 RtlSecondsSince1970ToTime( reply->write_time, (LARGE_INTEGER *)&info->ftLastWriteTime );
811 RtlSecondsSince1970ToTime( reply->access_time, (LARGE_INTEGER *)&info->ftLastAccessTime );
812 info->dwFileAttributes = reply->attr;
813 info->dwVolumeSerialNumber = reply->serial;
814 info->nFileSizeHigh = reply->size_high;
815 info->nFileSizeLow = reply->size_low;
816 info->nNumberOfLinks = reply->links;
817 info->nFileIndexHigh = reply->index_high;
818 info->nFileIndexLow = reply->index_low;
820 else
822 SetLastError(ERROR_NOT_SUPPORTED);
823 ret = 0;
827 SERVER_END_REQ;
828 return ret;
832 /**************************************************************************
833 * GetFileAttributes (KERNEL.420)
835 DWORD WINAPI GetFileAttributes16( LPCSTR name )
837 return GetFileAttributesA( name );
841 /**************************************************************************
842 * GetFileAttributesW (KERNEL32.@)
844 DWORD WINAPI GetFileAttributesW( LPCWSTR name )
846 DOS_FULL_NAME full_name;
847 BY_HANDLE_FILE_INFORMATION info;
849 if (name == NULL)
851 SetLastError( ERROR_INVALID_PARAMETER );
852 return -1;
854 if (!DOSFS_GetFullName( name, TRUE, &full_name) )
855 return -1;
856 if (!FILE_Stat( full_name.long_name, &info, NULL )) return -1;
857 return info.dwFileAttributes;
861 /**************************************************************************
862 * GetFileAttributesA (KERNEL32.@)
864 DWORD WINAPI GetFileAttributesA( LPCSTR name )
866 UNICODE_STRING nameW;
867 DWORD ret = (DWORD)-1;
869 if (!name)
871 SetLastError( ERROR_INVALID_PARAMETER );
872 return (DWORD)-1;
875 if (RtlCreateUnicodeStringFromAsciiz(&nameW, name))
877 ret = GetFileAttributesW(nameW.Buffer);
878 RtlFreeUnicodeString(&nameW);
880 else
881 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
882 return ret;
886 /**************************************************************************
887 * SetFileAttributes (KERNEL.421)
889 BOOL16 WINAPI SetFileAttributes16( LPCSTR lpFileName, DWORD attributes )
891 return SetFileAttributesA( lpFileName, attributes );
895 /**************************************************************************
896 * SetFileAttributesW (KERNEL32.@)
898 BOOL WINAPI SetFileAttributesW(LPCWSTR lpFileName, DWORD attributes)
900 struct stat buf;
901 DOS_FULL_NAME full_name;
903 if (!lpFileName)
905 SetLastError( ERROR_INVALID_PARAMETER );
906 return FALSE;
909 TRACE("(%s,%lx)\n", debugstr_w(lpFileName), attributes);
911 if (!DOSFS_GetFullName( lpFileName, TRUE, &full_name ))
912 return FALSE;
914 if(stat(full_name.long_name,&buf)==-1)
916 FILE_SetDosError();
917 return FALSE;
919 if (attributes & FILE_ATTRIBUTE_READONLY)
921 if(S_ISDIR(buf.st_mode))
922 /* FIXME */
923 WARN("FILE_ATTRIBUTE_READONLY ignored for directory.\n");
924 else
925 buf.st_mode &= ~0222; /* octal!, clear write permission bits */
926 attributes &= ~FILE_ATTRIBUTE_READONLY;
928 else
930 /* add write permission */
931 buf.st_mode |= (0600 | ((buf.st_mode & 044) >> 1)) & (~FILE_umask);
933 if (attributes & FILE_ATTRIBUTE_DIRECTORY)
935 if (!S_ISDIR(buf.st_mode))
936 FIXME("SetFileAttributes expected the file %s to be a directory\n",
937 debugstr_w(lpFileName));
938 attributes &= ~FILE_ATTRIBUTE_DIRECTORY;
940 attributes &= ~(FILE_ATTRIBUTE_NORMAL|FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_HIDDEN|FILE_ATTRIBUTE_SYSTEM);
941 if (attributes)
942 FIXME("(%s):%lx attribute(s) not implemented.\n", debugstr_w(lpFileName), attributes);
943 if (-1==chmod(full_name.long_name,buf.st_mode))
945 if (GetDriveTypeW(lpFileName) == DRIVE_CDROM)
947 SetLastError( ERROR_ACCESS_DENIED );
948 return FALSE;
952 * FIXME: We don't return FALSE here because of differences between
953 * Linux and Windows privileges. Under Linux only the owner of
954 * the file is allowed to change file attributes. Under Windows,
955 * applications expect that if you can write to a file, you can also
956 * change its attributes (see GENERIC_WRITE). We could try to be
957 * clever here but that would break multi-user installations where
958 * users share read-only DLLs. This is because some installers like
959 * to change attributes of already installed DLLs.
961 FIXME("Couldn't set file attributes for existing file \"%s\".\n"
962 "Check permissions or set VFAT \"quiet\" mount flag\n", full_name.long_name);
964 return TRUE;
968 /**************************************************************************
969 * SetFileAttributesA (KERNEL32.@)
971 BOOL WINAPI SetFileAttributesA(LPCSTR lpFileName, DWORD attributes)
973 UNICODE_STRING filenameW;
974 BOOL ret = FALSE;
976 if (!lpFileName)
978 SetLastError( ERROR_INVALID_PARAMETER );
979 return FALSE;
982 if (RtlCreateUnicodeStringFromAsciiz(&filenameW, lpFileName))
984 ret = SetFileAttributesW(filenameW.Buffer, attributes);
985 RtlFreeUnicodeString(&filenameW);
987 else
988 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
989 return ret;
993 /***********************************************************************
994 * GetFileSize (KERNEL32.@)
996 DWORD WINAPI GetFileSize( HANDLE hFile, LPDWORD filesizehigh )
998 BY_HANDLE_FILE_INFORMATION info;
999 if (!GetFileInformationByHandle( hFile, &info )) return -1;
1000 if (filesizehigh) *filesizehigh = info.nFileSizeHigh;
1001 return info.nFileSizeLow;
1005 /***********************************************************************
1006 * GetFileSizeEx (KERNEL32.@)
1008 BOOL WINAPI GetFileSizeEx( HANDLE hFile, PLARGE_INTEGER lpFileSize )
1010 BY_HANDLE_FILE_INFORMATION info;
1012 if (!lpFileSize)
1014 SetLastError( ERROR_INVALID_PARAMETER );
1015 return FALSE;
1018 if (!GetFileInformationByHandle( hFile, &info ))
1020 return FALSE;
1023 lpFileSize->s.LowPart = info.nFileSizeLow;
1024 lpFileSize->s.HighPart = info.nFileSizeHigh;
1026 return TRUE;
1030 /***********************************************************************
1031 * GetFileTime (KERNEL32.@)
1033 BOOL WINAPI GetFileTime( HANDLE hFile, FILETIME *lpCreationTime,
1034 FILETIME *lpLastAccessTime,
1035 FILETIME *lpLastWriteTime )
1037 BY_HANDLE_FILE_INFORMATION info;
1038 if (!GetFileInformationByHandle( hFile, &info )) return FALSE;
1039 if (lpCreationTime) *lpCreationTime = info.ftCreationTime;
1040 if (lpLastAccessTime) *lpLastAccessTime = info.ftLastAccessTime;
1041 if (lpLastWriteTime) *lpLastWriteTime = info.ftLastWriteTime;
1042 return TRUE;
1045 /***********************************************************************
1046 * FILE_GetTempFileName : utility for GetTempFileName
1048 static UINT FILE_GetTempFileName( LPCWSTR path, LPCWSTR prefix, UINT unique,
1049 LPWSTR buffer )
1051 static UINT unique_temp;
1052 DOS_FULL_NAME full_name;
1053 int i;
1054 LPWSTR p;
1055 UINT num;
1056 char buf[20];
1058 if ( !path || !prefix || !buffer )
1060 SetLastError( ERROR_INVALID_PARAMETER );
1061 return 0;
1064 if (!unique_temp) unique_temp = time(NULL) & 0xffff;
1065 num = unique ? (unique & 0xffff) : (unique_temp++ & 0xffff);
1067 strcpyW( buffer, path );
1068 p = buffer + strlenW(buffer);
1070 /* add a \, if there isn't one and path is more than just the drive letter ... */
1071 if ( !((strlenW(buffer) == 2) && (buffer[1] == ':'))
1072 && ((p == buffer) || (p[-1] != '\\'))) *p++ = '\\';
1074 for (i = 3; (i > 0) && (*prefix); i--) *p++ = *prefix++;
1076 sprintf( buf, "%04x.tmp", num );
1077 MultiByteToWideChar(CP_ACP, 0, buf, -1, p, 20);
1079 /* Now try to create it */
1081 if (!unique)
1085 HANDLE handle = CreateFileW( buffer, GENERIC_WRITE, 0, NULL,
1086 CREATE_NEW, FILE_ATTRIBUTE_NORMAL, 0 );
1087 if (handle != INVALID_HANDLE_VALUE)
1088 { /* We created it */
1089 TRACE("created %s\n", debugstr_w(buffer) );
1090 CloseHandle( handle );
1091 break;
1093 if (GetLastError() != ERROR_FILE_EXISTS &&
1094 GetLastError() != ERROR_SHARING_VIOLATION)
1095 break; /* No need to go on */
1096 num++;
1097 sprintf( buf, "%04x.tmp", num );
1098 MultiByteToWideChar(CP_ACP, 0, buf, -1, p, 20);
1099 } while (num != (unique & 0xffff));
1102 /* Get the full path name */
1104 if (DOSFS_GetFullName( buffer, FALSE, &full_name ))
1106 char *slash;
1107 /* Check if we have write access in the directory */
1108 if ((slash = strrchr( full_name.long_name, '/' ))) *slash = '\0';
1109 if (access( full_name.long_name, W_OK ) == -1)
1110 WARN("returns %s, which doesn't seem to be writeable.\n",
1111 debugstr_w(buffer) );
1113 TRACE("returning %s\n", debugstr_w(buffer) );
1114 return unique ? unique : num;
1118 /***********************************************************************
1119 * GetTempFileNameA (KERNEL32.@)
1121 UINT WINAPI GetTempFileNameA( LPCSTR path, LPCSTR prefix, UINT unique,
1122 LPSTR buffer)
1124 UNICODE_STRING pathW, prefixW;
1125 WCHAR bufferW[MAX_PATH];
1126 UINT ret;
1128 if ( !path || !prefix || !buffer )
1130 SetLastError( ERROR_INVALID_PARAMETER );
1131 return 0;
1134 RtlCreateUnicodeStringFromAsciiz(&pathW, path);
1135 RtlCreateUnicodeStringFromAsciiz(&prefixW, prefix);
1137 ret = GetTempFileNameW(pathW.Buffer, prefixW.Buffer, unique, bufferW);
1138 if (ret)
1139 WideCharToMultiByte(CP_ACP, 0, bufferW, -1, buffer, MAX_PATH, NULL, NULL);
1141 RtlFreeUnicodeString(&pathW);
1142 RtlFreeUnicodeString(&prefixW);
1143 return ret;
1146 /***********************************************************************
1147 * GetTempFileNameW (KERNEL32.@)
1149 UINT WINAPI GetTempFileNameW( LPCWSTR path, LPCWSTR prefix, UINT unique,
1150 LPWSTR buffer )
1152 return FILE_GetTempFileName( path, prefix, unique, buffer );
1156 /***********************************************************************
1157 * GetTempFileName (KERNEL.97)
1159 UINT16 WINAPI GetTempFileName16( BYTE drive, LPCSTR prefix, UINT16 unique,
1160 LPSTR buffer )
1162 char temppath[MAX_PATH];
1163 char *prefix16 = NULL;
1164 UINT16 ret;
1166 if (!(drive & ~TF_FORCEDRIVE)) /* drive 0 means current default drive */
1167 drive |= DRIVE_GetCurrentDrive() + 'A';
1169 if ((drive & TF_FORCEDRIVE) &&
1170 !DRIVE_IsValid( toupper(drive & ~TF_FORCEDRIVE) - 'A' ))
1172 drive &= ~TF_FORCEDRIVE;
1173 WARN("invalid drive %d specified\n", drive );
1176 if (drive & TF_FORCEDRIVE)
1177 sprintf(temppath,"%c:", drive & ~TF_FORCEDRIVE );
1178 else
1179 GetTempPathA( MAX_PATH, temppath );
1181 if (prefix)
1183 prefix16 = HeapAlloc(GetProcessHeap(), 0, strlen(prefix) + 2);
1184 *prefix16 = '~';
1185 strcpy(prefix16 + 1, prefix);
1188 ret = GetTempFileNameA( temppath, prefix16, unique, buffer );
1190 if (prefix16) HeapFree(GetProcessHeap(), 0, prefix16);
1191 return ret;
1194 /***********************************************************************
1195 * FILE_DoOpenFile
1197 * Implementation of OpenFile16() and OpenFile32().
1199 static HFILE FILE_DoOpenFile( LPCSTR name, OFSTRUCT *ofs, UINT mode,
1200 BOOL win32 )
1202 HFILE hFileRet;
1203 HANDLE handle;
1204 FILETIME filetime;
1205 WORD filedatetime[2];
1206 DOS_FULL_NAME full_name;
1207 DWORD access, sharing;
1208 WCHAR *p;
1209 WCHAR buffer[MAX_PATH];
1210 LPWSTR nameW;
1212 if (!ofs) return HFILE_ERROR;
1214 TRACE("%s %s %s %s%s%s%s%s%s%s%s%s\n",name,
1215 ((mode & 0x3 )==OF_READ)?"OF_READ":
1216 ((mode & 0x3 )==OF_WRITE)?"OF_WRITE":
1217 ((mode & 0x3 )==OF_READWRITE)?"OF_READWRITE":"unknown",
1218 ((mode & 0x70 )==OF_SHARE_COMPAT)?"OF_SHARE_COMPAT":
1219 ((mode & 0x70 )==OF_SHARE_DENY_NONE)?"OF_SHARE_DENY_NONE":
1220 ((mode & 0x70 )==OF_SHARE_DENY_READ)?"OF_SHARE_DENY_READ":
1221 ((mode & 0x70 )==OF_SHARE_DENY_WRITE)?"OF_SHARE_DENY_WRITE":
1222 ((mode & 0x70 )==OF_SHARE_EXCLUSIVE)?"OF_SHARE_EXCLUSIVE":"unknown",
1223 ((mode & OF_PARSE )==OF_PARSE)?"OF_PARSE ":"",
1224 ((mode & OF_DELETE )==OF_DELETE)?"OF_DELETE ":"",
1225 ((mode & OF_VERIFY )==OF_VERIFY)?"OF_VERIFY ":"",
1226 ((mode & OF_SEARCH )==OF_SEARCH)?"OF_SEARCH ":"",
1227 ((mode & OF_CANCEL )==OF_CANCEL)?"OF_CANCEL ":"",
1228 ((mode & OF_CREATE )==OF_CREATE)?"OF_CREATE ":"",
1229 ((mode & OF_PROMPT )==OF_PROMPT)?"OF_PROMPT ":"",
1230 ((mode & OF_EXIST )==OF_EXIST)?"OF_EXIST ":"",
1231 ((mode & OF_REOPEN )==OF_REOPEN)?"OF_REOPEN ":""
1235 ofs->cBytes = sizeof(OFSTRUCT);
1236 ofs->nErrCode = 0;
1237 if (mode & OF_REOPEN) name = ofs->szPathName;
1239 if (!name) {
1240 ERR("called with `name' set to NULL ! Please debug.\n");
1241 return HFILE_ERROR;
1244 TRACE("%s %04x\n", name, mode );
1246 /* the watcom 10.6 IDE relies on a valid path returned in ofs->szPathName
1247 Are there any cases where getting the path here is wrong?
1248 Uwe Bonnes 1997 Apr 2 */
1249 if (!GetFullPathNameA( name, sizeof(ofs->szPathName),
1250 ofs->szPathName, NULL )) goto error;
1251 FILE_ConvertOFMode( mode, &access, &sharing );
1253 /* OF_PARSE simply fills the structure */
1255 if (mode & OF_PARSE)
1257 ofs->fFixedDisk = (GetDriveType16( ofs->szPathName[0]-'A' )
1258 != DRIVE_REMOVABLE);
1259 TRACE("(%s): OF_PARSE, res = '%s'\n",
1260 name, ofs->szPathName );
1261 return 0;
1264 /* OF_CREATE is completely different from all other options, so
1265 handle it first */
1267 if (mode & OF_CREATE)
1269 if ((handle = CreateFileA( name, GENERIC_READ | GENERIC_WRITE,
1270 sharing, NULL, CREATE_ALWAYS,
1271 FILE_ATTRIBUTE_NORMAL, 0 ))== INVALID_HANDLE_VALUE)
1272 goto error;
1273 goto success;
1276 MultiByteToWideChar(CP_ACP, 0, name, -1, buffer, MAX_PATH);
1277 nameW = buffer;
1279 /* If OF_SEARCH is set, ignore the given path */
1281 if ((mode & OF_SEARCH) && !(mode & OF_REOPEN))
1283 /* First try the file name as is */
1284 if (DOSFS_GetFullName( nameW, TRUE, &full_name )) goto found;
1285 /* Now remove the path */
1286 if (nameW[0] && (nameW[1] == ':')) nameW += 2;
1287 if ((p = strrchrW( nameW, '\\' ))) nameW = p + 1;
1288 if ((p = strrchrW( nameW, '/' ))) nameW = p + 1;
1289 if (!nameW[0]) goto not_found;
1292 /* Now look for the file */
1294 if (!DIR_SearchPath( NULL, nameW, NULL, &full_name, win32 )) goto not_found;
1296 found:
1297 TRACE("found %s = %s\n",
1298 full_name.long_name, debugstr_w(full_name.short_name) );
1299 WideCharToMultiByte(CP_ACP, 0, full_name.short_name, -1,
1300 ofs->szPathName, sizeof(ofs->szPathName), NULL, NULL);
1302 if (mode & OF_SHARE_EXCLUSIVE)
1303 /* Some InstallShield version uses OF_SHARE_EXCLUSIVE
1304 on the file <tempdir>/_ins0432._mp to determine how
1305 far installation has proceeded.
1306 _ins0432._mp is an executable and while running the
1307 application expects the open with OF_SHARE_ to fail*/
1308 /* Probable FIXME:
1309 As our loader closes the files after loading the executable,
1310 we can't find the running executable with FILE_InUse.
1311 The loader should keep the file open, as Windows does that, too.
1314 char *last = strrchr(full_name.long_name,'/');
1315 if (!last)
1316 last = full_name.long_name - 1;
1317 if (GetModuleHandle16(last+1))
1319 TRACE("Denying shared open for %s\n",full_name.long_name);
1320 return HFILE_ERROR;
1324 if (mode & OF_DELETE)
1326 if (unlink( full_name.long_name ) == -1) goto not_found;
1327 TRACE("(%s): OF_DELETE return = OK\n", name);
1328 return 1;
1331 handle = FILE_CreateFile( full_name.long_name, access, sharing,
1332 NULL, OPEN_EXISTING, 0, 0,
1333 DRIVE_GetFlags(full_name.drive) & DRIVE_FAIL_READ_ONLY,
1334 GetDriveTypeW( full_name.short_name ) );
1335 if (!handle) goto not_found;
1337 GetFileTime( handle, NULL, NULL, &filetime );
1338 FileTimeToDosDateTime( &filetime, &filedatetime[0], &filedatetime[1] );
1339 if ((mode & OF_VERIFY) && (mode & OF_REOPEN))
1341 if (ofs->Reserved1 != filedatetime[0] || ofs->Reserved2 != filedatetime[1] )
1343 CloseHandle( handle );
1344 WARN("(%s): OF_VERIFY failed\n", name );
1345 /* FIXME: what error here? */
1346 SetLastError( ERROR_FILE_NOT_FOUND );
1347 goto error;
1350 ofs->Reserved1 = filedatetime[0];
1351 ofs->Reserved2 = filedatetime[1];
1353 success: /* We get here if the open was successful */
1354 TRACE("(%s): OK, return = %p\n", name, handle );
1355 if (win32)
1357 hFileRet = (HFILE)handle;
1358 if (mode & OF_EXIST) /* Return the handle, but close it first */
1359 CloseHandle( handle );
1361 else
1363 hFileRet = Win32HandleToDosFileHandle( handle );
1364 if (hFileRet == HFILE_ERROR16) goto error;
1365 if (mode & OF_EXIST) /* Return the handle, but close it first */
1366 _lclose16( hFileRet );
1368 return hFileRet;
1370 not_found: /* We get here if the file does not exist */
1371 WARN("'%s' not found or sharing violation\n", name );
1372 SetLastError( ERROR_FILE_NOT_FOUND );
1373 /* fall through */
1375 error: /* We get here if there was an error opening the file */
1376 ofs->nErrCode = GetLastError();
1377 WARN("(%s): return = HFILE_ERROR error= %d\n",
1378 name,ofs->nErrCode );
1379 return HFILE_ERROR;
1383 /***********************************************************************
1384 * OpenFile (KERNEL.74)
1385 * OpenFileEx (KERNEL.360)
1387 HFILE16 WINAPI OpenFile16( LPCSTR name, OFSTRUCT *ofs, UINT16 mode )
1389 return FILE_DoOpenFile( name, ofs, mode, FALSE );
1393 /***********************************************************************
1394 * OpenFile (KERNEL32.@)
1396 HFILE WINAPI OpenFile( LPCSTR name, OFSTRUCT *ofs, UINT mode )
1398 return FILE_DoOpenFile( name, ofs, mode, TRUE );
1402 /***********************************************************************
1403 * FILE_InitProcessDosHandles
1405 * Allocates the default DOS handles for a process. Called either by
1406 * Win32HandleToDosFileHandle below or by the DOSVM stuff.
1408 static void FILE_InitProcessDosHandles( void )
1410 HANDLE cp = GetCurrentProcess();
1411 DuplicateHandle(cp, GetStdHandle(STD_INPUT_HANDLE), cp, &dos_handles[0],
1412 0, TRUE, DUPLICATE_SAME_ACCESS);
1413 DuplicateHandle(cp, GetStdHandle(STD_OUTPUT_HANDLE), cp, &dos_handles[1],
1414 0, TRUE, DUPLICATE_SAME_ACCESS);
1415 DuplicateHandle(cp, GetStdHandle(STD_ERROR_HANDLE), cp, &dos_handles[2],
1416 0, TRUE, DUPLICATE_SAME_ACCESS);
1417 DuplicateHandle(cp, GetStdHandle(STD_ERROR_HANDLE), cp, &dos_handles[3],
1418 0, TRUE, DUPLICATE_SAME_ACCESS);
1419 DuplicateHandle(cp, GetStdHandle(STD_ERROR_HANDLE), cp, &dos_handles[4],
1420 0, TRUE, DUPLICATE_SAME_ACCESS);
1423 /***********************************************************************
1424 * Win32HandleToDosFileHandle (KERNEL32.21)
1426 * Allocate a DOS handle for a Win32 handle. The Win32 handle is no
1427 * longer valid after this function (even on failure).
1429 * Note: this is not exactly right, since on Win95 the Win32 handles
1430 * are on top of DOS handles and we do it the other way
1431 * around. Should be good enough though.
1433 HFILE WINAPI Win32HandleToDosFileHandle( HANDLE handle )
1435 int i;
1437 if (!handle || (handle == INVALID_HANDLE_VALUE))
1438 return HFILE_ERROR;
1440 for (i = 5; i < DOS_TABLE_SIZE; i++)
1441 if (!dos_handles[i])
1443 dos_handles[i] = handle;
1444 TRACE("Got %d for h32 %p\n", i, handle );
1445 return (HFILE)i;
1447 CloseHandle( handle );
1448 SetLastError( ERROR_TOO_MANY_OPEN_FILES );
1449 return HFILE_ERROR;
1453 /***********************************************************************
1454 * DosFileHandleToWin32Handle (KERNEL32.20)
1456 * Return the Win32 handle for a DOS handle.
1458 * Note: this is not exactly right, since on Win95 the Win32 handles
1459 * are on top of DOS handles and we do it the other way
1460 * around. Should be good enough though.
1462 HANDLE WINAPI DosFileHandleToWin32Handle( HFILE handle )
1464 HFILE16 hfile = (HFILE16)handle;
1465 if (hfile < 5 && !dos_handles[hfile]) FILE_InitProcessDosHandles();
1466 if ((hfile >= DOS_TABLE_SIZE) || !dos_handles[hfile])
1468 SetLastError( ERROR_INVALID_HANDLE );
1469 return INVALID_HANDLE_VALUE;
1471 return dos_handles[hfile];
1475 /***********************************************************************
1476 * DisposeLZ32Handle (KERNEL32.22)
1478 * Note: this is not entirely correct, we should only close the
1479 * 32-bit handle and not the 16-bit one, but we cannot do
1480 * this because of the way our DOS handles are implemented.
1481 * It shouldn't break anything though.
1483 void WINAPI DisposeLZ32Handle( HANDLE handle )
1485 int i;
1487 if (!handle || (handle == INVALID_HANDLE_VALUE)) return;
1489 for (i = 5; i < DOS_TABLE_SIZE; i++)
1490 if (dos_handles[i] == handle)
1492 dos_handles[i] = 0;
1493 CloseHandle( handle );
1494 break;
1499 /***********************************************************************
1500 * FILE_Dup2
1502 * dup2() function for DOS handles.
1504 HFILE16 FILE_Dup2( HFILE16 hFile1, HFILE16 hFile2 )
1506 HANDLE new_handle;
1508 if (hFile1 < 5 && !dos_handles[hFile1]) FILE_InitProcessDosHandles();
1510 if ((hFile1 >= DOS_TABLE_SIZE) || (hFile2 >= DOS_TABLE_SIZE) || !dos_handles[hFile1])
1512 SetLastError( ERROR_INVALID_HANDLE );
1513 return HFILE_ERROR16;
1515 if (!DuplicateHandle( GetCurrentProcess(), dos_handles[hFile1],
1516 GetCurrentProcess(), &new_handle,
1517 0, FALSE, DUPLICATE_SAME_ACCESS ))
1518 return HFILE_ERROR16;
1519 if (dos_handles[hFile2]) CloseHandle( dos_handles[hFile2] );
1520 dos_handles[hFile2] = new_handle;
1521 return hFile2;
1525 /***********************************************************************
1526 * _lclose (KERNEL.81)
1528 HFILE16 WINAPI _lclose16( HFILE16 hFile )
1530 if ((hFile >= DOS_TABLE_SIZE) || !dos_handles[hFile])
1532 SetLastError( ERROR_INVALID_HANDLE );
1533 return HFILE_ERROR16;
1535 TRACE("%d (handle32=%p)\n", hFile, dos_handles[hFile] );
1536 CloseHandle( dos_handles[hFile] );
1537 dos_handles[hFile] = 0;
1538 return 0;
1542 /***********************************************************************
1543 * _lclose (KERNEL32.@)
1545 HFILE WINAPI _lclose( HFILE hFile )
1547 TRACE("handle %d\n", hFile );
1548 return CloseHandle( (HANDLE)hFile ) ? 0 : HFILE_ERROR;
1551 /***********************************************************************
1552 * GetOverlappedResult (KERNEL32.@)
1554 * Check the result of an Asynchronous data transfer from a file.
1556 * RETURNS
1557 * TRUE on success
1558 * FALSE on failure
1560 * If successful (and relevant) lpTransferred will hold the number of
1561 * bytes transferred during the async operation.
1563 * BUGS
1565 * Currently only works for WaitCommEvent, ReadFile, WriteFile
1566 * with communications ports.
1569 BOOL WINAPI GetOverlappedResult(
1570 HANDLE hFile, /* [in] handle of file to check on */
1571 LPOVERLAPPED lpOverlapped, /* [in/out] pointer to overlapped */
1572 LPDWORD lpTransferred, /* [in/out] number of bytes transferred */
1573 BOOL bWait /* [in] wait for the transfer to complete ? */
1575 DWORD r;
1577 TRACE("(%p %p %p %x)\n", hFile, lpOverlapped, lpTransferred, bWait);
1579 if(lpOverlapped==NULL)
1581 ERR("lpOverlapped was null\n");
1582 return FALSE;
1584 if(!lpOverlapped->hEvent)
1586 ERR("lpOverlapped->hEvent was null\n");
1587 return FALSE;
1590 if ( bWait )
1592 do {
1593 TRACE("waiting on %p\n",lpOverlapped);
1594 r = WaitForSingleObjectEx(lpOverlapped->hEvent, INFINITE, TRUE);
1595 TRACE("wait on %p returned %ld\n",lpOverlapped,r);
1596 } while (r==STATUS_USER_APC);
1598 else if ( lpOverlapped->Internal == STATUS_PENDING )
1600 /* Wait in order to give APCs a chance to run. */
1601 /* This is cheating, so we must set the event again in case of success -
1602 it may be a non-manual reset event. */
1603 do {
1604 TRACE("waiting on %p\n",lpOverlapped);
1605 r = WaitForSingleObjectEx(lpOverlapped->hEvent, 0, TRUE);
1606 TRACE("wait on %p returned %ld\n",lpOverlapped,r);
1607 } while (r==STATUS_USER_APC);
1608 if ( r == WAIT_OBJECT_0 )
1609 NtSetEvent ( lpOverlapped->hEvent, NULL );
1612 if(lpTransferred)
1613 *lpTransferred = lpOverlapped->InternalHigh;
1615 switch ( lpOverlapped->Internal )
1617 case STATUS_SUCCESS:
1618 return TRUE;
1619 case STATUS_PENDING:
1620 SetLastError ( ERROR_IO_INCOMPLETE );
1621 if ( bWait ) ERR ("PENDING status after waiting!\n");
1622 return FALSE;
1623 default:
1624 SetLastError ( RtlNtStatusToDosError ( lpOverlapped->Internal ) );
1625 return FALSE;
1629 /***********************************************************************
1630 * CancelIo (KERNEL32.@)
1632 BOOL WINAPI CancelIo(HANDLE handle)
1634 async_private *ovp,*t;
1636 TRACE("handle = %p\n",handle);
1638 for (ovp = NtCurrentTeb()->pending_list; ovp; ovp = t)
1640 t = ovp->next;
1641 if ( ovp->handle == handle )
1642 cancel_async ( ovp );
1644 WaitForMultipleObjectsEx(0,NULL,FALSE,1,TRUE);
1645 return TRUE;
1648 /***********************************************************************
1649 * FILE_AsyncReadService (INTERNAL)
1651 * This function is called while the client is waiting on the
1652 * server, so we can't make any server calls here.
1654 static void FILE_AsyncReadService(async_private *ovp)
1656 async_fileio *fileio = (async_fileio*) ovp;
1657 LPOVERLAPPED lpOverlapped = fileio->lpOverlapped;
1658 int result, r;
1659 int already = lpOverlapped->InternalHigh;
1661 TRACE("%p %p\n", lpOverlapped, fileio->buffer );
1663 /* check to see if the data is ready (non-blocking) */
1665 if ( fileio->fd_type == FD_TYPE_SOCKET )
1666 result = read (ovp->fd, &fileio->buffer[already], fileio->count - already);
1667 else
1669 result = pread (ovp->fd, &fileio->buffer[already], fileio->count - already,
1670 OVERLAPPED_OFFSET (lpOverlapped) + already);
1671 if ((result < 0) && (errno == ESPIPE))
1672 result = read (ovp->fd, &fileio->buffer[already], fileio->count - already);
1675 if ( (result<0) && ((errno == EAGAIN) || (errno == EINTR)))
1677 TRACE("Deferred read %d\n",errno);
1678 r = STATUS_PENDING;
1679 goto async_end;
1682 /* check to see if the transfer is complete */
1683 if(result<0)
1685 r = FILE_GetNtStatus ();
1686 goto async_end;
1688 else if ( result == 0 )
1690 r = ( lpOverlapped->InternalHigh ? STATUS_SUCCESS : STATUS_END_OF_FILE );
1691 goto async_end;
1694 lpOverlapped->InternalHigh += result;
1695 TRACE("read %d more bytes %ld/%d so far\n",result,lpOverlapped->InternalHigh,fileio->count);
1697 if(lpOverlapped->InternalHigh >= fileio->count || fileio->fd_type == FD_TYPE_SOCKET )
1698 r = STATUS_SUCCESS;
1699 else
1700 r = STATUS_PENDING;
1702 async_end:
1703 lpOverlapped->Internal = r;
1706 /***********************************************************************
1707 * FILE_ReadFileEx (INTERNAL)
1709 static BOOL FILE_ReadFileEx(HANDLE hFile, LPVOID buffer, DWORD bytesToRead,
1710 LPOVERLAPPED overlapped,
1711 LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine,
1712 HANDLE hEvent)
1714 async_fileio *ovp;
1715 int fd;
1716 int flags;
1717 enum fd_type type;
1719 TRACE("file %p to buf %p num %ld %p func %p\n",
1720 hFile, buffer, bytesToRead, overlapped, lpCompletionRoutine);
1722 /* check that there is an overlapped struct */
1723 if (overlapped==NULL)
1725 SetLastError(ERROR_INVALID_PARAMETER);
1726 return FALSE;
1729 fd = FILE_GetUnixHandleType ( hFile, GENERIC_READ, &type, &flags);
1730 if ( fd < 0 )
1732 WARN ( "Couldn't get FD\n" );
1733 return FALSE;
1736 ovp = (async_fileio*) HeapAlloc(GetProcessHeap(), 0, sizeof (async_fileio));
1737 if(!ovp)
1739 TRACE("HeapAlloc Failed\n");
1740 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1741 goto error;
1744 ovp->async.ops = ( lpCompletionRoutine ? &fileio_async_ops : &fileio_nocomp_async_ops );
1745 ovp->async.handle = hFile;
1746 ovp->async.fd = fd;
1747 ovp->async.type = ASYNC_TYPE_READ;
1748 ovp->async.func = FILE_AsyncReadService;
1749 ovp->async.event = hEvent;
1750 ovp->lpOverlapped = overlapped;
1751 ovp->count = bytesToRead;
1752 ovp->completion_func = lpCompletionRoutine;
1753 ovp->buffer = buffer;
1754 ovp->fd_type = type;
1756 return !register_new_async (&ovp->async);
1758 error:
1759 close (fd);
1760 return FALSE;
1764 /***********************************************************************
1765 * ReadFileEx (KERNEL32.@)
1767 BOOL WINAPI ReadFileEx(HANDLE hFile, LPVOID buffer, DWORD bytesToRead,
1768 LPOVERLAPPED overlapped,
1769 LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine)
1771 overlapped->InternalHigh = 0;
1772 return FILE_ReadFileEx(hFile,buffer,bytesToRead,overlapped,lpCompletionRoutine, INVALID_HANDLE_VALUE);
1775 static BOOL FILE_TimeoutRead(HANDLE hFile, LPVOID buffer, DWORD bytesToRead, LPDWORD bytesRead)
1777 OVERLAPPED ov;
1778 BOOL r = FALSE;
1780 TRACE("%p %p %ld %p\n", hFile, buffer, bytesToRead, bytesRead );
1782 ZeroMemory(&ov, sizeof (OVERLAPPED));
1783 if(STATUS_SUCCESS==NtCreateEvent(&ov.hEvent, SYNCHRONIZE, NULL, 0, 0))
1785 if(FILE_ReadFileEx(hFile, buffer, bytesToRead, &ov, NULL, ov.hEvent))
1787 r = GetOverlappedResult(hFile, &ov, bytesRead, TRUE);
1790 CloseHandle(ov.hEvent);
1791 return r;
1794 /***********************************************************************
1795 * ReadFile (KERNEL32.@)
1797 BOOL WINAPI ReadFile( HANDLE hFile, LPVOID buffer, DWORD bytesToRead,
1798 LPDWORD bytesRead, LPOVERLAPPED overlapped )
1800 int unix_handle, result, flags;
1801 enum fd_type type;
1803 TRACE("%p %p %ld %p %p\n", hFile, buffer, bytesToRead,
1804 bytesRead, overlapped );
1806 if (bytesRead) *bytesRead = 0; /* Do this before anything else */
1807 if (!bytesToRead) return TRUE;
1809 unix_handle = FILE_GetUnixHandleType( hFile, GENERIC_READ, &type, &flags );
1811 if (flags & FD_FLAG_OVERLAPPED)
1813 if (unix_handle == -1) return FALSE;
1814 if ( (overlapped==NULL) || NtResetEvent( overlapped->hEvent, NULL ) )
1816 TRACE("Overlapped not specified or invalid event flag\n");
1817 close(unix_handle);
1818 SetLastError(ERROR_INVALID_PARAMETER);
1819 return FALSE;
1822 close(unix_handle);
1823 overlapped->InternalHigh = 0;
1825 if(!FILE_ReadFileEx(hFile, buffer, bytesToRead, overlapped, NULL, overlapped->hEvent))
1826 return FALSE;
1828 if ( !GetOverlappedResult (hFile, overlapped, bytesRead, FALSE) )
1830 if ( GetLastError() == ERROR_IO_INCOMPLETE )
1831 SetLastError ( ERROR_IO_PENDING );
1832 return FALSE;
1835 return TRUE;
1837 if (flags & FD_FLAG_TIMEOUT)
1839 close(unix_handle);
1840 return FILE_TimeoutRead(hFile, buffer, bytesToRead, bytesRead);
1842 switch(type)
1844 case FD_TYPE_SMB:
1845 return SMB_ReadFile(hFile, buffer, bytesToRead, bytesRead, NULL);
1847 case FD_TYPE_CONSOLE:
1848 return FILE_ReadConsole(hFile, buffer, bytesToRead, bytesRead, NULL);
1850 case FD_TYPE_DEFAULT:
1851 /* normal unix files */
1852 if (unix_handle == -1) return FALSE;
1853 if (overlapped)
1855 DWORD highOffset = overlapped->OffsetHigh;
1856 if ( (INVALID_SET_FILE_POINTER == SetFilePointer(hFile, overlapped->Offset,
1857 &highOffset, FILE_BEGIN)) &&
1858 (GetLastError() != NO_ERROR) )
1860 close(unix_handle);
1861 return FALSE;
1864 break;
1866 default:
1867 if (unix_handle == -1)
1868 return FALSE;
1871 if(overlapped)
1873 off_t offset = OVERLAPPED_OFFSET(overlapped);
1874 if(lseek(unix_handle, offset, SEEK_SET) == -1)
1876 close(unix_handle);
1877 SetLastError(ERROR_INVALID_PARAMETER);
1878 return FALSE;
1882 /* code for synchronous reads */
1883 while ((result = read( unix_handle, buffer, bytesToRead )) == -1)
1885 if ((errno == EAGAIN) || (errno == EINTR)) continue;
1886 if ((errno == EFAULT) && !IsBadWritePtr( buffer, bytesToRead )) continue;
1887 FILE_SetDosError();
1888 break;
1890 close( unix_handle );
1891 if (result == -1) return FALSE;
1892 if (bytesRead) *bytesRead = result;
1893 return TRUE;
1897 /***********************************************************************
1898 * FILE_AsyncWriteService (INTERNAL)
1900 * This function is called while the client is waiting on the
1901 * server, so we can't make any server calls here.
1903 static void FILE_AsyncWriteService(struct async_private *ovp)
1905 async_fileio *fileio = (async_fileio *) ovp;
1906 LPOVERLAPPED lpOverlapped = fileio->lpOverlapped;
1907 int result, r;
1908 int already = lpOverlapped->InternalHigh;
1910 TRACE("(%p %p)\n",lpOverlapped,fileio->buffer);
1912 /* write some data (non-blocking) */
1914 if ( fileio->fd_type == FD_TYPE_SOCKET )
1915 result = write(ovp->fd, &fileio->buffer[already], fileio->count - already);
1916 else
1918 result = pwrite(ovp->fd, &fileio->buffer[already], fileio->count - already,
1919 OVERLAPPED_OFFSET (lpOverlapped) + already);
1920 if ((result < 0) && (errno == ESPIPE))
1921 result = write(ovp->fd, &fileio->buffer[already], fileio->count - already);
1924 if ( (result<0) && ((errno == EAGAIN) || (errno == EINTR)))
1926 r = STATUS_PENDING;
1927 goto async_end;
1930 /* check to see if the transfer is complete */
1931 if(result<0)
1933 r = FILE_GetNtStatus ();
1934 goto async_end;
1937 lpOverlapped->InternalHigh += result;
1939 TRACE("wrote %d more bytes %ld/%d so far\n",result,lpOverlapped->InternalHigh,fileio->count);
1941 if(lpOverlapped->InternalHigh < fileio->count)
1942 r = STATUS_PENDING;
1943 else
1944 r = STATUS_SUCCESS;
1946 async_end:
1947 lpOverlapped->Internal = r;
1950 /***********************************************************************
1951 * FILE_WriteFileEx
1953 static BOOL FILE_WriteFileEx(HANDLE hFile, LPCVOID buffer, DWORD bytesToWrite,
1954 LPOVERLAPPED overlapped,
1955 LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine,
1956 HANDLE hEvent)
1958 async_fileio *ovp;
1959 int fd;
1960 int flags;
1961 enum fd_type type;
1963 TRACE("file %p to buf %p num %ld %p func %p handle %p\n",
1964 hFile, buffer, bytesToWrite, overlapped, lpCompletionRoutine, hEvent);
1966 if (overlapped == NULL)
1968 SetLastError(ERROR_INVALID_PARAMETER);
1969 return FALSE;
1972 fd = FILE_GetUnixHandleType ( hFile, GENERIC_WRITE, &type, &flags );
1973 if ( fd < 0 )
1975 TRACE( "Couldn't get FD\n" );
1976 return FALSE;
1979 ovp = (async_fileio*) HeapAlloc(GetProcessHeap(), 0, sizeof (async_fileio));
1980 if(!ovp)
1982 TRACE("HeapAlloc Failed\n");
1983 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1984 goto error;
1987 ovp->async.ops = ( lpCompletionRoutine ? &fileio_async_ops : &fileio_nocomp_async_ops );
1988 ovp->async.handle = hFile;
1989 ovp->async.fd = fd;
1990 ovp->async.type = ASYNC_TYPE_WRITE;
1991 ovp->async.func = FILE_AsyncWriteService;
1992 ovp->lpOverlapped = overlapped;
1993 ovp->async.event = hEvent;
1994 ovp->buffer = (LPVOID) buffer;
1995 ovp->count = bytesToWrite;
1996 ovp->completion_func = lpCompletionRoutine;
1997 ovp->fd_type = type;
1999 return !register_new_async (&ovp->async);
2001 error:
2002 close (fd);
2003 return FALSE;
2006 /***********************************************************************
2007 * WriteFileEx (KERNEL32.@)
2009 BOOL WINAPI WriteFileEx(HANDLE hFile, LPCVOID buffer, DWORD bytesToWrite,
2010 LPOVERLAPPED overlapped,
2011 LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine)
2013 overlapped->InternalHigh = 0;
2015 return FILE_WriteFileEx(hFile, buffer, bytesToWrite, overlapped, lpCompletionRoutine, INVALID_HANDLE_VALUE);
2018 /***********************************************************************
2019 * WriteFile (KERNEL32.@)
2021 BOOL WINAPI WriteFile( HANDLE hFile, LPCVOID buffer, DWORD bytesToWrite,
2022 LPDWORD bytesWritten, LPOVERLAPPED overlapped )
2024 int unix_handle, result, flags;
2025 enum fd_type type;
2027 TRACE("%p %p %ld %p %p\n", hFile, buffer, bytesToWrite,
2028 bytesWritten, overlapped );
2030 if (bytesWritten) *bytesWritten = 0; /* Do this before anything else */
2031 if (!bytesToWrite) return TRUE;
2033 unix_handle = FILE_GetUnixHandleType( hFile, GENERIC_WRITE, &type, &flags );
2035 if (flags & FD_FLAG_OVERLAPPED)
2037 if (unix_handle == -1) return FALSE;
2038 if ( (overlapped==NULL) || NtResetEvent( overlapped->hEvent, NULL ) )
2040 TRACE("Overlapped not specified or invalid event flag\n");
2041 close(unix_handle);
2042 SetLastError(ERROR_INVALID_PARAMETER);
2043 return FALSE;
2046 close(unix_handle);
2047 overlapped->InternalHigh = 0;
2049 if(!FILE_WriteFileEx(hFile, buffer, bytesToWrite, overlapped, NULL, overlapped->hEvent))
2050 return FALSE;
2052 if ( !GetOverlappedResult (hFile, overlapped, bytesWritten, FALSE) )
2054 if ( GetLastError() == ERROR_IO_INCOMPLETE )
2055 SetLastError ( ERROR_IO_PENDING );
2056 return FALSE;
2059 return TRUE;
2062 switch(type)
2064 case FD_TYPE_CONSOLE:
2065 TRACE("%p %s %ld %p %p\n", hFile, debugstr_an(buffer, bytesToWrite), bytesToWrite,
2066 bytesWritten, overlapped );
2067 return FILE_WriteConsole(hFile, buffer, bytesToWrite, bytesWritten, NULL);
2069 case FD_TYPE_DEFAULT:
2070 if (unix_handle == -1) return FALSE;
2072 if(overlapped)
2074 DWORD highOffset = overlapped->OffsetHigh;
2075 if ( (INVALID_SET_FILE_POINTER == SetFilePointer(hFile, overlapped->Offset,
2076 &highOffset, FILE_BEGIN)) &&
2077 (GetLastError() != NO_ERROR) )
2079 close(unix_handle);
2080 return FALSE;
2083 break;
2085 default:
2086 if (unix_handle == -1)
2087 return FALSE;
2088 if (overlapped)
2090 close(unix_handle);
2091 SetLastError(ERROR_INVALID_PARAMETER);
2092 return FALSE;
2094 break;
2097 if(overlapped)
2099 off_t offset = OVERLAPPED_OFFSET(overlapped);
2100 if(lseek(unix_handle, offset, SEEK_SET) == -1)
2102 close(unix_handle);
2103 SetLastError(ERROR_INVALID_PARAMETER);
2104 return FALSE;
2108 /* synchronous file write */
2109 while ((result = write( unix_handle, buffer, bytesToWrite )) == -1)
2111 if ((errno == EAGAIN) || (errno == EINTR)) continue;
2112 if ((errno == EFAULT) && !IsBadReadPtr( buffer, bytesToWrite )) continue;
2113 if (errno == ENOSPC)
2114 SetLastError( ERROR_DISK_FULL );
2115 else
2116 FILE_SetDosError();
2117 break;
2119 close( unix_handle );
2120 if (result == -1) return FALSE;
2121 if (bytesWritten) *bytesWritten = result;
2122 return TRUE;
2126 /***********************************************************************
2127 * _hread (KERNEL.349)
2129 LONG WINAPI WIN16_hread( HFILE16 hFile, SEGPTR buffer, LONG count )
2131 LONG maxlen;
2133 TRACE("%d %08lx %ld\n",
2134 hFile, (DWORD)buffer, count );
2136 /* Some programs pass a count larger than the allocated buffer */
2137 maxlen = GetSelectorLimit16( SELECTOROF(buffer) ) - OFFSETOF(buffer) + 1;
2138 if (count > maxlen) count = maxlen;
2139 return _lread((HFILE)DosFileHandleToWin32Handle(hFile), MapSL(buffer), count );
2143 /***********************************************************************
2144 * _lread (KERNEL.82)
2146 UINT16 WINAPI WIN16_lread( HFILE16 hFile, SEGPTR buffer, UINT16 count )
2148 return (UINT16)WIN16_hread( hFile, buffer, (LONG)count );
2152 /***********************************************************************
2153 * _lread (KERNEL32.@)
2155 UINT WINAPI _lread( HFILE handle, LPVOID buffer, UINT count )
2157 DWORD result;
2158 if (!ReadFile( (HANDLE)handle, buffer, count, &result, NULL )) return -1;
2159 return result;
2163 /***********************************************************************
2164 * _lread16 (KERNEL.82)
2166 UINT16 WINAPI _lread16( HFILE16 hFile, LPVOID buffer, UINT16 count )
2168 return (UINT16)_lread((HFILE)DosFileHandleToWin32Handle(hFile), buffer, (LONG)count );
2172 /***********************************************************************
2173 * _lcreat (KERNEL.83)
2175 HFILE16 WINAPI _lcreat16( LPCSTR path, INT16 attr )
2177 return Win32HandleToDosFileHandle( (HANDLE)_lcreat( path, attr ) );
2181 /***********************************************************************
2182 * _lcreat (KERNEL32.@)
2184 HFILE WINAPI _lcreat( LPCSTR path, INT attr )
2186 /* Mask off all flags not explicitly allowed by the doc */
2187 attr &= FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM;
2188 TRACE("%s %02x\n", path, attr );
2189 return (HFILE)CreateFileA( path, GENERIC_READ | GENERIC_WRITE,
2190 FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
2191 CREATE_ALWAYS, attr, 0 );
2195 /***********************************************************************
2196 * SetFilePointer (KERNEL32.@)
2198 DWORD WINAPI SetFilePointer( HANDLE hFile, LONG distance, LONG *highword,
2199 DWORD method )
2201 DWORD ret = INVALID_SET_FILE_POINTER;
2203 TRACE("handle %p offset %ld high %ld origin %ld\n",
2204 hFile, distance, highword?*highword:0, method );
2206 SERVER_START_REQ( set_file_pointer )
2208 req->handle = hFile;
2209 req->low = distance;
2210 req->high = highword ? *highword : (distance >= 0) ? 0 : -1;
2211 /* FIXME: assumes 1:1 mapping between Windows and Unix seek constants */
2212 req->whence = method;
2213 SetLastError( 0 );
2214 if (!wine_server_call_err( req ))
2216 ret = reply->new_low;
2217 if (highword) *highword = reply->new_high;
2220 SERVER_END_REQ;
2221 return ret;
2225 /***********************************************************************
2226 * _llseek (KERNEL.84)
2228 * FIXME:
2229 * Seeking before the start of the file should be allowed for _llseek16,
2230 * but cause subsequent I/O operations to fail (cf. interrupt list)
2233 LONG WINAPI _llseek16( HFILE16 hFile, LONG lOffset, INT16 nOrigin )
2235 return SetFilePointer( DosFileHandleToWin32Handle(hFile), lOffset, NULL, nOrigin );
2239 /***********************************************************************
2240 * _llseek (KERNEL32.@)
2242 LONG WINAPI _llseek( HFILE hFile, LONG lOffset, INT nOrigin )
2244 return SetFilePointer( (HANDLE)hFile, lOffset, NULL, nOrigin );
2248 /***********************************************************************
2249 * _lopen (KERNEL.85)
2251 HFILE16 WINAPI _lopen16( LPCSTR path, INT16 mode )
2253 return Win32HandleToDosFileHandle( (HANDLE)_lopen( path, mode ) );
2257 /***********************************************************************
2258 * _lopen (KERNEL32.@)
2260 HFILE WINAPI _lopen( LPCSTR path, INT mode )
2262 DWORD access, sharing;
2264 TRACE("('%s',%04x)\n", path, mode );
2265 FILE_ConvertOFMode( mode, &access, &sharing );
2266 return (HFILE)CreateFileA( path, access, sharing, NULL, OPEN_EXISTING, 0, 0 );
2270 /***********************************************************************
2271 * _lwrite (KERNEL.86)
2273 UINT16 WINAPI _lwrite16( HFILE16 hFile, LPCSTR buffer, UINT16 count )
2275 return (UINT16)_hwrite( (HFILE)DosFileHandleToWin32Handle(hFile), buffer, (LONG)count );
2278 /***********************************************************************
2279 * _lwrite (KERNEL32.@)
2281 UINT WINAPI _lwrite( HFILE hFile, LPCSTR buffer, UINT count )
2283 return (UINT)_hwrite( hFile, buffer, (LONG)count );
2287 /***********************************************************************
2288 * _hread16 (KERNEL.349)
2290 LONG WINAPI _hread16( HFILE16 hFile, LPVOID buffer, LONG count)
2292 return _lread( (HFILE)DosFileHandleToWin32Handle(hFile), buffer, count );
2296 /***********************************************************************
2297 * _hread (KERNEL32.@)
2299 LONG WINAPI _hread( HFILE hFile, LPVOID buffer, LONG count)
2301 return _lread( hFile, buffer, count );
2305 /***********************************************************************
2306 * _hwrite (KERNEL.350)
2308 LONG WINAPI _hwrite16( HFILE16 hFile, LPCSTR buffer, LONG count )
2310 return _hwrite( (HFILE)DosFileHandleToWin32Handle(hFile), buffer, count );
2314 /***********************************************************************
2315 * _hwrite (KERNEL32.@)
2317 * experimentation yields that _lwrite:
2318 * o truncates the file at the current position with
2319 * a 0 len write
2320 * o returns 0 on a 0 length write
2321 * o works with console handles
2324 LONG WINAPI _hwrite( HFILE handle, LPCSTR buffer, LONG count )
2326 DWORD result;
2328 TRACE("%d %p %ld\n", handle, buffer, count );
2330 if (!count)
2332 /* Expand or truncate at current position */
2333 if (!SetEndOfFile( (HANDLE)handle )) return HFILE_ERROR;
2334 return 0;
2336 if (!WriteFile( (HANDLE)handle, buffer, count, &result, NULL ))
2337 return HFILE_ERROR;
2338 return result;
2342 /***********************************************************************
2343 * SetHandleCount (KERNEL.199)
2345 UINT16 WINAPI SetHandleCount16( UINT16 count )
2347 return SetHandleCount( count );
2351 /*************************************************************************
2352 * SetHandleCount (KERNEL32.@)
2354 UINT WINAPI SetHandleCount( UINT count )
2356 return min( 256, count );
2360 /***********************************************************************
2361 * FlushFileBuffers (KERNEL32.@)
2363 BOOL WINAPI FlushFileBuffers( HANDLE hFile )
2365 NTSTATUS nts;
2366 IO_STATUS_BLOCK ioblk;
2368 nts = NtFlushBuffersFile( hFile, &ioblk );
2369 if (nts != STATUS_SUCCESS)
2371 SetLastError( RtlNtStatusToDosError( nts ) );
2372 return FALSE;
2375 return TRUE;
2379 /**************************************************************************
2380 * SetEndOfFile (KERNEL32.@)
2382 BOOL WINAPI SetEndOfFile( HANDLE hFile )
2384 BOOL ret;
2385 SERVER_START_REQ( truncate_file )
2387 req->handle = hFile;
2388 ret = !wine_server_call_err( req );
2390 SERVER_END_REQ;
2391 return ret;
2395 /***********************************************************************
2396 * DeleteFile (KERNEL.146)
2398 BOOL16 WINAPI DeleteFile16( LPCSTR path )
2400 return DeleteFileA( path );
2404 /***********************************************************************
2405 * DeleteFileW (KERNEL32.@)
2407 BOOL WINAPI DeleteFileW( LPCWSTR path )
2409 DOS_FULL_NAME full_name;
2410 HANDLE hFile;
2412 TRACE("%s\n", debugstr_w(path) );
2413 if (!path || !*path)
2415 SetLastError(ERROR_PATH_NOT_FOUND);
2416 return FALSE;
2418 if (DOSFS_GetDevice( path ))
2420 WARN("cannot remove DOS device %s!\n", debugstr_w(path));
2421 SetLastError( ERROR_FILE_NOT_FOUND );
2422 return FALSE;
2425 if (!DOSFS_GetFullName( path, TRUE, &full_name )) return FALSE;
2427 /* check if we are allowed to delete the source */
2428 hFile = FILE_CreateFile( full_name.long_name, GENERIC_READ|GENERIC_WRITE, 0,
2429 NULL, OPEN_EXISTING, 0, 0, TRUE,
2430 GetDriveTypeW( full_name.short_name ) );
2431 if (!hFile) return FALSE;
2433 if (unlink( full_name.long_name ) == -1)
2435 FILE_SetDosError();
2436 CloseHandle(hFile);
2437 return FALSE;
2439 CloseHandle(hFile);
2440 return TRUE;
2444 /***********************************************************************
2445 * DeleteFileA (KERNEL32.@)
2447 BOOL WINAPI DeleteFileA( LPCSTR path )
2449 UNICODE_STRING pathW;
2450 BOOL ret = FALSE;
2452 if (!path)
2454 SetLastError(ERROR_INVALID_PARAMETER);
2455 return FALSE;
2458 if (RtlCreateUnicodeStringFromAsciiz(&pathW, path))
2460 ret = DeleteFileW(pathW.Buffer);
2461 RtlFreeUnicodeString(&pathW);
2463 else
2464 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
2465 return ret;
2469 /***********************************************************************
2470 * GetFileType (KERNEL32.@)
2472 DWORD WINAPI GetFileType( HANDLE hFile )
2474 DWORD ret = FILE_TYPE_UNKNOWN;
2475 SERVER_START_REQ( get_file_info )
2477 req->handle = hFile;
2478 if (!wine_server_call_err( req )) ret = reply->type;
2480 SERVER_END_REQ;
2481 return ret;
2485 /* check if a file name is for an executable file (.exe or .com) */
2486 inline static BOOL is_executable( const char *name )
2488 int len = strlen(name);
2490 if (len < 4) return FALSE;
2491 return (!strcasecmp( name + len - 4, ".exe" ) ||
2492 !strcasecmp( name + len - 4, ".com" ));
2496 /***********************************************************************
2497 * FILE_AddBootRenameEntry
2499 * Adds an entry to the registry that is loaded when windows boots and
2500 * checks if there are some files to be removed or renamed/moved.
2501 * <fn1> has to be valid and <fn2> may be NULL. If both pointers are
2502 * non-NULL then the file is moved, otherwise it is deleted. The
2503 * entry of the registrykey is always appended with two zero
2504 * terminated strings. If <fn2> is NULL then the second entry is
2505 * simply a single 0-byte. Otherwise the second filename goes
2506 * there. The entries are prepended with \??\ before the path and the
2507 * second filename gets also a '!' as the first character if
2508 * MOVEFILE_REPLACE_EXISTING is set. After the final string another
2509 * 0-byte follows to indicate the end of the strings.
2510 * i.e.:
2511 * \??\D:\test\file1[0]
2512 * !\??\D:\test\file1_renamed[0]
2513 * \??\D:\Test|delete[0]
2514 * [0] <- file is to be deleted, second string empty
2515 * \??\D:\test\file2[0]
2516 * !\??\D:\test\file2_renamed[0]
2517 * [0] <- indicates end of strings
2519 * or:
2520 * \??\D:\test\file1[0]
2521 * !\??\D:\test\file1_renamed[0]
2522 * \??\D:\Test|delete[0]
2523 * [0] <- file is to be deleted, second string empty
2524 * [0] <- indicates end of strings
2527 static BOOL FILE_AddBootRenameEntry( LPCWSTR fn1, LPCWSTR fn2, DWORD flags )
2529 static const WCHAR PreString[] = {'\\','?','?','\\',0};
2530 static const WCHAR ValueName[] = {'P','e','n','d','i','n','g',
2531 'F','i','l','e','R','e','n','a','m','e',
2532 'O','p','e','r','a','t','i','o','n','s',0};
2533 static const WCHAR SessionW[] = {'M','a','c','h','i','n','e','\\',
2534 'S','y','s','t','e','m','\\',
2535 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
2536 'C','o','n','t','r','o','l','\\',
2537 'S','e','s','s','i','o','n',' ','M','a','n','a','g','e','r',0};
2538 static const int info_size = FIELD_OFFSET( KEY_VALUE_PARTIAL_INFORMATION, Data );
2540 OBJECT_ATTRIBUTES attr;
2541 UNICODE_STRING nameW;
2542 KEY_VALUE_PARTIAL_INFORMATION *info;
2543 BOOL rc = FALSE;
2544 HKEY Reboot = 0;
2545 DWORD len0, len1, len2;
2546 DWORD DataSize = 0;
2547 BYTE *Buffer = NULL;
2548 WCHAR *p;
2550 attr.Length = sizeof(attr);
2551 attr.RootDirectory = 0;
2552 attr.ObjectName = &nameW;
2553 attr.Attributes = 0;
2554 attr.SecurityDescriptor = NULL;
2555 attr.SecurityQualityOfService = NULL;
2556 RtlInitUnicodeString( &nameW, SessionW );
2558 if (NtCreateKey( &Reboot, KEY_ALL_ACCESS, &attr, 0, NULL, 0, NULL ) != STATUS_SUCCESS)
2560 WARN("Error creating key for reboot managment [%s]\n",
2561 "SYSTEM\\CurrentControlSet\\Control\\Session Manager");
2562 return FALSE;
2565 len0 = strlenW(PreString);
2566 len1 = strlenW(fn1) + len0 + 1;
2567 if (fn2)
2569 len2 = strlenW(fn2) + len0 + 1;
2570 if (flags & MOVEFILE_REPLACE_EXISTING) len2++; /* Plus 1 because of the leading '!' */
2572 else len2 = 1; /* minimum is the 0 characters for the empty second string */
2574 /* convert characters to bytes */
2575 len0 *= sizeof(WCHAR);
2576 len1 *= sizeof(WCHAR);
2577 len2 *= sizeof(WCHAR);
2579 RtlInitUnicodeString( &nameW, ValueName );
2581 /* First we check if the key exists and if so how many bytes it already contains. */
2582 if (NtQueryValueKey( Reboot, &nameW, KeyValuePartialInformation,
2583 NULL, 0, &DataSize ) == STATUS_BUFFER_OVERFLOW)
2585 if (!(Buffer = HeapAlloc( GetProcessHeap(), 0, DataSize + len1 + len2 + sizeof(WCHAR) )))
2586 goto Quit;
2587 if (NtQueryValueKey( Reboot, &nameW, KeyValuePartialInformation,
2588 Buffer, DataSize, &DataSize )) goto Quit;
2589 info = (KEY_VALUE_PARTIAL_INFORMATION *)Buffer;
2590 if (info->Type != REG_MULTI_SZ) goto Quit;
2591 if (DataSize > sizeof(info)) DataSize -= sizeof(WCHAR); /* remove terminating null (will be added back later) */
2593 else
2595 DataSize = info_size;
2596 if (!(Buffer = HeapAlloc( GetProcessHeap(), 0, DataSize + len1 + len2 + sizeof(WCHAR) )))
2597 goto Quit;
2600 p = (WCHAR *)(Buffer + DataSize);
2601 strcpyW( p, PreString );
2602 strcatW( p, fn1 );
2603 DataSize += len1;
2604 if (fn2)
2606 p = (WCHAR *)(Buffer + DataSize);
2607 if (flags & MOVEFILE_REPLACE_EXISTING)
2608 *p++ = '!';
2609 strcpyW( p, PreString );
2610 strcatW( p, fn2 );
2611 DataSize += len2;
2613 else
2615 p = (WCHAR *)(Buffer + DataSize);
2616 *p = 0;
2617 DataSize += sizeof(WCHAR);
2620 /* add final null */
2621 p = (WCHAR *)(Buffer + DataSize);
2622 *p = 0;
2623 DataSize += sizeof(WCHAR);
2625 rc = !NtSetValueKey(Reboot, &nameW, 0, REG_MULTI_SZ, Buffer + info_size, DataSize - info_size);
2627 Quit:
2628 if (Reboot) NtClose(Reboot);
2629 if (Buffer) HeapFree( GetProcessHeap(), 0, Buffer );
2630 return(rc);
2634 /**************************************************************************
2635 * MoveFileExW (KERNEL32.@)
2637 BOOL WINAPI MoveFileExW( LPCWSTR fn1, LPCWSTR fn2, DWORD flag )
2639 DOS_FULL_NAME full_name1, full_name2;
2640 HANDLE hFile;
2641 DWORD attr = INVALID_FILE_ATTRIBUTES;
2643 TRACE("(%s,%s,%04lx)\n", debugstr_w(fn1), debugstr_w(fn2), flag);
2645 /* FIXME: <Gerhard W. Gruber>sparhawk@gmx.at
2646 In case of W9x and lesser this function should return 120 (ERROR_CALL_NOT_IMPLEMENTED)
2647 to be really compatible. Most programs wont have any problems though. In case
2648 you encounter one, this is what you should return here. I don't know what's up
2649 with NT 3.5. Is this function available there or not?
2650 Does anybody really care about 3.5? :)
2653 /* Filename1 has to be always set to a valid path. Filename2 may be NULL
2654 if the source file has to be deleted.
2656 if (!fn1) {
2657 SetLastError(ERROR_INVALID_PARAMETER);
2658 return FALSE;
2661 /* This function has to be run through in order to process the name properly.
2662 If the BOOTDELAY flag is set, the file doesn't need to exist though. At least
2663 that is the behaviour on NT 4.0. The operation accepts the filenames as
2664 they are given but it can't reply with a reasonable returncode. Success
2665 means in that case success for entering the values into the registry.
2667 if(!DOSFS_GetFullName( fn1, TRUE, &full_name1 ))
2669 if(!(flag & MOVEFILE_DELAY_UNTIL_REBOOT))
2670 return FALSE;
2673 if (fn2) /* !fn2 means delete fn1 */
2675 if (DOSFS_GetFullName( fn2, TRUE, &full_name2 ))
2677 if(!(flag & MOVEFILE_DELAY_UNTIL_REBOOT))
2679 /* target exists, check if we may overwrite */
2680 if (!(flag & MOVEFILE_REPLACE_EXISTING))
2682 SetLastError( ERROR_FILE_EXISTS );
2683 return FALSE;
2687 else
2689 if (!DOSFS_GetFullName( fn2, FALSE, &full_name2 ))
2691 if(!(flag & MOVEFILE_DELAY_UNTIL_REBOOT))
2692 return FALSE;
2696 /* Source name and target path are valid */
2698 if (flag & MOVEFILE_DELAY_UNTIL_REBOOT)
2700 return FILE_AddBootRenameEntry( fn1, fn2, flag );
2703 attr = GetFileAttributesW( fn1 );
2704 if ( attr == INVALID_FILE_ATTRIBUTES ) return FALSE;
2706 /* check if we are allowed to rename the source */
2707 hFile = FILE_CreateFile( full_name1.long_name, 0, 0,
2708 NULL, OPEN_EXISTING, 0, 0, TRUE,
2709 GetDriveTypeW( full_name1.short_name ) );
2710 if (!hFile)
2712 if (GetLastError() != ERROR_ACCESS_DENIED) return FALSE;
2713 if ( !(attr & FILE_ATTRIBUTE_DIRECTORY) ) return FALSE;
2714 /* if it's a directory we can continue */
2716 else CloseHandle(hFile);
2718 /* check, if we are allowed to delete the destination,
2719 ** (but the file not being there is fine) */
2720 hFile = FILE_CreateFile( full_name2.long_name, GENERIC_READ|GENERIC_WRITE, 0,
2721 NULL, OPEN_EXISTING, 0, 0, TRUE,
2722 GetDriveTypeW( full_name2.short_name ) );
2723 if(!hFile && GetLastError() != ERROR_FILE_NOT_FOUND) return FALSE;
2724 CloseHandle(hFile);
2726 if (full_name1.drive != full_name2.drive)
2728 if (!(flag & MOVEFILE_COPY_ALLOWED))
2730 SetLastError( ERROR_NOT_SAME_DEVICE );
2731 return FALSE;
2733 else if ( attr & FILE_ATTRIBUTE_DIRECTORY )
2735 /* Strange, but that's what Windows returns */
2736 SetLastError ( ERROR_ACCESS_DENIED );
2737 return FALSE;
2740 if (rename( full_name1.long_name, full_name2.long_name ) == -1)
2741 /* Try copy/delete unless it's a directory. */
2742 /* FIXME: This does not handle the (unlikely) case that the two locations
2743 are on the same Wine drive, but on different Unix file systems. */
2745 if ( attr & FILE_ATTRIBUTE_DIRECTORY )
2747 FILE_SetDosError();
2748 return FALSE;
2750 else
2752 if ( ! CopyFileW( fn1, fn2, !(flag & MOVEFILE_REPLACE_EXISTING) ))
2753 return FALSE;
2754 if ( ! DeleteFileW ( fn1 ) )
2755 return FALSE;
2758 if (is_executable( full_name1.long_name ) != is_executable( full_name2.long_name ))
2760 struct stat fstat;
2761 if (stat( full_name2.long_name, &fstat ) != -1)
2763 if (is_executable( full_name2.long_name ))
2764 /* set executable bit where read bit is set */
2765 fstat.st_mode |= (fstat.st_mode & 0444) >> 2;
2766 else
2767 fstat.st_mode &= ~0111;
2768 chmod( full_name2.long_name, fstat.st_mode );
2771 return TRUE;
2773 else /* fn2 == NULL means delete source */
2775 if (flag & MOVEFILE_DELAY_UNTIL_REBOOT)
2777 if (flag & MOVEFILE_COPY_ALLOWED) {
2778 WARN("Illegal flag\n");
2779 SetLastError( ERROR_GEN_FAILURE );
2780 return FALSE;
2783 return FILE_AddBootRenameEntry( fn1, NULL, flag );
2786 if (unlink( full_name1.long_name ) == -1)
2788 FILE_SetDosError();
2789 return FALSE;
2791 return TRUE; /* successfully deleted */
2795 /**************************************************************************
2796 * MoveFileExA (KERNEL32.@)
2798 BOOL WINAPI MoveFileExA( LPCSTR fn1, LPCSTR fn2, DWORD flag )
2800 UNICODE_STRING fn1W, fn2W;
2801 BOOL ret;
2803 if (!fn1)
2805 SetLastError(ERROR_INVALID_PARAMETER);
2806 return FALSE;
2809 RtlCreateUnicodeStringFromAsciiz(&fn1W, fn1);
2810 if (fn2) RtlCreateUnicodeStringFromAsciiz(&fn2W, fn2);
2811 else fn2W.Buffer = NULL;
2813 ret = MoveFileExW( fn1W.Buffer, fn2W.Buffer, flag );
2815 RtlFreeUnicodeString(&fn1W);
2816 RtlFreeUnicodeString(&fn2W);
2817 return ret;
2821 /**************************************************************************
2822 * MoveFileW (KERNEL32.@)
2824 * Move file or directory
2826 BOOL WINAPI MoveFileW( LPCWSTR fn1, LPCWSTR fn2 )
2828 return MoveFileExW( fn1, fn2, MOVEFILE_COPY_ALLOWED );
2832 /**************************************************************************
2833 * MoveFileA (KERNEL32.@)
2835 BOOL WINAPI MoveFileA( LPCSTR fn1, LPCSTR fn2 )
2837 return MoveFileExA( fn1, fn2, MOVEFILE_COPY_ALLOWED );
2841 /**************************************************************************
2842 * CopyFileW (KERNEL32.@)
2844 BOOL WINAPI CopyFileW( LPCWSTR source, LPCWSTR dest, BOOL fail_if_exists )
2846 HANDLE h1, h2;
2847 BY_HANDLE_FILE_INFORMATION info;
2848 DWORD count;
2849 BOOL ret = FALSE;
2850 char buffer[2048];
2852 if (!source || !dest)
2854 SetLastError(ERROR_INVALID_PARAMETER);
2855 return FALSE;
2858 TRACE("%s -> %s\n", debugstr_w(source), debugstr_w(dest));
2860 if ((h1 = CreateFileW(source, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE,
2861 NULL, OPEN_EXISTING, 0, 0)) == INVALID_HANDLE_VALUE)
2863 WARN("Unable to open source %s\n", debugstr_w(source));
2864 return FALSE;
2867 if (!GetFileInformationByHandle( h1, &info ))
2869 WARN("GetFileInformationByHandle returned error for %s\n", debugstr_w(source));
2870 CloseHandle( h1 );
2871 return FALSE;
2874 if ((h2 = CreateFileW( dest, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
2875 fail_if_exists ? CREATE_NEW : CREATE_ALWAYS,
2876 info.dwFileAttributes, h1 )) == INVALID_HANDLE_VALUE)
2878 WARN("Unable to open dest %s\n", debugstr_w(dest));
2879 CloseHandle( h1 );
2880 return FALSE;
2883 while (ReadFile( h1, buffer, sizeof(buffer), &count, NULL ) && count)
2885 char *p = buffer;
2886 while (count != 0)
2888 DWORD res;
2889 if (!WriteFile( h2, p, count, &res, NULL ) || !res) goto done;
2890 p += res;
2891 count -= res;
2894 ret = TRUE;
2895 done:
2896 CloseHandle( h1 );
2897 CloseHandle( h2 );
2898 return ret;
2902 /**************************************************************************
2903 * CopyFileA (KERNEL32.@)
2905 BOOL WINAPI CopyFileA( LPCSTR source, LPCSTR dest, BOOL fail_if_exists)
2907 UNICODE_STRING sourceW, destW;
2908 BOOL ret;
2910 if (!source || !dest)
2912 SetLastError(ERROR_INVALID_PARAMETER);
2913 return FALSE;
2916 RtlCreateUnicodeStringFromAsciiz(&sourceW, source);
2917 RtlCreateUnicodeStringFromAsciiz(&destW, dest);
2919 ret = CopyFileW(sourceW.Buffer, destW.Buffer, fail_if_exists);
2921 RtlFreeUnicodeString(&sourceW);
2922 RtlFreeUnicodeString(&destW);
2923 return ret;
2927 /**************************************************************************
2928 * CopyFileExW (KERNEL32.@)
2930 * This implementation ignores most of the extra parameters passed-in into
2931 * the "ex" version of the method and calls the CopyFile method.
2932 * It will have to be fixed eventually.
2934 BOOL WINAPI CopyFileExW(LPCWSTR sourceFilename, LPCWSTR destFilename,
2935 LPPROGRESS_ROUTINE progressRoutine, LPVOID appData,
2936 LPBOOL cancelFlagPointer, DWORD copyFlags)
2939 * Interpret the only flag that CopyFile can interpret.
2941 return CopyFileW(sourceFilename, destFilename, (copyFlags & COPY_FILE_FAIL_IF_EXISTS) != 0);
2944 /**************************************************************************
2945 * CopyFileExA (KERNEL32.@)
2947 BOOL WINAPI CopyFileExA(LPCSTR sourceFilename, LPCSTR destFilename,
2948 LPPROGRESS_ROUTINE progressRoutine, LPVOID appData,
2949 LPBOOL cancelFlagPointer, DWORD copyFlags)
2951 UNICODE_STRING sourceW, destW;
2952 BOOL ret;
2954 if (!sourceFilename || !destFilename)
2956 SetLastError(ERROR_INVALID_PARAMETER);
2957 return FALSE;
2960 RtlCreateUnicodeStringFromAsciiz(&sourceW, sourceFilename);
2961 RtlCreateUnicodeStringFromAsciiz(&destW, destFilename);
2963 ret = CopyFileExW(sourceW.Buffer, destW.Buffer, progressRoutine, appData,
2964 cancelFlagPointer, copyFlags);
2966 RtlFreeUnicodeString(&sourceW);
2967 RtlFreeUnicodeString(&destW);
2968 return ret;
2972 /***********************************************************************
2973 * SetFileTime (KERNEL32.@)
2975 BOOL WINAPI SetFileTime( HANDLE hFile,
2976 const FILETIME *lpCreationTime,
2977 const FILETIME *lpLastAccessTime,
2978 const FILETIME *lpLastWriteTime )
2980 BOOL ret;
2981 SERVER_START_REQ( set_file_time )
2983 req->handle = hFile;
2984 if (lpLastAccessTime)
2985 RtlTimeToSecondsSince1970( (PLARGE_INTEGER) lpLastAccessTime, (DWORD *)&req->access_time );
2986 else
2987 req->access_time = 0; /* FIXME */
2988 if (lpLastWriteTime)
2989 RtlTimeToSecondsSince1970( (PLARGE_INTEGER) lpLastWriteTime, (DWORD *)&req->write_time );
2990 else
2991 req->write_time = 0; /* FIXME */
2992 ret = !wine_server_call_err( req );
2994 SERVER_END_REQ;
2995 return ret;
2999 /**************************************************************************
3000 * LockFile (KERNEL32.@)
3002 BOOL WINAPI LockFile( HANDLE hFile, DWORD offset_low, DWORD offset_high,
3003 DWORD count_low, DWORD count_high )
3005 BOOL ret;
3007 TRACE( "%p %lx%08lx %lx%08lx\n", hFile, offset_high, offset_low, count_high, count_low );
3009 SERVER_START_REQ( lock_file )
3011 req->handle = hFile;
3012 req->offset_low = offset_low;
3013 req->offset_high = offset_high;
3014 req->count_low = count_low;
3015 req->count_high = count_high;
3016 req->shared = FALSE;
3017 req->wait = FALSE;
3018 ret = !wine_server_call_err( req );
3020 SERVER_END_REQ;
3021 return ret;
3024 /**************************************************************************
3025 * LockFileEx [KERNEL32.@]
3027 * Locks a byte range within an open file for shared or exclusive access.
3029 * RETURNS
3030 * success: TRUE
3031 * failure: FALSE
3033 * NOTES
3034 * Per Microsoft docs, the third parameter (reserved) must be set to 0.
3036 BOOL WINAPI LockFileEx( HANDLE hFile, DWORD flags, DWORD reserved,
3037 DWORD count_low, DWORD count_high, LPOVERLAPPED overlapped )
3039 NTSTATUS err;
3040 BOOL async;
3041 HANDLE handle;
3043 if (reserved)
3045 SetLastError( ERROR_INVALID_PARAMETER );
3046 return FALSE;
3049 TRACE( "%p %lx%08lx %lx%08lx flags %lx\n",
3050 hFile, overlapped->OffsetHigh, overlapped->Offset, count_high, count_low, flags );
3052 for (;;)
3054 SERVER_START_REQ( lock_file )
3056 req->handle = hFile;
3057 req->offset_low = overlapped->Offset;
3058 req->offset_high = overlapped->OffsetHigh;
3059 req->count_low = count_low;
3060 req->count_high = count_high;
3061 req->shared = !(flags & LOCKFILE_EXCLUSIVE_LOCK);
3062 req->wait = !(flags & LOCKFILE_FAIL_IMMEDIATELY);
3063 err = wine_server_call( req );
3064 handle = reply->handle;
3065 async = reply->overlapped;
3067 SERVER_END_REQ;
3068 if (err != STATUS_PENDING)
3070 if (err) SetLastError( RtlNtStatusToDosError(err) );
3071 return !err;
3073 if (async)
3075 FIXME( "Async I/O lock wait not implemented, might deadlock\n" );
3076 if (handle) CloseHandle( handle );
3077 SetLastError( ERROR_IO_PENDING );
3078 return FALSE;
3080 if (handle)
3082 WaitForSingleObject( handle, INFINITE );
3083 CloseHandle( handle );
3085 else Sleep(100); /* Unix lock conflict, sleep a bit and retry */
3090 /**************************************************************************
3091 * UnlockFile (KERNEL32.@)
3093 BOOL WINAPI UnlockFile( HANDLE hFile, DWORD offset_low, DWORD offset_high,
3094 DWORD count_low, DWORD count_high )
3096 BOOL ret;
3098 TRACE( "%p %lx%08lx %lx%08lx\n", hFile, offset_high, offset_low, count_high, count_low );
3100 SERVER_START_REQ( unlock_file )
3102 req->handle = hFile;
3103 req->offset_low = offset_low;
3104 req->offset_high = offset_high;
3105 req->count_low = count_low;
3106 req->count_high = count_high;
3107 ret = !wine_server_call_err( req );
3109 SERVER_END_REQ;
3110 return ret;
3114 /**************************************************************************
3115 * UnlockFileEx (KERNEL32.@)
3117 BOOL WINAPI UnlockFileEx( HANDLE hFile, DWORD reserved, DWORD count_low, DWORD count_high,
3118 LPOVERLAPPED overlapped )
3120 if (reserved)
3122 SetLastError( ERROR_INVALID_PARAMETER );
3123 return FALSE;
3125 return UnlockFile( hFile, overlapped->Offset, overlapped->OffsetHigh, count_low, count_high );
3129 /**************************************************************************
3130 * GetFileAttributesExW (KERNEL32.@)
3132 BOOL WINAPI GetFileAttributesExW(
3133 LPCWSTR lpFileName, GET_FILEEX_INFO_LEVELS fInfoLevelId,
3134 LPVOID lpFileInformation)
3136 DOS_FULL_NAME full_name;
3137 BY_HANDLE_FILE_INFORMATION info;
3139 if (!lpFileName || !lpFileInformation)
3141 SetLastError(ERROR_INVALID_PARAMETER);
3142 return FALSE;
3145 if (fInfoLevelId == GetFileExInfoStandard) {
3146 LPWIN32_FILE_ATTRIBUTE_DATA lpFad =
3147 (LPWIN32_FILE_ATTRIBUTE_DATA) lpFileInformation;
3148 if (!DOSFS_GetFullName( lpFileName, TRUE, &full_name )) return FALSE;
3149 if (!FILE_Stat( full_name.long_name, &info, NULL )) return FALSE;
3151 lpFad->dwFileAttributes = info.dwFileAttributes;
3152 lpFad->ftCreationTime = info.ftCreationTime;
3153 lpFad->ftLastAccessTime = info.ftLastAccessTime;
3154 lpFad->ftLastWriteTime = info.ftLastWriteTime;
3155 lpFad->nFileSizeHigh = info.nFileSizeHigh;
3156 lpFad->nFileSizeLow = info.nFileSizeLow;
3158 else {
3159 FIXME("invalid info level %d!\n", fInfoLevelId);
3160 return FALSE;
3163 return TRUE;
3167 /**************************************************************************
3168 * GetFileAttributesExA (KERNEL32.@)
3170 BOOL WINAPI GetFileAttributesExA(
3171 LPCSTR filename, GET_FILEEX_INFO_LEVELS fInfoLevelId,
3172 LPVOID lpFileInformation)
3174 UNICODE_STRING filenameW;
3175 BOOL ret = FALSE;
3177 if (!filename || !lpFileInformation)
3179 SetLastError(ERROR_INVALID_PARAMETER);
3180 return FALSE;
3183 if (RtlCreateUnicodeStringFromAsciiz(&filenameW, filename))
3185 ret = GetFileAttributesExW(filenameW.Buffer, fInfoLevelId, lpFileInformation);
3186 RtlFreeUnicodeString(&filenameW);
3188 else
3189 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
3190 return ret;
3193 /**************************************************************************
3194 * ReplaceFileW (KERNEL32.@)
3195 * ReplaceFile (KERNEL32.@)
3197 BOOL WINAPI ReplaceFileW(LPCWSTR lpReplacedFileName,LPCWSTR lpReplacementFileName,
3198 LPCWSTR lpBackupFileName, DWORD dwReplaceFlags,
3199 LPVOID lpExclude, LPVOID lpReserved)
3201 FIXME("(%s,%s,%s,%08lx,%p,%p) stub\n",debugstr_w(lpReplacedFileName),debugstr_w(lpReplacementFileName),
3202 debugstr_w(lpBackupFileName),dwReplaceFlags,lpExclude,lpReserved);
3203 SetLastError(ERROR_UNABLE_TO_MOVE_REPLACEMENT);
3204 return FALSE;
3207 /**************************************************************************
3208 * ReplaceFileA (KERNEL32.@)
3210 BOOL WINAPI ReplaceFileA(LPCSTR lpReplacedFileName,LPCSTR lpReplacementFileName,
3211 LPCSTR lpBackupFileName, DWORD dwReplaceFlags,
3212 LPVOID lpExclude, LPVOID lpReserved)
3214 FIXME("(%s,%s,%s,%08lx,%p,%p) stub\n",lpReplacedFileName,lpReplacementFileName,
3215 lpBackupFileName,dwReplaceFlags,lpExclude,lpReserved);
3216 SetLastError(ERROR_UNABLE_TO_MOVE_REPLACEMENT);
3217 return FALSE;