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
22 * Fix the CopyFileEx methods to implement the "extended" functionality.
23 * Right now, they simply call the CopyFile method.
27 #include "wine/port.h"
36 #ifdef HAVE_SYS_ERRNO_H
37 #include <sys/errno.h>
39 #include <sys/types.h>
41 #ifdef HAVE_SYS_MMAN_H
44 #ifdef HAVE_SYS_TIME_H
45 # include <sys/time.h>
47 #ifdef HAVE_SYS_POLL_H
48 # include <sys/poll.h>
58 #define NONAMELESSUNION
59 #define NONAMELESSSTRUCT
64 #include "wine/winbase16.h"
65 #include "wine/server.h"
73 #include "../kernel/kernel_private.h"
76 #include "wine/unicode.h"
77 #include "wine/debug.h"
79 WINE_DEFAULT_DEBUG_CHANNEL(file);
81 #if defined(MAP_ANONYMOUS) && !defined(MAP_ANON)
82 #define MAP_ANON MAP_ANONYMOUS
85 /* Macro to derive file offset from OVERLAPPED struct */
86 #define OVERLAPPED_OFFSET(overlapped) ((off_t) (overlapped)->Offset + ((off_t) (overlapped)->OffsetHigh << 32))
88 HANDLE dos_handles[DOS_TABLE_SIZE];
91 extern HANDLE WINAPI FILE_SmbOpen(LPCSTR name);
93 /***********************************************************************
94 * Asynchronous file I/O *
96 static DWORD fileio_get_async_status (const async_private *ovp);
97 static DWORD fileio_get_async_count (const async_private *ovp);
98 static void fileio_set_async_status (async_private *ovp, const DWORD status);
99 static void CALLBACK fileio_call_completion_func (ULONG_PTR data);
100 static void fileio_async_cleanup (async_private *ovp);
102 static async_ops fileio_async_ops =
104 fileio_get_async_status, /* get_status */
105 fileio_set_async_status, /* set_status */
106 fileio_get_async_count, /* get_count */
107 fileio_call_completion_func, /* call_completion */
108 fileio_async_cleanup /* cleanup */
111 static async_ops fileio_nocomp_async_ops =
113 fileio_get_async_status, /* get_status */
114 fileio_set_async_status, /* set_status */
115 fileio_get_async_count, /* get_count */
116 NULL, /* call_completion */
117 fileio_async_cleanup /* cleanup */
120 typedef struct async_fileio
122 struct async_private async;
123 LPOVERLAPPED lpOverlapped;
124 LPOVERLAPPED_COMPLETION_ROUTINE completion_func;
127 enum fd_type fd_type;
130 static DWORD fileio_get_async_status (const struct async_private *ovp)
132 return ((async_fileio*) ovp)->lpOverlapped->Internal;
135 static void fileio_set_async_status (async_private *ovp, const DWORD status)
137 ((async_fileio*) ovp)->lpOverlapped->Internal = status;
140 static DWORD fileio_get_async_count (const struct async_private *ovp)
142 async_fileio *fileio = (async_fileio*) ovp;
144 if (fileio->count < fileio->lpOverlapped->InternalHigh)
146 return fileio->count - fileio->lpOverlapped->InternalHigh;
149 static void CALLBACK fileio_call_completion_func (ULONG_PTR data)
151 async_fileio *ovp = (async_fileio*) data;
152 TRACE ("data: %p\n", ovp);
154 ovp->completion_func( RtlNtStatusToDosError ( ovp->lpOverlapped->Internal ),
155 ovp->lpOverlapped->InternalHigh,
158 fileio_async_cleanup ( &ovp->async );
161 static void fileio_async_cleanup ( struct async_private *ovp )
163 HeapFree ( GetProcessHeap(), 0, ovp );
166 /***********************************************************************
169 * Convert OF_* mode into flags for CreateFile.
171 void FILE_ConvertOFMode( INT mode, DWORD *access, DWORD *sharing )
175 case OF_READ: *access = GENERIC_READ; break;
176 case OF_WRITE: *access = GENERIC_WRITE; break;
177 case OF_READWRITE: *access = GENERIC_READ | GENERIC_WRITE; break;
178 default: *access = 0; break;
182 case OF_SHARE_EXCLUSIVE: *sharing = 0; break;
183 case OF_SHARE_DENY_WRITE: *sharing = FILE_SHARE_READ; break;
184 case OF_SHARE_DENY_READ: *sharing = FILE_SHARE_WRITE; break;
185 case OF_SHARE_DENY_NONE:
186 case OF_SHARE_COMPAT:
187 default: *sharing = FILE_SHARE_READ | FILE_SHARE_WRITE; break;
192 /***********************************************************************
195 * locale-independent case conversion for file I/O
197 int FILE_strcasecmp( const char *str1, const char *str2 )
200 for ( ; ; str1++, str2++)
201 if ((ret = FILE_toupper(*str1) - FILE_toupper(*str2)) || !*str1) break;
206 /***********************************************************************
209 * locale-independent case conversion for file I/O
211 int FILE_strncasecmp( const char *str1, const char *str2, int len )
214 for ( ; len > 0; len--, str1++, str2++)
215 if ((ret = FILE_toupper(*str1) - FILE_toupper(*str2)) || !*str1) break;
220 /***********************************************************************
221 * FILE_GetNtStatus(void)
223 * Retrieve the Nt Status code from errno.
224 * Try to be consistent with FILE_SetDosError().
226 DWORD FILE_GetNtStatus(void)
230 TRACE ( "errno = %d\n", errno );
233 case EAGAIN: nt = STATUS_SHARING_VIOLATION; break;
234 case EBADF: nt = STATUS_INVALID_HANDLE; break;
235 case ENOSPC: nt = STATUS_DISK_FULL; break;
238 case EACCES: nt = STATUS_ACCESS_DENIED; break;
239 case ENOENT: nt = STATUS_SHARING_VIOLATION; break;
240 case EISDIR: nt = STATUS_FILE_IS_A_DIRECTORY; break;
242 case ENFILE: nt = STATUS_NO_MORE_FILES; break;
244 case ENOTEMPTY: nt = STATUS_DIRECTORY_NOT_EMPTY; break;
245 case EPIPE: nt = STATUS_PIPE_BROKEN; break;
246 case ENOEXEC: /* ?? */
247 case ESPIPE: /* ?? */
248 case EEXIST: /* ?? */
250 FIXME ( "Converting errno %d to STATUS_UNSUCCESSFUL\n", err );
251 nt = STATUS_UNSUCCESSFUL;
256 /***********************************************************************
259 * Set the DOS error code from errno.
261 void FILE_SetDosError(void)
263 int save_errno = errno; /* errno gets overwritten by printf */
265 TRACE("errno = %d %s\n", errno, strerror(errno));
269 SetLastError( ERROR_SHARING_VIOLATION );
272 SetLastError( ERROR_INVALID_HANDLE );
275 SetLastError( ERROR_HANDLE_DISK_FULL );
280 SetLastError( ERROR_ACCESS_DENIED );
283 SetLastError( ERROR_LOCK_VIOLATION );
286 SetLastError( ERROR_FILE_NOT_FOUND );
289 SetLastError( ERROR_CANNOT_MAKE );
293 SetLastError( ERROR_NO_MORE_FILES );
296 SetLastError( ERROR_FILE_EXISTS );
300 SetLastError( ERROR_SEEK );
303 SetLastError( ERROR_DIR_NOT_EMPTY );
306 SetLastError( ERROR_BAD_FORMAT );
309 WARN("unknown file error: %s\n", strerror(save_errno) );
310 SetLastError( ERROR_GEN_FAILURE );
317 /***********************************************************************
318 * FILE_GetUnixHandleType
320 * Retrieve the Unix handle corresponding to a file handle.
321 * Returns -1 on failure.
323 static int FILE_GetUnixHandleType( HANDLE handle, DWORD access, enum fd_type *type, int *flags_ptr )
325 int ret, flags, fd = -1;
327 ret = wine_server_handle_to_fd( handle, access, &fd, type, &flags );
328 if (flags_ptr) *flags_ptr = flags;
329 if (ret) SetLastError( RtlNtStatusToDosError(ret) );
330 else if (((access & GENERIC_READ) && (flags & FD_FLAG_RECV_SHUTDOWN)) ||
331 ((access & GENERIC_WRITE) && (flags & FD_FLAG_SEND_SHUTDOWN)))
334 SetLastError ( ERROR_PIPE_NOT_CONNECTED );
340 /***********************************************************************
343 * Retrieve the Unix handle corresponding to a file handle.
344 * Returns -1 on failure.
346 int FILE_GetUnixHandle( HANDLE handle, DWORD access )
348 return FILE_GetUnixHandleType( handle, access, NULL, NULL );
351 /******************************************************************
352 * OpenConsoleW (KERNEL32.@)
355 * Open a handle to the current process console.
356 * Returns INVALID_HANDLE_VALUE on failure.
358 HANDLE WINAPI OpenConsoleW(LPCWSTR name, DWORD access, LPSECURITY_ATTRIBUTES sa,
361 static const WCHAR coninW[] = {'C','O','N','I','N','$',0};
362 static const WCHAR conoutW[] = {'C','O','N','O','U','T','$',0};
366 if (strcmpW(coninW, name) == 0)
368 else if (strcmpW(conoutW, name) == 0)
372 SetLastError(ERROR_INVALID_NAME);
373 return INVALID_HANDLE_VALUE;
375 if (creation != OPEN_EXISTING)
377 SetLastError(ERROR_INVALID_PARAMETER);
378 return INVALID_HANDLE_VALUE;
381 SERVER_START_REQ( open_console )
384 req->access = access;
385 req->share = FILE_SHARE_READ | FILE_SHARE_WRITE;
386 req->inherit = (sa && (sa->nLength>=sizeof(*sa)) && sa->bInheritHandle);
388 wine_server_call_err( req );
392 return ret ? console_handle_map(ret) : INVALID_HANDLE_VALUE;
395 /******************************************************************
396 * VerifyConsoleIoHandle (KERNEL32.@)
400 BOOL WINAPI VerifyConsoleIoHandle(HANDLE handle)
404 if (!is_console_handle(handle)) return FALSE;
405 SERVER_START_REQ(get_console_mode)
407 req->handle = console_handle_unmap(handle);
408 ret = !wine_server_call_err( req );
414 /******************************************************************
415 * DuplicateConsoleHandle (KERNEL32.@)
419 HANDLE WINAPI DuplicateConsoleHandle(HANDLE handle, DWORD access, BOOL inherit,
424 if (!is_console_handle(handle) ||
425 !DuplicateHandle(GetCurrentProcess(), console_handle_unmap(handle),
426 GetCurrentProcess(), &ret, access, inherit, options))
427 return INVALID_HANDLE_VALUE;
428 return console_handle_map(ret);
431 /******************************************************************
432 * CloseConsoleHandle (KERNEL32.@)
436 BOOL WINAPI CloseConsoleHandle(HANDLE handle)
438 if (!is_console_handle(handle))
440 SetLastError(ERROR_INVALID_PARAMETER);
443 return CloseHandle(console_handle_unmap(handle));
446 /******************************************************************
447 * GetConsoleInputWaitHandle (KERNEL32.@)
451 HANDLE WINAPI GetConsoleInputWaitHandle(void)
453 static HANDLE console_wait_event;
455 /* FIXME: this is not thread safe */
456 if (!console_wait_event)
458 SERVER_START_REQ(get_console_wait_event)
460 if (!wine_server_call_err( req )) console_wait_event = reply->handle;
464 return console_wait_event;
469 /* FIXME: those routines defined as pointers are needed, because this file is
470 * currently compiled into NTDLL whereas it belongs to kernel32.
471 * this shall go away once all the DLL separation process is done
473 typedef BOOL (WINAPI* pRW)(HANDLE, const void*, DWORD, DWORD*, void*);
475 static BOOL FILE_ReadConsole(HANDLE hCon, void* buf, DWORD nb, DWORD* nr, void* p)
477 static HANDLE hKernel /* = 0 */;
478 static pRW pReadConsole /* = 0 */;
480 if ((!hKernel && !(hKernel = LoadLibraryA("kernel32"))) ||
482 !(pReadConsole = GetProcAddress(hKernel, "ReadConsoleA"))))
487 return (pReadConsole)(hCon, buf, nb, nr, p);
490 static BOOL FILE_WriteConsole(HANDLE hCon, const void* buf, DWORD nb, DWORD* nr, void* p)
492 static HANDLE hKernel /* = 0 */;
493 static pRW pWriteConsole /* = 0 */;
495 if ((!hKernel && !(hKernel = LoadLibraryA("kernel32"))) ||
497 !(pWriteConsole = GetProcAddress(hKernel, "WriteConsoleA"))))
502 return (pWriteConsole)(hCon, buf, nb, nr, p);
506 /***********************************************************************
509 * Implementation of CreateFile. Takes a Unix path name.
510 * Returns 0 on failure.
512 HANDLE FILE_CreateFile( LPCSTR filename, DWORD access, DWORD sharing,
513 LPSECURITY_ATTRIBUTES sa, DWORD creation,
514 DWORD attributes, HANDLE template, BOOL fail_read_only,
522 SERVER_START_REQ( create_file )
524 req->access = access;
525 req->inherit = (sa && (sa->nLength>=sizeof(*sa)) && sa->bInheritHandle);
526 req->sharing = sharing;
527 req->create = creation;
528 req->attrs = attributes;
529 req->drive_type = drive_type;
530 wine_server_add_data( req, filename, strlen(filename) );
532 err = wine_server_call( req );
537 /* If write access failed, retry without GENERIC_WRITE */
539 if (!ret && !fail_read_only && (access & GENERIC_WRITE))
541 if ((err == STATUS_MEDIA_WRITE_PROTECTED) || (err == STATUS_ACCESS_DENIED))
543 TRACE("Write access failed for file '%s', trying without "
544 "write access\n", filename);
545 access &= ~GENERIC_WRITE;
552 /* In the case file creation was rejected due to CREATE_NEW flag
553 * was specified and file with that name already exists, correct
554 * last error is ERROR_FILE_EXISTS and not ERROR_ALREADY_EXISTS.
555 * Note: RtlNtStatusToDosError is not the subject to blame here.
557 if (err == STATUS_OBJECT_NAME_COLLISION)
558 SetLastError( ERROR_FILE_EXISTS );
560 SetLastError( RtlNtStatusToDosError(err) );
563 if (!ret) WARN("Unable to create file '%s' (GLE %ld)\n", filename, GetLastError());
569 /***********************************************************************
572 * Same as FILE_CreateFile but for a device
573 * Returns 0 on failure.
575 HANDLE FILE_CreateDevice( int client_id, DWORD access, LPSECURITY_ATTRIBUTES sa )
578 SERVER_START_REQ( create_device )
580 req->access = access;
581 req->inherit = (sa && (sa->nLength>=sizeof(*sa)) && sa->bInheritHandle);
584 wine_server_call_err( req );
591 static HANDLE FILE_OpenPipe(LPCWSTR name, DWORD access, LPSECURITY_ATTRIBUTES sa )
596 if (name && (len = strlenW(name)) > MAX_PATH)
598 SetLastError( ERROR_FILENAME_EXCED_RANGE );
601 SERVER_START_REQ( open_named_pipe )
603 req->access = access;
604 req->inherit = (sa && (sa->nLength>=sizeof(*sa)) && sa->bInheritHandle);
606 wine_server_add_data( req, name, len * sizeof(WCHAR) );
607 wine_server_call_err( req );
611 TRACE("Returned %p\n",ret);
615 /*************************************************************************
616 * CreateFileW [KERNEL32.@] Creates or opens a file or other object
618 * Creates or opens an object, and returns a handle that can be used to
619 * access that object.
623 * filename [in] pointer to filename to be accessed
624 * access [in] access mode requested
625 * sharing [in] share mode
626 * sa [in] pointer to security attributes
627 * creation [in] how to create the file
628 * attributes [in] attributes for newly created file
629 * template [in] handle to file with extended attributes to copy
632 * Success: Open handle to specified file
633 * Failure: INVALID_HANDLE_VALUE
636 * Should call SetLastError() on failure.
640 * Doesn't support character devices, template files, or a
641 * lot of the 'attributes' flags yet.
643 HANDLE WINAPI CreateFileW( LPCWSTR filename, DWORD access, DWORD sharing,
644 LPSECURITY_ATTRIBUTES sa, DWORD creation,
645 DWORD attributes, HANDLE template )
647 DOS_FULL_NAME full_name;
649 static const WCHAR bkslashes_with_question_markW[] = {'\\','\\','?','\\',0};
650 static const WCHAR bkslashes_with_dotW[] = {'\\','\\','.','\\',0};
651 static const WCHAR bkslashesW[] = {'\\','\\',0};
652 static const WCHAR coninW[] = {'C','O','N','I','N','$',0};
653 static const WCHAR conoutW[] = {'C','O','N','O','U','T','$',0};
657 SetLastError( ERROR_INVALID_PARAMETER );
658 return INVALID_HANDLE_VALUE;
660 TRACE("%s %s%s%s%s%s%s%s attributes 0x%lx\n", debugstr_w(filename),
661 ((access & GENERIC_READ)==GENERIC_READ)?"GENERIC_READ ":"",
662 ((access & GENERIC_WRITE)==GENERIC_WRITE)?"GENERIC_WRITE ":"",
663 (!access)?"QUERY_ACCESS ":"",
664 ((sharing & FILE_SHARE_READ)==FILE_SHARE_READ)?"FILE_SHARE_READ ":"",
665 ((sharing & FILE_SHARE_WRITE)==FILE_SHARE_WRITE)?"FILE_SHARE_WRITE ":"",
666 ((sharing & FILE_SHARE_DELETE)==FILE_SHARE_DELETE)?"FILE_SHARE_DELETE ":"",
667 (creation ==CREATE_NEW)?"CREATE_NEW":
668 (creation ==CREATE_ALWAYS)?"CREATE_ALWAYS ":
669 (creation ==OPEN_EXISTING)?"OPEN_EXISTING ":
670 (creation ==OPEN_ALWAYS)?"OPEN_ALWAYS ":
671 (creation ==TRUNCATE_EXISTING)?"TRUNCATE_EXISTING ":"", attributes);
673 /* If the name starts with '\\?\', ignore the first 4 chars. */
674 if (!strncmpW(filename, bkslashes_with_question_markW, 4))
676 static const WCHAR uncW[] = {'U','N','C','\\',0};
678 if (!strncmpiW(filename, uncW, 4))
680 FIXME("UNC name (%s) not supported.\n", debugstr_w(filename) );
681 SetLastError( ERROR_PATH_NOT_FOUND );
682 return INVALID_HANDLE_VALUE;
686 if (!strncmpW(filename, bkslashes_with_dotW, 4))
688 static const WCHAR pipeW[] = {'P','I','P','E','\\',0};
689 if(!strncmpiW(filename + 4, pipeW, 5))
691 TRACE("Opening a pipe: %s\n", debugstr_w(filename));
692 ret = FILE_OpenPipe( filename, access, sa );
695 else if (isalphaW(filename[4]) && filename[5] == ':' && filename[6] == '\0')
697 ret = FILE_CreateDevice( (toupperW(filename[4]) - 'A') | 0x20000, access, sa );
700 else if (!DOSFS_GetDevice( filename ))
702 ret = DEVICE_Open( filename+4, access, sa );
706 filename+=4; /* fall into DOSFS_Device case below */
709 /* If the name still starts with '\\', it's a UNC name. */
710 if (!strncmpW(filename, bkslashesW, 2))
712 ret = SMB_CreateFileW(filename, access, sharing, sa, creation, attributes, template );
716 /* If the name contains a DOS wild card (* or ?), do no create a file */
717 if(strchrW(filename, '*') || strchrW(filename, '?'))
719 SetLastError(ERROR_BAD_PATHNAME);
720 return INVALID_HANDLE_VALUE;
723 /* Open a console for CONIN$ or CONOUT$ */
724 if (!strcmpiW(filename, coninW) || !strcmpiW(filename, conoutW))
726 ret = OpenConsoleW(filename, access, sa, creation);
730 if (DOSFS_GetDevice( filename ))
732 TRACE("opening device %s\n", debugstr_w(filename) );
734 if (!(ret = DOSFS_OpenDevice( filename, access, attributes, sa )))
736 /* Do not silence this please. It is a critical error. -MM */
737 ERR("Couldn't open device %s!\n", debugstr_w(filename));
738 SetLastError( ERROR_FILE_NOT_FOUND );
743 /* check for filename, don't check for last entry if creating */
744 if (!DOSFS_GetFullName( filename,
745 (creation == OPEN_EXISTING) ||
746 (creation == TRUNCATE_EXISTING),
748 WARN("Unable to get full filename from %s (GLE %ld)\n",
749 debugstr_w(filename), GetLastError());
750 return INVALID_HANDLE_VALUE;
753 ret = FILE_CreateFile( full_name.long_name, access, sharing,
754 sa, creation, attributes, template,
755 DRIVE_GetFlags(full_name.drive) & DRIVE_FAIL_READ_ONLY,
756 GetDriveTypeW( full_name.short_name ) );
758 if (!ret) ret = INVALID_HANDLE_VALUE;
759 TRACE("returning %p\n", ret);
765 /*************************************************************************
766 * CreateFileA (KERNEL32.@)
768 HANDLE WINAPI CreateFileA( LPCSTR filename, DWORD access, DWORD sharing,
769 LPSECURITY_ATTRIBUTES sa, DWORD creation,
770 DWORD attributes, HANDLE template)
772 UNICODE_STRING filenameW;
773 HANDLE ret = INVALID_HANDLE_VALUE;
777 SetLastError( ERROR_INVALID_PARAMETER );
778 return INVALID_HANDLE_VALUE;
781 if (RtlCreateUnicodeStringFromAsciiz(&filenameW, filename))
783 ret = CreateFileW(filenameW.Buffer, access, sharing, sa, creation,
784 attributes, template);
785 RtlFreeUnicodeString(&filenameW);
788 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
793 /***********************************************************************
796 * Fill a file information from a struct stat.
798 static void FILE_FillInfo( struct stat *st, BY_HANDLE_FILE_INFORMATION *info )
800 if (S_ISDIR(st->st_mode))
801 info->dwFileAttributes = FILE_ATTRIBUTE_DIRECTORY;
803 info->dwFileAttributes = FILE_ATTRIBUTE_ARCHIVE;
804 if (!(st->st_mode & S_IWUSR))
805 info->dwFileAttributes |= FILE_ATTRIBUTE_READONLY;
807 RtlSecondsSince1970ToTime( st->st_mtime, (LARGE_INTEGER *)&info->ftCreationTime );
808 RtlSecondsSince1970ToTime( st->st_mtime, (LARGE_INTEGER *)&info->ftLastWriteTime );
809 RtlSecondsSince1970ToTime( st->st_atime, (LARGE_INTEGER *)&info->ftLastAccessTime );
811 info->dwVolumeSerialNumber = 0; /* FIXME */
812 info->nFileSizeHigh = 0;
813 info->nFileSizeLow = 0;
814 if (!S_ISDIR(st->st_mode)) {
815 info->nFileSizeHigh = st->st_size >> 32;
816 info->nFileSizeLow = st->st_size & 0xffffffff;
818 info->nNumberOfLinks = st->st_nlink;
819 info->nFileIndexHigh = 0;
820 info->nFileIndexLow = st->st_ino;
824 /***********************************************************************
827 * Stat a Unix path name. Return TRUE if OK.
829 BOOL FILE_Stat( LPCSTR unixName, BY_HANDLE_FILE_INFORMATION *info, BOOL *is_symlink_ptr )
835 if (lstat( unixName, &st ) == -1)
840 is_symlink = S_ISLNK(st.st_mode);
843 /* do a "real" stat to find out
844 about the type of the symlink destination */
845 if (stat( unixName, &st ) == -1)
852 /* fill in the information we gathered so far */
853 FILE_FillInfo( &st, info );
855 /* and now see if this is a hidden file, based on the name */
856 p = strrchr( unixName, '/');
857 p = p ? p + 1 : unixName;
858 if (*p == '.' && *(p+1) && (*(p+1) != '.' || *(p+2)))
860 static const WCHAR wineW[] = {'w','i','n','e',0};
861 static const WCHAR ShowDotFilesW[] = {'S','h','o','w','D','o','t','F','i','l','e','s',0};
862 static int show_dot_files = -1;
863 if (show_dot_files == -1)
864 show_dot_files = PROFILE_GetWineIniBool(wineW, ShowDotFilesW, 0);
866 info->dwFileAttributes |= FILE_ATTRIBUTE_HIDDEN;
868 if (is_symlink_ptr) *is_symlink_ptr = is_symlink;
873 /***********************************************************************
874 * GetFileInformationByHandle (KERNEL32.@)
876 DWORD WINAPI GetFileInformationByHandle( HANDLE hFile,
877 BY_HANDLE_FILE_INFORMATION *info )
882 TRACE("%p\n", hFile);
884 SERVER_START_REQ( get_file_info )
887 if ((ret = !wine_server_call_err( req )))
889 /* FIXME: which file types are supported ?
890 * Serial ports (FILE_TYPE_CHAR) are not,
891 * and MSDN also says that pipes are not supported.
892 * FILE_TYPE_REMOTE seems to be supported according to
893 * MSDN q234741.txt */
894 if ((reply->type == FILE_TYPE_DISK) || (reply->type == FILE_TYPE_REMOTE))
896 RtlSecondsSince1970ToTime( reply->write_time, (LARGE_INTEGER *)&info->ftCreationTime );
897 RtlSecondsSince1970ToTime( reply->write_time, (LARGE_INTEGER *)&info->ftLastWriteTime );
898 RtlSecondsSince1970ToTime( reply->access_time, (LARGE_INTEGER *)&info->ftLastAccessTime );
899 info->dwFileAttributes = reply->attr;
900 info->dwVolumeSerialNumber = reply->serial;
901 info->nFileSizeHigh = reply->size_high;
902 info->nFileSizeLow = reply->size_low;
903 info->nNumberOfLinks = reply->links;
904 info->nFileIndexHigh = reply->index_high;
905 info->nFileIndexLow = reply->index_low;
909 SetLastError(ERROR_NOT_SUPPORTED);
919 /**************************************************************************
920 * GetFileAttributesW (KERNEL32.@)
922 DWORD WINAPI GetFileAttributesW( LPCWSTR name )
924 DOS_FULL_NAME full_name;
925 BY_HANDLE_FILE_INFORMATION info;
929 SetLastError( ERROR_INVALID_PARAMETER );
932 if (!DOSFS_GetFullName( name, TRUE, &full_name) )
934 if (!FILE_Stat( full_name.long_name, &info, NULL )) return -1;
935 return info.dwFileAttributes;
939 /**************************************************************************
940 * GetFileAttributesA (KERNEL32.@)
942 DWORD WINAPI GetFileAttributesA( LPCSTR name )
944 UNICODE_STRING nameW;
945 DWORD ret = (DWORD)-1;
949 SetLastError( ERROR_INVALID_PARAMETER );
953 if (RtlCreateUnicodeStringFromAsciiz(&nameW, name))
955 ret = GetFileAttributesW(nameW.Buffer);
956 RtlFreeUnicodeString(&nameW);
959 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
964 /**************************************************************************
965 * SetFileAttributesW (KERNEL32.@)
967 BOOL WINAPI SetFileAttributesW(LPCWSTR lpFileName, DWORD attributes)
970 DOS_FULL_NAME full_name;
974 SetLastError( ERROR_INVALID_PARAMETER );
978 TRACE("(%s,%lx)\n", debugstr_w(lpFileName), attributes);
980 if (!DOSFS_GetFullName( lpFileName, TRUE, &full_name ))
983 if(stat(full_name.long_name,&buf)==-1)
988 if (attributes & FILE_ATTRIBUTE_READONLY)
990 if(S_ISDIR(buf.st_mode))
992 WARN("FILE_ATTRIBUTE_READONLY ignored for directory.\n");
994 buf.st_mode &= ~0222; /* octal!, clear write permission bits */
995 attributes &= ~FILE_ATTRIBUTE_READONLY;
999 /* add write permission */
1000 buf.st_mode |= (0600 | ((buf.st_mode & 044) >> 1)) & (~FILE_umask);
1002 if (attributes & FILE_ATTRIBUTE_DIRECTORY)
1004 if (!S_ISDIR(buf.st_mode))
1005 FIXME("SetFileAttributes expected the file %s to be a directory\n",
1006 debugstr_w(lpFileName));
1007 attributes &= ~FILE_ATTRIBUTE_DIRECTORY;
1009 attributes &= ~(FILE_ATTRIBUTE_NORMAL|FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_HIDDEN|FILE_ATTRIBUTE_SYSTEM);
1011 FIXME("(%s):%lx attribute(s) not implemented.\n", debugstr_w(lpFileName), attributes);
1012 if (-1==chmod(full_name.long_name,buf.st_mode))
1014 if (GetDriveTypeW(lpFileName) == DRIVE_CDROM)
1016 SetLastError( ERROR_ACCESS_DENIED );
1021 * FIXME: We don't return FALSE here because of differences between
1022 * Linux and Windows privileges. Under Linux only the owner of
1023 * the file is allowed to change file attributes. Under Windows,
1024 * applications expect that if you can write to a file, you can also
1025 * change its attributes (see GENERIC_WRITE). We could try to be
1026 * clever here but that would break multi-user installations where
1027 * users share read-only DLLs. This is because some installers like
1028 * to change attributes of already installed DLLs.
1030 FIXME("Couldn't set file attributes for existing file \"%s\".\n"
1031 "Check permissions or set VFAT \"quiet\" mount flag\n", full_name.long_name);
1037 /**************************************************************************
1038 * SetFileAttributesA (KERNEL32.@)
1040 BOOL WINAPI SetFileAttributesA(LPCSTR lpFileName, DWORD attributes)
1042 UNICODE_STRING filenameW;
1047 SetLastError( ERROR_INVALID_PARAMETER );
1051 if (RtlCreateUnicodeStringFromAsciiz(&filenameW, lpFileName))
1053 ret = SetFileAttributesW(filenameW.Buffer, attributes);
1054 RtlFreeUnicodeString(&filenameW);
1057 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1062 /***********************************************************************
1063 * GetFileTime (KERNEL32.@)
1065 BOOL WINAPI GetFileTime( HANDLE hFile, FILETIME *lpCreationTime,
1066 FILETIME *lpLastAccessTime,
1067 FILETIME *lpLastWriteTime )
1069 BY_HANDLE_FILE_INFORMATION info;
1070 if (!GetFileInformationByHandle( hFile, &info )) return FALSE;
1071 if (lpCreationTime) *lpCreationTime = info.ftCreationTime;
1072 if (lpLastAccessTime) *lpLastAccessTime = info.ftLastAccessTime;
1073 if (lpLastWriteTime) *lpLastWriteTime = info.ftLastWriteTime;
1078 /***********************************************************************
1079 * FILE_GetTempFileName : utility for GetTempFileName
1081 static UINT FILE_GetTempFileName( LPCWSTR path, LPCWSTR prefix, UINT unique,
1084 static UINT unique_temp;
1085 DOS_FULL_NAME full_name;
1091 if ( !path || !prefix || !buffer )
1093 SetLastError( ERROR_INVALID_PARAMETER );
1097 if (!unique_temp) unique_temp = time(NULL) & 0xffff;
1098 num = unique ? (unique & 0xffff) : (unique_temp++ & 0xffff);
1100 strcpyW( buffer, path );
1101 p = buffer + strlenW(buffer);
1103 /* add a \, if there isn't one and path is more than just the drive letter ... */
1104 if ( !((strlenW(buffer) == 2) && (buffer[1] == ':'))
1105 && ((p == buffer) || (p[-1] != '\\'))) *p++ = '\\';
1107 for (i = 3; (i > 0) && (*prefix); i--) *p++ = *prefix++;
1109 sprintf( buf, "%04x.tmp", num );
1110 MultiByteToWideChar(CP_ACP, 0, buf, -1, p, 20);
1112 /* Now try to create it */
1118 HANDLE handle = CreateFileW( buffer, GENERIC_WRITE, 0, NULL,
1119 CREATE_NEW, FILE_ATTRIBUTE_NORMAL, 0 );
1120 if (handle != INVALID_HANDLE_VALUE)
1121 { /* We created it */
1122 TRACE("created %s\n", debugstr_w(buffer) );
1123 CloseHandle( handle );
1126 if (GetLastError() != ERROR_FILE_EXISTS &&
1127 GetLastError() != ERROR_SHARING_VIOLATION)
1128 break; /* No need to go on */
1130 sprintf( buf, "%04x.tmp", num );
1131 MultiByteToWideChar(CP_ACP, 0, buf, -1, p, 20);
1132 } while (num != (unique & 0xffff));
1135 /* Get the full path name */
1137 if (DOSFS_GetFullName( buffer, FALSE, &full_name ))
1140 /* Check if we have write access in the directory */
1141 if ((slash = strrchr( full_name.long_name, '/' ))) *slash = '\0';
1142 if (access( full_name.long_name, W_OK ) == -1)
1143 WARN("returns %s, which doesn't seem to be writeable.\n",
1144 debugstr_w(buffer) );
1146 TRACE("returning %s\n", debugstr_w(buffer) );
1147 return unique ? unique : num;
1151 /***********************************************************************
1152 * GetTempFileNameA (KERNEL32.@)
1154 UINT WINAPI GetTempFileNameA( LPCSTR path, LPCSTR prefix, UINT unique,
1157 UNICODE_STRING pathW, prefixW;
1158 WCHAR bufferW[MAX_PATH];
1161 if ( !path || !prefix || !buffer )
1163 SetLastError( ERROR_INVALID_PARAMETER );
1167 RtlCreateUnicodeStringFromAsciiz(&pathW, path);
1168 RtlCreateUnicodeStringFromAsciiz(&prefixW, prefix);
1170 ret = GetTempFileNameW(pathW.Buffer, prefixW.Buffer, unique, bufferW);
1172 WideCharToMultiByte(CP_ACP, 0, bufferW, -1, buffer, MAX_PATH, NULL, NULL);
1174 RtlFreeUnicodeString(&pathW);
1175 RtlFreeUnicodeString(&prefixW);
1179 /***********************************************************************
1180 * GetTempFileNameW (KERNEL32.@)
1182 UINT WINAPI GetTempFileNameW( LPCWSTR path, LPCWSTR prefix, UINT unique,
1185 return FILE_GetTempFileName( path, prefix, unique, buffer );
1189 /***********************************************************************
1192 * Implementation of OpenFile16() and OpenFile32().
1194 static HFILE FILE_DoOpenFile( LPCSTR name, OFSTRUCT *ofs, UINT mode, BOOL win32 )
1199 WORD filedatetime[2];
1200 DOS_FULL_NAME full_name;
1201 DWORD access, sharing;
1203 WCHAR buffer[MAX_PATH];
1206 if (!ofs) return HFILE_ERROR;
1208 TRACE("%s %s %s %s%s%s%s%s%s%s%s%s\n",name,
1209 ((mode & 0x3 )==OF_READ)?"OF_READ":
1210 ((mode & 0x3 )==OF_WRITE)?"OF_WRITE":
1211 ((mode & 0x3 )==OF_READWRITE)?"OF_READWRITE":"unknown",
1212 ((mode & 0x70 )==OF_SHARE_COMPAT)?"OF_SHARE_COMPAT":
1213 ((mode & 0x70 )==OF_SHARE_DENY_NONE)?"OF_SHARE_DENY_NONE":
1214 ((mode & 0x70 )==OF_SHARE_DENY_READ)?"OF_SHARE_DENY_READ":
1215 ((mode & 0x70 )==OF_SHARE_DENY_WRITE)?"OF_SHARE_DENY_WRITE":
1216 ((mode & 0x70 )==OF_SHARE_EXCLUSIVE)?"OF_SHARE_EXCLUSIVE":"unknown",
1217 ((mode & OF_PARSE )==OF_PARSE)?"OF_PARSE ":"",
1218 ((mode & OF_DELETE )==OF_DELETE)?"OF_DELETE ":"",
1219 ((mode & OF_VERIFY )==OF_VERIFY)?"OF_VERIFY ":"",
1220 ((mode & OF_SEARCH )==OF_SEARCH)?"OF_SEARCH ":"",
1221 ((mode & OF_CANCEL )==OF_CANCEL)?"OF_CANCEL ":"",
1222 ((mode & OF_CREATE )==OF_CREATE)?"OF_CREATE ":"",
1223 ((mode & OF_PROMPT )==OF_PROMPT)?"OF_PROMPT ":"",
1224 ((mode & OF_EXIST )==OF_EXIST)?"OF_EXIST ":"",
1225 ((mode & OF_REOPEN )==OF_REOPEN)?"OF_REOPEN ":""
1229 ofs->cBytes = sizeof(OFSTRUCT);
1231 if (mode & OF_REOPEN) name = ofs->szPathName;
1234 ERR("called with `name' set to NULL ! Please debug.\n");
1238 TRACE("%s %04x\n", name, mode );
1240 /* the watcom 10.6 IDE relies on a valid path returned in ofs->szPathName
1241 Are there any cases where getting the path here is wrong?
1242 Uwe Bonnes 1997 Apr 2 */
1243 if (!GetFullPathNameA( name, sizeof(ofs->szPathName),
1244 ofs->szPathName, NULL )) goto error;
1245 FILE_ConvertOFMode( mode, &access, &sharing );
1247 /* OF_PARSE simply fills the structure */
1249 if (mode & OF_PARSE)
1251 ofs->fFixedDisk = (GetDriveType16( ofs->szPathName[0]-'A' )
1252 != DRIVE_REMOVABLE);
1253 TRACE("(%s): OF_PARSE, res = '%s'\n",
1254 name, ofs->szPathName );
1258 /* OF_CREATE is completely different from all other options, so
1261 if (mode & OF_CREATE)
1263 if ((handle = CreateFileA( name, GENERIC_READ | GENERIC_WRITE,
1264 sharing, NULL, CREATE_ALWAYS,
1265 FILE_ATTRIBUTE_NORMAL, 0 ))== INVALID_HANDLE_VALUE)
1270 MultiByteToWideChar(CP_ACP, 0, name, -1, buffer, MAX_PATH);
1273 /* If OF_SEARCH is set, ignore the given path */
1275 if ((mode & OF_SEARCH) && !(mode & OF_REOPEN))
1277 /* First try the file name as is */
1278 if (DOSFS_GetFullName( nameW, TRUE, &full_name )) goto found;
1279 /* Now remove the path */
1280 if (nameW[0] && (nameW[1] == ':')) nameW += 2;
1281 if ((p = strrchrW( nameW, '\\' ))) nameW = p + 1;
1282 if ((p = strrchrW( nameW, '/' ))) nameW = p + 1;
1283 if (!nameW[0]) goto not_found;
1286 /* Now look for the file */
1288 if (!DIR_SearchPath( NULL, nameW, NULL, &full_name, win32 )) goto not_found;
1291 TRACE("found %s = %s\n",
1292 full_name.long_name, debugstr_w(full_name.short_name) );
1293 WideCharToMultiByte(CP_ACP, 0, full_name.short_name, -1,
1294 ofs->szPathName, sizeof(ofs->szPathName), NULL, NULL);
1296 if (mode & OF_SHARE_EXCLUSIVE)
1297 /* Some InstallShield version uses OF_SHARE_EXCLUSIVE
1298 on the file <tempdir>/_ins0432._mp to determine how
1299 far installation has proceeded.
1300 _ins0432._mp is an executable and while running the
1301 application expects the open with OF_SHARE_ to fail*/
1303 As our loader closes the files after loading the executable,
1304 we can't find the running executable with FILE_InUse.
1305 The loader should keep the file open, as Windows does that, too.
1308 char *last = strrchr(full_name.long_name,'/');
1310 last = full_name.long_name - 1;
1311 if (GetModuleHandle16(last+1))
1313 TRACE("Denying shared open for %s\n",full_name.long_name);
1318 if (mode & OF_DELETE)
1320 if (unlink( full_name.long_name ) == -1) goto not_found;
1321 TRACE("(%s): OF_DELETE return = OK\n", name);
1325 handle = FILE_CreateFile( full_name.long_name, access, sharing,
1326 NULL, OPEN_EXISTING, 0, 0,
1327 DRIVE_GetFlags(full_name.drive) & DRIVE_FAIL_READ_ONLY,
1328 GetDriveTypeW( full_name.short_name ) );
1329 if (!handle) goto not_found;
1331 GetFileTime( handle, NULL, NULL, &filetime );
1332 FileTimeToDosDateTime( &filetime, &filedatetime[0], &filedatetime[1] );
1333 if ((mode & OF_VERIFY) && (mode & OF_REOPEN))
1335 if (ofs->Reserved1 != filedatetime[0] || ofs->Reserved2 != filedatetime[1] )
1337 CloseHandle( handle );
1338 WARN("(%s): OF_VERIFY failed\n", name );
1339 /* FIXME: what error here? */
1340 SetLastError( ERROR_FILE_NOT_FOUND );
1344 ofs->Reserved1 = filedatetime[0];
1345 ofs->Reserved2 = filedatetime[1];
1347 success: /* We get here if the open was successful */
1348 TRACE("(%s): OK, return = %p\n", name, handle );
1351 hFileRet = (HFILE)handle;
1352 if (mode & OF_EXIST) /* Return the handle, but close it first */
1353 CloseHandle( handle );
1357 hFileRet = Win32HandleToDosFileHandle( handle );
1358 if (hFileRet == HFILE_ERROR16) goto error;
1359 if (mode & OF_EXIST) /* Return the handle, but close it first */
1360 _lclose16( hFileRet );
1364 not_found: /* We get here if the file does not exist */
1365 WARN("'%s' not found or sharing violation\n", name );
1366 SetLastError( ERROR_FILE_NOT_FOUND );
1369 error: /* We get here if there was an error opening the file */
1370 ofs->nErrCode = GetLastError();
1371 WARN("(%s): return = HFILE_ERROR error= %d\n",
1372 name,ofs->nErrCode );
1377 /***********************************************************************
1378 * OpenFile (KERNEL.74)
1379 * OpenFileEx (KERNEL.360)
1381 HFILE16 WINAPI OpenFile16( LPCSTR name, OFSTRUCT *ofs, UINT16 mode )
1383 return FILE_DoOpenFile( name, ofs, mode, FALSE );
1387 /***********************************************************************
1388 * OpenFile (KERNEL32.@)
1390 HFILE WINAPI OpenFile( LPCSTR name, OFSTRUCT *ofs, UINT mode )
1392 return FILE_DoOpenFile( name, ofs, mode, TRUE );
1396 /***********************************************************************
1397 * FILE_InitProcessDosHandles
1399 * Allocates the default DOS handles for a process. Called either by
1400 * Win32HandleToDosFileHandle below or by the DOSVM stuff.
1402 static void FILE_InitProcessDosHandles( void )
1404 HANDLE cp = GetCurrentProcess();
1405 DuplicateHandle(cp, GetStdHandle(STD_INPUT_HANDLE), cp, &dos_handles[0],
1406 0, TRUE, DUPLICATE_SAME_ACCESS);
1407 DuplicateHandle(cp, GetStdHandle(STD_OUTPUT_HANDLE), cp, &dos_handles[1],
1408 0, TRUE, DUPLICATE_SAME_ACCESS);
1409 DuplicateHandle(cp, GetStdHandle(STD_ERROR_HANDLE), cp, &dos_handles[2],
1410 0, TRUE, DUPLICATE_SAME_ACCESS);
1411 DuplicateHandle(cp, GetStdHandle(STD_ERROR_HANDLE), cp, &dos_handles[3],
1412 0, TRUE, DUPLICATE_SAME_ACCESS);
1413 DuplicateHandle(cp, GetStdHandle(STD_ERROR_HANDLE), cp, &dos_handles[4],
1414 0, TRUE, DUPLICATE_SAME_ACCESS);
1417 /***********************************************************************
1418 * Win32HandleToDosFileHandle (KERNEL32.21)
1420 * Allocate a DOS handle for a Win32 handle. The Win32 handle is no
1421 * longer valid after this function (even on failure).
1423 * Note: this is not exactly right, since on Win95 the Win32 handles
1424 * are on top of DOS handles and we do it the other way
1425 * around. Should be good enough though.
1427 HFILE WINAPI Win32HandleToDosFileHandle( HANDLE handle )
1431 if (!handle || (handle == INVALID_HANDLE_VALUE))
1434 for (i = 5; i < DOS_TABLE_SIZE; i++)
1435 if (!dos_handles[i])
1437 dos_handles[i] = handle;
1438 TRACE("Got %d for h32 %p\n", i, handle );
1441 CloseHandle( handle );
1442 SetLastError( ERROR_TOO_MANY_OPEN_FILES );
1447 /***********************************************************************
1448 * DosFileHandleToWin32Handle (KERNEL32.20)
1450 * Return the Win32 handle for a DOS handle.
1452 * Note: this is not exactly right, since on Win95 the Win32 handles
1453 * are on top of DOS handles and we do it the other way
1454 * around. Should be good enough though.
1456 HANDLE WINAPI DosFileHandleToWin32Handle( HFILE handle )
1458 HFILE16 hfile = (HFILE16)handle;
1459 if (hfile < 5 && !dos_handles[hfile]) FILE_InitProcessDosHandles();
1460 if ((hfile >= DOS_TABLE_SIZE) || !dos_handles[hfile])
1462 SetLastError( ERROR_INVALID_HANDLE );
1463 return INVALID_HANDLE_VALUE;
1465 return dos_handles[hfile];
1469 /***********************************************************************
1470 * DisposeLZ32Handle (KERNEL32.22)
1472 * Note: this is not entirely correct, we should only close the
1473 * 32-bit handle and not the 16-bit one, but we cannot do
1474 * this because of the way our DOS handles are implemented.
1475 * It shouldn't break anything though.
1477 void WINAPI DisposeLZ32Handle( HANDLE handle )
1481 if (!handle || (handle == INVALID_HANDLE_VALUE)) return;
1483 for (i = 5; i < DOS_TABLE_SIZE; i++)
1484 if (dos_handles[i] == handle)
1487 CloseHandle( handle );
1493 /***********************************************************************
1496 * dup2() function for DOS handles.
1498 HFILE16 FILE_Dup2( HFILE16 hFile1, HFILE16 hFile2 )
1502 if (hFile1 < 5 && !dos_handles[hFile1]) FILE_InitProcessDosHandles();
1504 if ((hFile1 >= DOS_TABLE_SIZE) || (hFile2 >= DOS_TABLE_SIZE) || !dos_handles[hFile1])
1506 SetLastError( ERROR_INVALID_HANDLE );
1507 return HFILE_ERROR16;
1509 if (!DuplicateHandle( GetCurrentProcess(), dos_handles[hFile1],
1510 GetCurrentProcess(), &new_handle,
1511 0, FALSE, DUPLICATE_SAME_ACCESS ))
1512 return HFILE_ERROR16;
1513 if (dos_handles[hFile2]) CloseHandle( dos_handles[hFile2] );
1514 dos_handles[hFile2] = new_handle;
1519 /***********************************************************************
1520 * _lclose (KERNEL.81)
1522 HFILE16 WINAPI _lclose16( HFILE16 hFile )
1524 if ((hFile >= DOS_TABLE_SIZE) || !dos_handles[hFile])
1526 SetLastError( ERROR_INVALID_HANDLE );
1527 return HFILE_ERROR16;
1529 TRACE("%d (handle32=%p)\n", hFile, dos_handles[hFile] );
1530 CloseHandle( dos_handles[hFile] );
1531 dos_handles[hFile] = 0;
1536 /***********************************************************************
1537 * GetOverlappedResult (KERNEL32.@)
1539 * Check the result of an Asynchronous data transfer from a file.
1545 * If successful (and relevant) lpTransferred will hold the number of
1546 * bytes transferred during the async operation.
1550 * Currently only works for WaitCommEvent, ReadFile, WriteFile
1551 * with communications ports.
1554 BOOL WINAPI GetOverlappedResult(
1555 HANDLE hFile, /* [in] handle of file to check on */
1556 LPOVERLAPPED lpOverlapped, /* [in/out] pointer to overlapped */
1557 LPDWORD lpTransferred, /* [in/out] number of bytes transferred */
1558 BOOL bWait /* [in] wait for the transfer to complete ? */
1562 TRACE("(%p %p %p %x)\n", hFile, lpOverlapped, lpTransferred, bWait);
1564 if(lpOverlapped==NULL)
1566 ERR("lpOverlapped was null\n");
1569 if(!lpOverlapped->hEvent)
1571 ERR("lpOverlapped->hEvent was null\n");
1578 TRACE("waiting on %p\n",lpOverlapped);
1579 r = WaitForSingleObjectEx(lpOverlapped->hEvent, INFINITE, TRUE);
1580 TRACE("wait on %p returned %ld\n",lpOverlapped,r);
1581 } while (r==STATUS_USER_APC);
1583 else if ( lpOverlapped->Internal == STATUS_PENDING )
1585 /* Wait in order to give APCs a chance to run. */
1586 /* This is cheating, so we must set the event again in case of success -
1587 it may be a non-manual reset event. */
1589 TRACE("waiting on %p\n",lpOverlapped);
1590 r = WaitForSingleObjectEx(lpOverlapped->hEvent, 0, TRUE);
1591 TRACE("wait on %p returned %ld\n",lpOverlapped,r);
1592 } while (r==STATUS_USER_APC);
1593 if ( r == WAIT_OBJECT_0 )
1594 NtSetEvent ( lpOverlapped->hEvent, NULL );
1598 *lpTransferred = lpOverlapped->InternalHigh;
1600 switch ( lpOverlapped->Internal )
1602 case STATUS_SUCCESS:
1604 case STATUS_PENDING:
1605 SetLastError ( ERROR_IO_INCOMPLETE );
1606 if ( bWait ) ERR ("PENDING status after waiting!\n");
1609 SetLastError ( RtlNtStatusToDosError ( lpOverlapped->Internal ) );
1614 /***********************************************************************
1615 * CancelIo (KERNEL32.@)
1617 BOOL WINAPI CancelIo(HANDLE handle)
1619 async_private *ovp,*t;
1621 TRACE("handle = %p\n",handle);
1623 for (ovp = NtCurrentTeb()->pending_list; ovp; ovp = t)
1626 if ( ovp->handle == handle )
1627 cancel_async ( ovp );
1629 WaitForMultipleObjectsEx(0,NULL,FALSE,1,TRUE);
1633 /***********************************************************************
1634 * FILE_AsyncReadService (INTERNAL)
1636 * This function is called while the client is waiting on the
1637 * server, so we can't make any server calls here.
1639 static void FILE_AsyncReadService(async_private *ovp)
1641 async_fileio *fileio = (async_fileio*) ovp;
1642 LPOVERLAPPED lpOverlapped = fileio->lpOverlapped;
1644 int already = lpOverlapped->InternalHigh;
1646 TRACE("%p %p\n", lpOverlapped, fileio->buffer );
1648 /* check to see if the data is ready (non-blocking) */
1650 if ( fileio->fd_type == FD_TYPE_SOCKET )
1651 result = read (ovp->fd, &fileio->buffer[already], fileio->count - already);
1654 result = pread (ovp->fd, &fileio->buffer[already], fileio->count - already,
1655 OVERLAPPED_OFFSET (lpOverlapped) + already);
1656 if ((result < 0) && (errno == ESPIPE))
1657 result = read (ovp->fd, &fileio->buffer[already], fileio->count - already);
1660 if ( (result<0) && ((errno == EAGAIN) || (errno == EINTR)))
1662 TRACE("Deferred read %d\n",errno);
1667 /* check to see if the transfer is complete */
1670 r = FILE_GetNtStatus ();
1673 else if ( result == 0 )
1675 r = ( lpOverlapped->InternalHigh ? STATUS_SUCCESS : STATUS_END_OF_FILE );
1679 lpOverlapped->InternalHigh += result;
1680 TRACE("read %d more bytes %ld/%d so far\n",result,lpOverlapped->InternalHigh,fileio->count);
1682 if(lpOverlapped->InternalHigh >= fileio->count || fileio->fd_type == FD_TYPE_SOCKET )
1688 lpOverlapped->Internal = r;
1691 /***********************************************************************
1692 * FILE_ReadFileEx (INTERNAL)
1694 static BOOL FILE_ReadFileEx(HANDLE hFile, LPVOID buffer, DWORD bytesToRead,
1695 LPOVERLAPPED overlapped,
1696 LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine,
1704 TRACE("file %p to buf %p num %ld %p func %p\n",
1705 hFile, buffer, bytesToRead, overlapped, lpCompletionRoutine);
1707 /* check that there is an overlapped struct */
1708 if (overlapped==NULL)
1710 SetLastError(ERROR_INVALID_PARAMETER);
1714 fd = FILE_GetUnixHandleType ( hFile, GENERIC_READ, &type, &flags);
1717 WARN ( "Couldn't get FD\n" );
1721 ovp = (async_fileio*) HeapAlloc(GetProcessHeap(), 0, sizeof (async_fileio));
1724 TRACE("HeapAlloc Failed\n");
1725 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1729 ovp->async.ops = ( lpCompletionRoutine ? &fileio_async_ops : &fileio_nocomp_async_ops );
1730 ovp->async.handle = hFile;
1732 ovp->async.type = ASYNC_TYPE_READ;
1733 ovp->async.func = FILE_AsyncReadService;
1734 ovp->async.event = hEvent;
1735 ovp->lpOverlapped = overlapped;
1736 ovp->count = bytesToRead;
1737 ovp->completion_func = lpCompletionRoutine;
1738 ovp->buffer = buffer;
1739 ovp->fd_type = type;
1741 return !register_new_async (&ovp->async);
1749 /***********************************************************************
1750 * ReadFileEx (KERNEL32.@)
1752 BOOL WINAPI ReadFileEx(HANDLE hFile, LPVOID buffer, DWORD bytesToRead,
1753 LPOVERLAPPED overlapped,
1754 LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine)
1756 overlapped->InternalHigh = 0;
1757 return FILE_ReadFileEx(hFile,buffer,bytesToRead,overlapped,lpCompletionRoutine, INVALID_HANDLE_VALUE);
1760 static BOOL FILE_TimeoutRead(HANDLE hFile, LPVOID buffer, DWORD bytesToRead, LPDWORD bytesRead)
1765 TRACE("%p %p %ld %p\n", hFile, buffer, bytesToRead, bytesRead );
1767 ZeroMemory(&ov, sizeof (OVERLAPPED));
1768 if(STATUS_SUCCESS==NtCreateEvent(&ov.hEvent, SYNCHRONIZE, NULL, 0, 0))
1770 if(FILE_ReadFileEx(hFile, buffer, bytesToRead, &ov, NULL, ov.hEvent))
1772 r = GetOverlappedResult(hFile, &ov, bytesRead, TRUE);
1775 CloseHandle(ov.hEvent);
1779 /***********************************************************************
1780 * ReadFile (KERNEL32.@)
1782 BOOL WINAPI ReadFile( HANDLE hFile, LPVOID buffer, DWORD bytesToRead,
1783 LPDWORD bytesRead, LPOVERLAPPED overlapped )
1785 int unix_handle, result, flags;
1788 TRACE("%p %p %ld %p %p\n", hFile, buffer, bytesToRead,
1789 bytesRead, overlapped );
1791 if (bytesRead) *bytesRead = 0; /* Do this before anything else */
1792 if (!bytesToRead) return TRUE;
1794 if (is_console_handle(hFile))
1795 return FILE_ReadConsole(hFile, buffer, bytesToRead, bytesRead, NULL);
1797 unix_handle = FILE_GetUnixHandleType( hFile, GENERIC_READ, &type, &flags );
1799 if (flags & FD_FLAG_OVERLAPPED)
1801 if (unix_handle == -1) return FALSE;
1802 if ( (overlapped==NULL) || NtResetEvent( overlapped->hEvent, NULL ) )
1804 TRACE("Overlapped not specified or invalid event flag\n");
1806 SetLastError(ERROR_INVALID_PARAMETER);
1811 overlapped->InternalHigh = 0;
1813 if(!FILE_ReadFileEx(hFile, buffer, bytesToRead, overlapped, NULL, overlapped->hEvent))
1816 if ( !GetOverlappedResult (hFile, overlapped, bytesRead, FALSE) )
1818 if ( GetLastError() == ERROR_IO_INCOMPLETE )
1819 SetLastError ( ERROR_IO_PENDING );
1825 if (flags & FD_FLAG_TIMEOUT)
1828 return FILE_TimeoutRead(hFile, buffer, bytesToRead, bytesRead);
1833 return SMB_ReadFile(hFile, buffer, bytesToRead, bytesRead, NULL);
1835 case FD_TYPE_DEFAULT:
1836 /* normal unix files */
1837 if (unix_handle == -1) return FALSE;
1840 DWORD highOffset = overlapped->OffsetHigh;
1841 if ( (INVALID_SET_FILE_POINTER == SetFilePointer(hFile, overlapped->Offset,
1842 &highOffset, FILE_BEGIN)) &&
1843 (GetLastError() != NO_ERROR) )
1852 if (unix_handle == -1)
1858 off_t offset = OVERLAPPED_OFFSET(overlapped);
1859 if(lseek(unix_handle, offset, SEEK_SET) == -1)
1862 SetLastError(ERROR_INVALID_PARAMETER);
1867 /* code for synchronous reads */
1868 while ((result = read( unix_handle, buffer, bytesToRead )) == -1)
1870 if ((errno == EAGAIN) || (errno == EINTR)) continue;
1871 if ((errno == EFAULT) && !IsBadWritePtr( buffer, bytesToRead )) continue;
1875 close( unix_handle );
1876 if (result == -1) return FALSE;
1877 if (bytesRead) *bytesRead = result;
1882 /***********************************************************************
1883 * FILE_AsyncWriteService (INTERNAL)
1885 * This function is called while the client is waiting on the
1886 * server, so we can't make any server calls here.
1888 static void FILE_AsyncWriteService(struct async_private *ovp)
1890 async_fileio *fileio = (async_fileio *) ovp;
1891 LPOVERLAPPED lpOverlapped = fileio->lpOverlapped;
1893 int already = lpOverlapped->InternalHigh;
1895 TRACE("(%p %p)\n",lpOverlapped,fileio->buffer);
1897 /* write some data (non-blocking) */
1899 if ( fileio->fd_type == FD_TYPE_SOCKET )
1900 result = write(ovp->fd, &fileio->buffer[already], fileio->count - already);
1903 result = pwrite(ovp->fd, &fileio->buffer[already], fileio->count - already,
1904 OVERLAPPED_OFFSET (lpOverlapped) + already);
1905 if ((result < 0) && (errno == ESPIPE))
1906 result = write(ovp->fd, &fileio->buffer[already], fileio->count - already);
1909 if ( (result<0) && ((errno == EAGAIN) || (errno == EINTR)))
1915 /* check to see if the transfer is complete */
1918 r = FILE_GetNtStatus ();
1922 lpOverlapped->InternalHigh += result;
1924 TRACE("wrote %d more bytes %ld/%d so far\n",result,lpOverlapped->InternalHigh,fileio->count);
1926 if(lpOverlapped->InternalHigh < fileio->count)
1932 lpOverlapped->Internal = r;
1935 /***********************************************************************
1938 static BOOL FILE_WriteFileEx(HANDLE hFile, LPCVOID buffer, DWORD bytesToWrite,
1939 LPOVERLAPPED overlapped,
1940 LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine,
1948 TRACE("file %p to buf %p num %ld %p func %p handle %p\n",
1949 hFile, buffer, bytesToWrite, overlapped, lpCompletionRoutine, hEvent);
1951 if (overlapped == NULL)
1953 SetLastError(ERROR_INVALID_PARAMETER);
1957 fd = FILE_GetUnixHandleType ( hFile, GENERIC_WRITE, &type, &flags );
1960 TRACE( "Couldn't get FD\n" );
1964 ovp = (async_fileio*) HeapAlloc(GetProcessHeap(), 0, sizeof (async_fileio));
1967 TRACE("HeapAlloc Failed\n");
1968 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1972 ovp->async.ops = ( lpCompletionRoutine ? &fileio_async_ops : &fileio_nocomp_async_ops );
1973 ovp->async.handle = hFile;
1975 ovp->async.type = ASYNC_TYPE_WRITE;
1976 ovp->async.func = FILE_AsyncWriteService;
1977 ovp->lpOverlapped = overlapped;
1978 ovp->async.event = hEvent;
1979 ovp->buffer = (LPVOID) buffer;
1980 ovp->count = bytesToWrite;
1981 ovp->completion_func = lpCompletionRoutine;
1982 ovp->fd_type = type;
1984 return !register_new_async (&ovp->async);
1991 /***********************************************************************
1992 * WriteFileEx (KERNEL32.@)
1994 BOOL WINAPI WriteFileEx(HANDLE hFile, LPCVOID buffer, DWORD bytesToWrite,
1995 LPOVERLAPPED overlapped,
1996 LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine)
1998 overlapped->InternalHigh = 0;
2000 return FILE_WriteFileEx(hFile, buffer, bytesToWrite, overlapped, lpCompletionRoutine, INVALID_HANDLE_VALUE);
2003 /***********************************************************************
2004 * WriteFile (KERNEL32.@)
2006 BOOL WINAPI WriteFile( HANDLE hFile, LPCVOID buffer, DWORD bytesToWrite,
2007 LPDWORD bytesWritten, LPOVERLAPPED overlapped )
2009 int unix_handle, result, flags;
2012 TRACE("%p %p %ld %p %p\n", hFile, buffer, bytesToWrite,
2013 bytesWritten, overlapped );
2015 if (bytesWritten) *bytesWritten = 0; /* Do this before anything else */
2016 if (!bytesToWrite) return TRUE;
2018 if (is_console_handle(hFile))
2019 return FILE_WriteConsole(hFile, buffer, bytesToWrite, bytesWritten, NULL);
2021 unix_handle = FILE_GetUnixHandleType( hFile, GENERIC_WRITE, &type, &flags );
2023 if (flags & FD_FLAG_OVERLAPPED)
2025 if (unix_handle == -1) return FALSE;
2026 if ( (overlapped==NULL) || NtResetEvent( overlapped->hEvent, NULL ) )
2028 TRACE("Overlapped not specified or invalid event flag\n");
2030 SetLastError(ERROR_INVALID_PARAMETER);
2035 overlapped->InternalHigh = 0;
2037 if(!FILE_WriteFileEx(hFile, buffer, bytesToWrite, overlapped, NULL, overlapped->hEvent))
2040 if ( !GetOverlappedResult (hFile, overlapped, bytesWritten, FALSE) )
2042 if ( GetLastError() == ERROR_IO_INCOMPLETE )
2043 SetLastError ( ERROR_IO_PENDING );
2052 case FD_TYPE_DEFAULT:
2053 if (unix_handle == -1) return FALSE;
2057 DWORD highOffset = overlapped->OffsetHigh;
2058 if ( (INVALID_SET_FILE_POINTER == SetFilePointer(hFile, overlapped->Offset,
2059 &highOffset, FILE_BEGIN)) &&
2060 (GetLastError() != NO_ERROR) )
2069 if (unix_handle == -1)
2074 SetLastError(ERROR_INVALID_PARAMETER);
2082 off_t offset = OVERLAPPED_OFFSET(overlapped);
2083 if(lseek(unix_handle, offset, SEEK_SET) == -1)
2086 SetLastError(ERROR_INVALID_PARAMETER);
2091 /* synchronous file write */
2092 while ((result = write( unix_handle, buffer, bytesToWrite )) == -1)
2094 if ((errno == EAGAIN) || (errno == EINTR)) continue;
2095 if ((errno == EFAULT) && !IsBadReadPtr( buffer, bytesToWrite )) continue;
2096 if (errno == ENOSPC)
2097 SetLastError( ERROR_DISK_FULL );
2102 close( unix_handle );
2103 if (result == -1) return FALSE;
2104 if (bytesWritten) *bytesWritten = result;
2109 /***********************************************************************
2110 * SetFilePointer (KERNEL32.@)
2112 DWORD WINAPI SetFilePointer( HANDLE hFile, LONG distance, LONG *highword,
2115 DWORD ret = INVALID_SET_FILE_POINTER;
2117 TRACE("handle %p offset %ld high %ld origin %ld\n",
2118 hFile, distance, highword?*highword:0, method );
2120 SERVER_START_REQ( set_file_pointer )
2122 req->handle = hFile;
2123 req->low = distance;
2124 req->high = highword ? *highword : (distance >= 0) ? 0 : -1;
2125 /* FIXME: assumes 1:1 mapping between Windows and Unix seek constants */
2126 req->whence = method;
2128 if (!wine_server_call_err( req ))
2130 ret = reply->new_low;
2131 if (highword) *highword = reply->new_high;
2139 /*************************************************************************
2140 * SetHandleCount (KERNEL32.@)
2142 UINT WINAPI SetHandleCount( UINT count )
2144 return min( 256, count );
2148 /**************************************************************************
2149 * SetEndOfFile (KERNEL32.@)
2151 BOOL WINAPI SetEndOfFile( HANDLE hFile )
2154 SERVER_START_REQ( truncate_file )
2156 req->handle = hFile;
2157 ret = !wine_server_call_err( req );
2164 /***********************************************************************
2165 * DeleteFileW (KERNEL32.@)
2167 BOOL WINAPI DeleteFileW( LPCWSTR path )
2169 DOS_FULL_NAME full_name;
2172 TRACE("%s\n", debugstr_w(path) );
2173 if (!path || !*path)
2175 SetLastError(ERROR_PATH_NOT_FOUND);
2178 if (DOSFS_GetDevice( path ))
2180 WARN("cannot remove DOS device %s!\n", debugstr_w(path));
2181 SetLastError( ERROR_FILE_NOT_FOUND );
2185 if (!DOSFS_GetFullName( path, TRUE, &full_name )) return FALSE;
2187 /* check if we are allowed to delete the source */
2188 hFile = FILE_CreateFile( full_name.long_name, GENERIC_READ|GENERIC_WRITE, 0,
2189 NULL, OPEN_EXISTING, 0, 0, TRUE,
2190 GetDriveTypeW( full_name.short_name ) );
2191 if (!hFile) return FALSE;
2193 if (unlink( full_name.long_name ) == -1)
2204 /***********************************************************************
2205 * DeleteFileA (KERNEL32.@)
2207 BOOL WINAPI DeleteFileA( LPCSTR path )
2209 UNICODE_STRING pathW;
2214 SetLastError(ERROR_INVALID_PARAMETER);
2218 if (RtlCreateUnicodeStringFromAsciiz(&pathW, path))
2220 ret = DeleteFileW(pathW.Buffer);
2221 RtlFreeUnicodeString(&pathW);
2224 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
2229 /***********************************************************************
2230 * GetFileType (KERNEL32.@)
2232 DWORD WINAPI GetFileType( HANDLE hFile )
2234 DWORD ret = FILE_TYPE_UNKNOWN;
2236 if (is_console_handle( hFile ))
2237 return FILE_TYPE_CHAR;
2239 SERVER_START_REQ( get_file_info )
2241 req->handle = hFile;
2242 if (!wine_server_call_err( req )) ret = reply->type;
2249 /* check if a file name is for an executable file (.exe or .com) */
2250 inline static BOOL is_executable( const char *name )
2252 int len = strlen(name);
2254 if (len < 4) return FALSE;
2255 return (!strcasecmp( name + len - 4, ".exe" ) ||
2256 !strcasecmp( name + len - 4, ".com" ));
2260 /***********************************************************************
2261 * FILE_AddBootRenameEntry
2263 * Adds an entry to the registry that is loaded when windows boots and
2264 * checks if there are some files to be removed or renamed/moved.
2265 * <fn1> has to be valid and <fn2> may be NULL. If both pointers are
2266 * non-NULL then the file is moved, otherwise it is deleted. The
2267 * entry of the registrykey is always appended with two zero
2268 * terminated strings. If <fn2> is NULL then the second entry is
2269 * simply a single 0-byte. Otherwise the second filename goes
2270 * there. The entries are prepended with \??\ before the path and the
2271 * second filename gets also a '!' as the first character if
2272 * MOVEFILE_REPLACE_EXISTING is set. After the final string another
2273 * 0-byte follows to indicate the end of the strings.
2275 * \??\D:\test\file1[0]
2276 * !\??\D:\test\file1_renamed[0]
2277 * \??\D:\Test|delete[0]
2278 * [0] <- file is to be deleted, second string empty
2279 * \??\D:\test\file2[0]
2280 * !\??\D:\test\file2_renamed[0]
2281 * [0] <- indicates end of strings
2284 * \??\D:\test\file1[0]
2285 * !\??\D:\test\file1_renamed[0]
2286 * \??\D:\Test|delete[0]
2287 * [0] <- file is to be deleted, second string empty
2288 * [0] <- indicates end of strings
2291 static BOOL FILE_AddBootRenameEntry( LPCWSTR fn1, LPCWSTR fn2, DWORD flags )
2293 static const WCHAR PreString[] = {'\\','?','?','\\',0};
2294 static const WCHAR ValueName[] = {'P','e','n','d','i','n','g',
2295 'F','i','l','e','R','e','n','a','m','e',
2296 'O','p','e','r','a','t','i','o','n','s',0};
2297 static const WCHAR SessionW[] = {'M','a','c','h','i','n','e','\\',
2298 'S','y','s','t','e','m','\\',
2299 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
2300 'C','o','n','t','r','o','l','\\',
2301 'S','e','s','s','i','o','n',' ','M','a','n','a','g','e','r',0};
2302 static const int info_size = FIELD_OFFSET( KEY_VALUE_PARTIAL_INFORMATION, Data );
2304 OBJECT_ATTRIBUTES attr;
2305 UNICODE_STRING nameW;
2306 KEY_VALUE_PARTIAL_INFORMATION *info;
2309 DWORD len0, len1, len2;
2311 BYTE *Buffer = NULL;
2314 attr.Length = sizeof(attr);
2315 attr.RootDirectory = 0;
2316 attr.ObjectName = &nameW;
2317 attr.Attributes = 0;
2318 attr.SecurityDescriptor = NULL;
2319 attr.SecurityQualityOfService = NULL;
2320 RtlInitUnicodeString( &nameW, SessionW );
2322 if (NtCreateKey( &Reboot, KEY_ALL_ACCESS, &attr, 0, NULL, 0, NULL ) != STATUS_SUCCESS)
2324 WARN("Error creating key for reboot managment [%s]\n",
2325 "SYSTEM\\CurrentControlSet\\Control\\Session Manager");
2329 len0 = strlenW(PreString);
2330 len1 = strlenW(fn1) + len0 + 1;
2333 len2 = strlenW(fn2) + len0 + 1;
2334 if (flags & MOVEFILE_REPLACE_EXISTING) len2++; /* Plus 1 because of the leading '!' */
2336 else len2 = 1; /* minimum is the 0 characters for the empty second string */
2338 /* convert characters to bytes */
2339 len0 *= sizeof(WCHAR);
2340 len1 *= sizeof(WCHAR);
2341 len2 *= sizeof(WCHAR);
2343 RtlInitUnicodeString( &nameW, ValueName );
2345 /* First we check if the key exists and if so how many bytes it already contains. */
2346 if (NtQueryValueKey( Reboot, &nameW, KeyValuePartialInformation,
2347 NULL, 0, &DataSize ) == STATUS_BUFFER_OVERFLOW)
2349 if (!(Buffer = HeapAlloc( GetProcessHeap(), 0, DataSize + len1 + len2 + sizeof(WCHAR) )))
2351 if (NtQueryValueKey( Reboot, &nameW, KeyValuePartialInformation,
2352 Buffer, DataSize, &DataSize )) goto Quit;
2353 info = (KEY_VALUE_PARTIAL_INFORMATION *)Buffer;
2354 if (info->Type != REG_MULTI_SZ) goto Quit;
2355 if (DataSize > sizeof(info)) DataSize -= sizeof(WCHAR); /* remove terminating null (will be added back later) */
2359 DataSize = info_size;
2360 if (!(Buffer = HeapAlloc( GetProcessHeap(), 0, DataSize + len1 + len2 + sizeof(WCHAR) )))
2364 p = (WCHAR *)(Buffer + DataSize);
2365 strcpyW( p, PreString );
2370 p = (WCHAR *)(Buffer + DataSize);
2371 if (flags & MOVEFILE_REPLACE_EXISTING)
2373 strcpyW( p, PreString );
2379 p = (WCHAR *)(Buffer + DataSize);
2381 DataSize += sizeof(WCHAR);
2384 /* add final null */
2385 p = (WCHAR *)(Buffer + DataSize);
2387 DataSize += sizeof(WCHAR);
2389 rc = !NtSetValueKey(Reboot, &nameW, 0, REG_MULTI_SZ, Buffer + info_size, DataSize - info_size);
2392 if (Reboot) NtClose(Reboot);
2393 if (Buffer) HeapFree( GetProcessHeap(), 0, Buffer );
2398 /**************************************************************************
2399 * MoveFileExW (KERNEL32.@)
2401 BOOL WINAPI MoveFileExW( LPCWSTR fn1, LPCWSTR fn2, DWORD flag )
2403 DOS_FULL_NAME full_name1, full_name2;
2405 DWORD attr = INVALID_FILE_ATTRIBUTES;
2407 TRACE("(%s,%s,%04lx)\n", debugstr_w(fn1), debugstr_w(fn2), flag);
2409 /* FIXME: <Gerhard W. Gruber>sparhawk@gmx.at
2410 In case of W9x and lesser this function should return 120 (ERROR_CALL_NOT_IMPLEMENTED)
2411 to be really compatible. Most programs wont have any problems though. In case
2412 you encounter one, this is what you should return here. I don't know what's up
2413 with NT 3.5. Is this function available there or not?
2414 Does anybody really care about 3.5? :)
2417 /* Filename1 has to be always set to a valid path. Filename2 may be NULL
2418 if the source file has to be deleted.
2421 SetLastError(ERROR_INVALID_PARAMETER);
2425 /* This function has to be run through in order to process the name properly.
2426 If the BOOTDELAY flag is set, the file doesn't need to exist though. At least
2427 that is the behaviour on NT 4.0. The operation accepts the filenames as
2428 they are given but it can't reply with a reasonable returncode. Success
2429 means in that case success for entering the values into the registry.
2431 if(!DOSFS_GetFullName( fn1, TRUE, &full_name1 ))
2433 if(!(flag & MOVEFILE_DELAY_UNTIL_REBOOT))
2437 if (fn2) /* !fn2 means delete fn1 */
2439 if (DOSFS_GetFullName( fn2, TRUE, &full_name2 ))
2441 if(!(flag & MOVEFILE_DELAY_UNTIL_REBOOT))
2443 /* target exists, check if we may overwrite */
2444 if (!(flag & MOVEFILE_REPLACE_EXISTING))
2446 SetLastError( ERROR_FILE_EXISTS );
2453 if (!DOSFS_GetFullName( fn2, FALSE, &full_name2 ))
2455 if(!(flag & MOVEFILE_DELAY_UNTIL_REBOOT))
2460 /* Source name and target path are valid */
2462 if (flag & MOVEFILE_DELAY_UNTIL_REBOOT)
2464 return FILE_AddBootRenameEntry( fn1, fn2, flag );
2467 attr = GetFileAttributesW( fn1 );
2468 if ( attr == INVALID_FILE_ATTRIBUTES ) return FALSE;
2470 /* check if we are allowed to rename the source */
2471 hFile = FILE_CreateFile( full_name1.long_name, 0, 0,
2472 NULL, OPEN_EXISTING, 0, 0, TRUE,
2473 GetDriveTypeW( full_name1.short_name ) );
2476 if (GetLastError() != ERROR_ACCESS_DENIED) return FALSE;
2477 if ( !(attr & FILE_ATTRIBUTE_DIRECTORY) ) return FALSE;
2478 /* if it's a directory we can continue */
2480 else CloseHandle(hFile);
2482 /* check, if we are allowed to delete the destination,
2483 ** (but the file not being there is fine) */
2484 hFile = FILE_CreateFile( full_name2.long_name, GENERIC_READ|GENERIC_WRITE, 0,
2485 NULL, OPEN_EXISTING, 0, 0, TRUE,
2486 GetDriveTypeW( full_name2.short_name ) );
2487 if(!hFile && GetLastError() != ERROR_FILE_NOT_FOUND) return FALSE;
2490 if (full_name1.drive != full_name2.drive)
2492 if (!(flag & MOVEFILE_COPY_ALLOWED))
2494 SetLastError( ERROR_NOT_SAME_DEVICE );
2497 else if ( attr & FILE_ATTRIBUTE_DIRECTORY )
2499 /* Strange, but that's what Windows returns */
2500 SetLastError ( ERROR_ACCESS_DENIED );
2504 if (rename( full_name1.long_name, full_name2.long_name ) == -1)
2505 /* Try copy/delete unless it's a directory. */
2506 /* FIXME: This does not handle the (unlikely) case that the two locations
2507 are on the same Wine drive, but on different Unix file systems. */
2509 if ( attr & FILE_ATTRIBUTE_DIRECTORY )
2516 if ( ! CopyFileW( fn1, fn2, !(flag & MOVEFILE_REPLACE_EXISTING) ))
2518 if ( ! DeleteFileW ( fn1 ) )
2522 if (is_executable( full_name1.long_name ) != is_executable( full_name2.long_name ))
2525 if (stat( full_name2.long_name, &fstat ) != -1)
2527 if (is_executable( full_name2.long_name ))
2528 /* set executable bit where read bit is set */
2529 fstat.st_mode |= (fstat.st_mode & 0444) >> 2;
2531 fstat.st_mode &= ~0111;
2532 chmod( full_name2.long_name, fstat.st_mode );
2537 else /* fn2 == NULL means delete source */
2539 if (flag & MOVEFILE_DELAY_UNTIL_REBOOT)
2541 if (flag & MOVEFILE_COPY_ALLOWED) {
2542 WARN("Illegal flag\n");
2543 SetLastError( ERROR_GEN_FAILURE );
2547 return FILE_AddBootRenameEntry( fn1, NULL, flag );
2550 if (unlink( full_name1.long_name ) == -1)
2555 return TRUE; /* successfully deleted */
2559 /**************************************************************************
2560 * MoveFileExA (KERNEL32.@)
2562 BOOL WINAPI MoveFileExA( LPCSTR fn1, LPCSTR fn2, DWORD flag )
2564 UNICODE_STRING fn1W, fn2W;
2569 SetLastError(ERROR_INVALID_PARAMETER);
2573 RtlCreateUnicodeStringFromAsciiz(&fn1W, fn1);
2574 if (fn2) RtlCreateUnicodeStringFromAsciiz(&fn2W, fn2);
2575 else fn2W.Buffer = NULL;
2577 ret = MoveFileExW( fn1W.Buffer, fn2W.Buffer, flag );
2579 RtlFreeUnicodeString(&fn1W);
2580 RtlFreeUnicodeString(&fn2W);
2585 /**************************************************************************
2586 * MoveFileW (KERNEL32.@)
2588 * Move file or directory
2590 BOOL WINAPI MoveFileW( LPCWSTR fn1, LPCWSTR fn2 )
2592 return MoveFileExW( fn1, fn2, MOVEFILE_COPY_ALLOWED );
2596 /**************************************************************************
2597 * MoveFileA (KERNEL32.@)
2599 BOOL WINAPI MoveFileA( LPCSTR fn1, LPCSTR fn2 )
2601 return MoveFileExA( fn1, fn2, MOVEFILE_COPY_ALLOWED );
2605 /**************************************************************************
2606 * CopyFileW (KERNEL32.@)
2608 BOOL WINAPI CopyFileW( LPCWSTR source, LPCWSTR dest, BOOL fail_if_exists )
2611 BY_HANDLE_FILE_INFORMATION info;
2616 if (!source || !dest)
2618 SetLastError(ERROR_INVALID_PARAMETER);
2622 TRACE("%s -> %s\n", debugstr_w(source), debugstr_w(dest));
2624 if ((h1 = CreateFileW(source, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE,
2625 NULL, OPEN_EXISTING, 0, 0)) == INVALID_HANDLE_VALUE)
2627 WARN("Unable to open source %s\n", debugstr_w(source));
2631 if (!GetFileInformationByHandle( h1, &info ))
2633 WARN("GetFileInformationByHandle returned error for %s\n", debugstr_w(source));
2638 if ((h2 = CreateFileW( dest, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
2639 fail_if_exists ? CREATE_NEW : CREATE_ALWAYS,
2640 info.dwFileAttributes, h1 )) == INVALID_HANDLE_VALUE)
2642 WARN("Unable to open dest %s\n", debugstr_w(dest));
2647 while (ReadFile( h1, buffer, sizeof(buffer), &count, NULL ) && count)
2653 if (!WriteFile( h2, p, count, &res, NULL ) || !res) goto done;
2666 /**************************************************************************
2667 * CopyFileA (KERNEL32.@)
2669 BOOL WINAPI CopyFileA( LPCSTR source, LPCSTR dest, BOOL fail_if_exists)
2671 UNICODE_STRING sourceW, destW;
2674 if (!source || !dest)
2676 SetLastError(ERROR_INVALID_PARAMETER);
2680 RtlCreateUnicodeStringFromAsciiz(&sourceW, source);
2681 RtlCreateUnicodeStringFromAsciiz(&destW, dest);
2683 ret = CopyFileW(sourceW.Buffer, destW.Buffer, fail_if_exists);
2685 RtlFreeUnicodeString(&sourceW);
2686 RtlFreeUnicodeString(&destW);
2691 /**************************************************************************
2692 * CopyFileExW (KERNEL32.@)
2694 * This implementation ignores most of the extra parameters passed-in into
2695 * the "ex" version of the method and calls the CopyFile method.
2696 * It will have to be fixed eventually.
2698 BOOL WINAPI CopyFileExW(LPCWSTR sourceFilename, LPCWSTR destFilename,
2699 LPPROGRESS_ROUTINE progressRoutine, LPVOID appData,
2700 LPBOOL cancelFlagPointer, DWORD copyFlags)
2703 * Interpret the only flag that CopyFile can interpret.
2705 return CopyFileW(sourceFilename, destFilename, (copyFlags & COPY_FILE_FAIL_IF_EXISTS) != 0);
2709 /**************************************************************************
2710 * CopyFileExA (KERNEL32.@)
2712 BOOL WINAPI CopyFileExA(LPCSTR sourceFilename, LPCSTR destFilename,
2713 LPPROGRESS_ROUTINE progressRoutine, LPVOID appData,
2714 LPBOOL cancelFlagPointer, DWORD copyFlags)
2716 UNICODE_STRING sourceW, destW;
2719 if (!sourceFilename || !destFilename)
2721 SetLastError(ERROR_INVALID_PARAMETER);
2725 RtlCreateUnicodeStringFromAsciiz(&sourceW, sourceFilename);
2726 RtlCreateUnicodeStringFromAsciiz(&destW, destFilename);
2728 ret = CopyFileExW(sourceW.Buffer, destW.Buffer, progressRoutine, appData,
2729 cancelFlagPointer, copyFlags);
2731 RtlFreeUnicodeString(&sourceW);
2732 RtlFreeUnicodeString(&destW);
2737 /***********************************************************************
2738 * SetFileTime (KERNEL32.@)
2740 BOOL WINAPI SetFileTime( HANDLE hFile,
2741 const FILETIME *lpCreationTime,
2742 const FILETIME *lpLastAccessTime,
2743 const FILETIME *lpLastWriteTime )
2746 SERVER_START_REQ( set_file_time )
2748 req->handle = hFile;
2749 if (lpLastAccessTime)
2750 RtlTimeToSecondsSince1970( (PLARGE_INTEGER) lpLastAccessTime, (DWORD *)&req->access_time );
2752 req->access_time = 0; /* FIXME */
2753 if (lpLastWriteTime)
2754 RtlTimeToSecondsSince1970( (PLARGE_INTEGER) lpLastWriteTime, (DWORD *)&req->write_time );
2756 req->write_time = 0; /* FIXME */
2757 ret = !wine_server_call_err( req );
2764 /**************************************************************************
2765 * GetFileAttributesExW (KERNEL32.@)
2767 BOOL WINAPI GetFileAttributesExW(
2768 LPCWSTR lpFileName, GET_FILEEX_INFO_LEVELS fInfoLevelId,
2769 LPVOID lpFileInformation)
2771 DOS_FULL_NAME full_name;
2772 BY_HANDLE_FILE_INFORMATION info;
2774 if (!lpFileName || !lpFileInformation)
2776 SetLastError(ERROR_INVALID_PARAMETER);
2780 if (fInfoLevelId == GetFileExInfoStandard) {
2781 LPWIN32_FILE_ATTRIBUTE_DATA lpFad =
2782 (LPWIN32_FILE_ATTRIBUTE_DATA) lpFileInformation;
2783 if (!DOSFS_GetFullName( lpFileName, TRUE, &full_name )) return FALSE;
2784 if (!FILE_Stat( full_name.long_name, &info, NULL )) return FALSE;
2786 lpFad->dwFileAttributes = info.dwFileAttributes;
2787 lpFad->ftCreationTime = info.ftCreationTime;
2788 lpFad->ftLastAccessTime = info.ftLastAccessTime;
2789 lpFad->ftLastWriteTime = info.ftLastWriteTime;
2790 lpFad->nFileSizeHigh = info.nFileSizeHigh;
2791 lpFad->nFileSizeLow = info.nFileSizeLow;
2794 FIXME("invalid info level %d!\n", fInfoLevelId);
2802 /**************************************************************************
2803 * GetFileAttributesExA (KERNEL32.@)
2805 BOOL WINAPI GetFileAttributesExA(
2806 LPCSTR filename, GET_FILEEX_INFO_LEVELS fInfoLevelId,
2807 LPVOID lpFileInformation)
2809 UNICODE_STRING filenameW;
2812 if (!filename || !lpFileInformation)
2814 SetLastError(ERROR_INVALID_PARAMETER);
2818 if (RtlCreateUnicodeStringFromAsciiz(&filenameW, filename))
2820 ret = GetFileAttributesExW(filenameW.Buffer, fInfoLevelId, lpFileInformation);
2821 RtlFreeUnicodeString(&filenameW);
2824 SetLastError(ERROR_NOT_ENOUGH_MEMORY);