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"
37 #ifdef HAVE_SYS_ERRNO_H
38 #include <sys/errno.h>
40 #include <sys/types.h>
42 #ifdef HAVE_SYS_MMAN_H
45 #ifdef HAVE_SYS_TIME_H
46 # include <sys/time.h>
48 #ifdef HAVE_SYS_POLL_H
49 # include <sys/poll.h>
59 #define NONAMELESSUNION
60 #define NONAMELESSSTRUCT
67 #include "wine/winbase16.h"
68 #include "wine/server.h"
72 #include "kernel_private.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
84 #define IS_OPTION_TRUE(ch) ((ch) == 'y' || (ch) == 'Y' || (ch) == 't' || (ch) == 'T' || (ch) == '1')
88 /***********************************************************************
91 * Convert OF_* mode into flags for CreateFile.
93 void FILE_ConvertOFMode( INT mode, DWORD *access, DWORD *sharing )
97 case OF_READ: *access = GENERIC_READ; break;
98 case OF_WRITE: *access = GENERIC_WRITE; break;
99 case OF_READWRITE: *access = GENERIC_READ | GENERIC_WRITE; break;
100 default: *access = 0; break;
104 case OF_SHARE_EXCLUSIVE: *sharing = 0; break;
105 case OF_SHARE_DENY_WRITE: *sharing = FILE_SHARE_READ; break;
106 case OF_SHARE_DENY_READ: *sharing = FILE_SHARE_WRITE; break;
107 case OF_SHARE_DENY_NONE:
108 case OF_SHARE_COMPAT:
109 default: *sharing = FILE_SHARE_READ | FILE_SHARE_WRITE; break;
114 /***********************************************************************
117 * Set the DOS error code from errno.
119 void FILE_SetDosError(void)
121 int save_errno = errno; /* errno gets overwritten by printf */
123 TRACE("errno = %d %s\n", errno, strerror(errno));
127 SetLastError( ERROR_SHARING_VIOLATION );
130 SetLastError( ERROR_INVALID_HANDLE );
133 SetLastError( ERROR_HANDLE_DISK_FULL );
138 SetLastError( ERROR_ACCESS_DENIED );
141 SetLastError( ERROR_LOCK_VIOLATION );
144 SetLastError( ERROR_FILE_NOT_FOUND );
147 SetLastError( ERROR_CANNOT_MAKE );
151 SetLastError( ERROR_NO_MORE_FILES );
154 SetLastError( ERROR_FILE_EXISTS );
158 SetLastError( ERROR_SEEK );
161 SetLastError( ERROR_DIR_NOT_EMPTY );
164 SetLastError( ERROR_BAD_FORMAT );
167 WARN("unknown file error: %s\n", strerror(save_errno) );
168 SetLastError( ERROR_GEN_FAILURE );
175 /***********************************************************************
178 * Implementation of CreateFile. Takes a Unix path name.
179 * Returns 0 on failure.
181 HANDLE FILE_CreateFile( LPCSTR filename, DWORD access, DWORD sharing,
182 LPSECURITY_ATTRIBUTES sa, DWORD creation,
183 DWORD attributes, HANDLE template, BOOL fail_read_only,
191 SERVER_START_REQ( create_file )
193 req->access = access;
194 req->inherit = (sa && (sa->nLength>=sizeof(*sa)) && sa->bInheritHandle);
195 req->sharing = sharing;
196 req->create = creation;
197 req->attrs = attributes;
198 req->removable = (drive_type == DRIVE_REMOVABLE || drive_type == DRIVE_CDROM);
199 wine_server_add_data( req, filename, strlen(filename) );
201 err = wine_server_call( req );
206 /* If write access failed, retry without GENERIC_WRITE */
208 if (!ret && !fail_read_only && (access & GENERIC_WRITE))
210 if ((err == STATUS_MEDIA_WRITE_PROTECTED) || (err == STATUS_ACCESS_DENIED))
212 TRACE("Write access failed for file '%s', trying without "
213 "write access\n", filename);
214 access &= ~GENERIC_WRITE;
221 /* In the case file creation was rejected due to CREATE_NEW flag
222 * was specified and file with that name already exists, correct
223 * last error is ERROR_FILE_EXISTS and not ERROR_ALREADY_EXISTS.
224 * Note: RtlNtStatusToDosError is not the subject to blame here.
226 if (err == STATUS_OBJECT_NAME_COLLISION)
227 SetLastError( ERROR_FILE_EXISTS );
229 SetLastError( RtlNtStatusToDosError(err) );
232 if (!ret) WARN("Unable to create file '%s' (GLE %ld)\n", filename, GetLastError());
238 static HANDLE FILE_OpenPipe(LPCWSTR name, DWORD access, LPSECURITY_ATTRIBUTES sa )
243 if (name && (len = strlenW(name)) > MAX_PATH)
245 SetLastError( ERROR_FILENAME_EXCED_RANGE );
248 SERVER_START_REQ( open_named_pipe )
250 req->access = access;
251 req->inherit = (sa && (sa->nLength>=sizeof(*sa)) && sa->bInheritHandle);
253 wine_server_add_data( req, name, len * sizeof(WCHAR) );
254 wine_server_call_err( req );
258 TRACE("Returned %p\n",ret);
262 /*************************************************************************
263 * CreateFileW [KERNEL32.@] Creates or opens a file or other object
265 * Creates or opens an object, and returns a handle that can be used to
266 * access that object.
270 * filename [in] pointer to filename to be accessed
271 * access [in] access mode requested
272 * sharing [in] share mode
273 * sa [in] pointer to security attributes
274 * creation [in] how to create the file
275 * attributes [in] attributes for newly created file
276 * template [in] handle to file with extended attributes to copy
279 * Success: Open handle to specified file
280 * Failure: INVALID_HANDLE_VALUE
283 * Should call SetLastError() on failure.
287 * Doesn't support character devices, template files, or a
288 * lot of the 'attributes' flags yet.
290 HANDLE WINAPI CreateFileW( LPCWSTR filename, DWORD access, DWORD sharing,
291 LPSECURITY_ATTRIBUTES sa, DWORD creation,
292 DWORD attributes, HANDLE template )
294 DOS_FULL_NAME full_name;
296 static const WCHAR bkslashes_with_question_markW[] = {'\\','\\','?','\\',0};
297 static const WCHAR bkslashes_with_dotW[] = {'\\','\\','.','\\',0};
298 static const WCHAR bkslashesW[] = {'\\','\\',0};
299 static const WCHAR coninW[] = {'C','O','N','I','N','$',0};
300 static const WCHAR conoutW[] = {'C','O','N','O','U','T','$',0};
304 SetLastError( ERROR_INVALID_PARAMETER );
305 return INVALID_HANDLE_VALUE;
307 TRACE("%s %s%s%s%s%s%s%s attributes 0x%lx\n", debugstr_w(filename),
308 ((access & GENERIC_READ)==GENERIC_READ)?"GENERIC_READ ":"",
309 ((access & GENERIC_WRITE)==GENERIC_WRITE)?"GENERIC_WRITE ":"",
310 (!access)?"QUERY_ACCESS ":"",
311 ((sharing & FILE_SHARE_READ)==FILE_SHARE_READ)?"FILE_SHARE_READ ":"",
312 ((sharing & FILE_SHARE_WRITE)==FILE_SHARE_WRITE)?"FILE_SHARE_WRITE ":"",
313 ((sharing & FILE_SHARE_DELETE)==FILE_SHARE_DELETE)?"FILE_SHARE_DELETE ":"",
314 (creation ==CREATE_NEW)?"CREATE_NEW":
315 (creation ==CREATE_ALWAYS)?"CREATE_ALWAYS ":
316 (creation ==OPEN_EXISTING)?"OPEN_EXISTING ":
317 (creation ==OPEN_ALWAYS)?"OPEN_ALWAYS ":
318 (creation ==TRUNCATE_EXISTING)?"TRUNCATE_EXISTING ":"", attributes);
320 /* If the name starts with '\\?\', ignore the first 4 chars. */
321 if (!strncmpW(filename, bkslashes_with_question_markW, 4))
323 static const WCHAR uncW[] = {'U','N','C','\\',0};
325 if (!strncmpiW(filename, uncW, 4))
327 FIXME("UNC name (%s) not supported.\n", debugstr_w(filename) );
328 SetLastError( ERROR_PATH_NOT_FOUND );
329 return INVALID_HANDLE_VALUE;
333 if (!strncmpW(filename, bkslashes_with_dotW, 4))
335 static const WCHAR pipeW[] = {'P','I','P','E','\\',0};
336 if(!strncmpiW(filename + 4, pipeW, 5))
338 TRACE("Opening a pipe: %s\n", debugstr_w(filename));
339 ret = FILE_OpenPipe( filename, access, sa );
342 else if (isalphaW(filename[4]) && filename[5] == ':' && filename[6] == '\0')
344 const char *device = DRIVE_GetDevice( toupperW(filename[4]) - 'A' );
347 ret = FILE_CreateFile( device, access, sharing, sa, creation,
348 attributes, template, TRUE, DRIVE_FIXED );
352 SetLastError( ERROR_ACCESS_DENIED );
353 ret = INVALID_HANDLE_VALUE;
357 else if (!RtlIsDosDeviceName_U( filename ))
359 ret = VXD_Open( filename+4, access, sa );
363 filename+=4; /* fall into DOSFS_Device case below */
366 /* If the name still starts with '\\', it's a UNC name. */
367 if (!strncmpW(filename, bkslashesW, 2))
369 ret = SMB_CreateFileW(filename, access, sharing, sa, creation, attributes, template );
373 /* If the name contains a DOS wild card (* or ?), do no create a file */
374 if(strchrW(filename, '*') || strchrW(filename, '?'))
376 SetLastError(ERROR_BAD_PATHNAME);
377 return INVALID_HANDLE_VALUE;
380 /* Open a console for CONIN$ or CONOUT$ */
381 if (!strcmpiW(filename, coninW) || !strcmpiW(filename, conoutW))
383 ret = OpenConsoleW(filename, access, sa, creation);
387 if (RtlIsDosDeviceName_U( filename ))
389 TRACE("opening device %s\n", debugstr_w(filename) );
391 if (!(ret = DOSFS_OpenDevice( filename, access, attributes, sa )))
393 /* Do not silence this please. It is a critical error. -MM */
394 ERR("Couldn't open device %s!\n", debugstr_w(filename));
395 SetLastError( ERROR_FILE_NOT_FOUND );
400 /* check for filename, don't check for last entry if creating */
401 if (!DOSFS_GetFullName( filename,
402 (creation == OPEN_EXISTING) ||
403 (creation == TRUNCATE_EXISTING),
405 WARN("Unable to get full filename from %s (GLE %ld)\n",
406 debugstr_w(filename), GetLastError());
407 return INVALID_HANDLE_VALUE;
410 ret = FILE_CreateFile( full_name.long_name, access, sharing,
411 sa, creation, attributes, template,
412 DRIVE_GetFlags(full_name.drive) & DRIVE_FAIL_READ_ONLY,
413 GetDriveTypeW( full_name.short_name ) );
415 if (!ret) ret = INVALID_HANDLE_VALUE;
416 TRACE("returning %p\n", ret);
422 /*************************************************************************
423 * CreateFileA (KERNEL32.@)
425 HANDLE WINAPI CreateFileA( LPCSTR filename, DWORD access, DWORD sharing,
426 LPSECURITY_ATTRIBUTES sa, DWORD creation,
427 DWORD attributes, HANDLE template)
429 UNICODE_STRING filenameW;
430 HANDLE ret = INVALID_HANDLE_VALUE;
434 SetLastError( ERROR_INVALID_PARAMETER );
435 return INVALID_HANDLE_VALUE;
438 if (RtlCreateUnicodeStringFromAsciiz(&filenameW, filename))
440 ret = CreateFileW(filenameW.Buffer, access, sharing, sa, creation,
441 attributes, template);
442 RtlFreeUnicodeString(&filenameW);
445 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
450 /***********************************************************************
453 * Fill a file information from a struct stat.
455 static void FILE_FillInfo( struct stat *st, BY_HANDLE_FILE_INFORMATION *info )
457 if (S_ISDIR(st->st_mode))
458 info->dwFileAttributes = FILE_ATTRIBUTE_DIRECTORY;
460 info->dwFileAttributes = FILE_ATTRIBUTE_ARCHIVE;
461 if (!(st->st_mode & S_IWUSR))
462 info->dwFileAttributes |= FILE_ATTRIBUTE_READONLY;
464 RtlSecondsSince1970ToTime( st->st_mtime, (LARGE_INTEGER *)&info->ftCreationTime );
465 RtlSecondsSince1970ToTime( st->st_mtime, (LARGE_INTEGER *)&info->ftLastWriteTime );
466 RtlSecondsSince1970ToTime( st->st_atime, (LARGE_INTEGER *)&info->ftLastAccessTime );
468 info->dwVolumeSerialNumber = 0; /* FIXME */
469 info->nFileSizeHigh = 0;
470 info->nFileSizeLow = 0;
471 if (!S_ISDIR(st->st_mode)) {
472 info->nFileSizeHigh = st->st_size >> 32;
473 info->nFileSizeLow = st->st_size & 0xffffffff;
475 info->nNumberOfLinks = st->st_nlink;
476 info->nFileIndexHigh = 0;
477 info->nFileIndexLow = st->st_ino;
481 /***********************************************************************
482 * get_show_dot_files_option
484 static BOOL get_show_dot_files_option(void)
486 static const WCHAR WineW[] = {'M','a','c','h','i','n','e','\\',
487 'S','o','f','t','w','a','r','e','\\',
488 'W','i','n','e','\\','W','i','n','e','\\',
489 'C','o','n','f','i','g','\\','W','i','n','e',0};
490 static const WCHAR ShowDotFilesW[] = {'S','h','o','w','D','o','t','F','i','l','e','s',0};
495 OBJECT_ATTRIBUTES attr;
496 UNICODE_STRING nameW;
499 attr.Length = sizeof(attr);
500 attr.RootDirectory = 0;
501 attr.ObjectName = &nameW;
503 attr.SecurityDescriptor = NULL;
504 attr.SecurityQualityOfService = NULL;
505 RtlInitUnicodeString( &nameW, WineW );
507 if (!NtOpenKey( &hkey, KEY_ALL_ACCESS, &attr ))
509 RtlInitUnicodeString( &nameW, ShowDotFilesW );
510 if (!NtQueryValueKey( hkey, &nameW, KeyValuePartialInformation, tmp, sizeof(tmp), &dummy ))
512 WCHAR *str = (WCHAR *)((KEY_VALUE_PARTIAL_INFORMATION *)tmp)->Data;
513 ret = IS_OPTION_TRUE( str[0] );
521 /***********************************************************************
524 * Stat a Unix path name. Return TRUE if OK.
526 BOOL FILE_Stat( LPCSTR unixName, BY_HANDLE_FILE_INFORMATION *info, BOOL *is_symlink_ptr )
532 if (lstat( unixName, &st ) == -1)
537 is_symlink = S_ISLNK(st.st_mode);
540 /* do a "real" stat to find out
541 about the type of the symlink destination */
542 if (stat( unixName, &st ) == -1)
549 /* fill in the information we gathered so far */
550 FILE_FillInfo( &st, info );
552 /* and now see if this is a hidden file, based on the name */
553 p = strrchr( unixName, '/');
554 p = p ? p + 1 : unixName;
555 if (*p == '.' && *(p+1) && (*(p+1) != '.' || *(p+2)))
557 static int show_dot_files = -1;
558 if (show_dot_files == -1)
559 show_dot_files = get_show_dot_files_option();
561 info->dwFileAttributes |= FILE_ATTRIBUTE_HIDDEN;
563 if (is_symlink_ptr) *is_symlink_ptr = is_symlink;
568 /***********************************************************************
569 * GetFileInformationByHandle (KERNEL32.@)
571 DWORD WINAPI GetFileInformationByHandle( HANDLE hFile,
572 BY_HANDLE_FILE_INFORMATION *info )
577 TRACE("%p\n", hFile);
579 SERVER_START_REQ( get_file_info )
582 if ((ret = !wine_server_call_err( req )))
584 /* FIXME: which file types are supported ?
585 * Serial ports (FILE_TYPE_CHAR) are not,
586 * and MSDN also says that pipes are not supported.
587 * FILE_TYPE_REMOTE seems to be supported according to
588 * MSDN q234741.txt */
589 if ((reply->type == FILE_TYPE_DISK) || (reply->type == FILE_TYPE_REMOTE))
591 RtlSecondsSince1970ToTime( reply->write_time, (LARGE_INTEGER *)&info->ftCreationTime );
592 RtlSecondsSince1970ToTime( reply->write_time, (LARGE_INTEGER *)&info->ftLastWriteTime );
593 RtlSecondsSince1970ToTime( reply->access_time, (LARGE_INTEGER *)&info->ftLastAccessTime );
594 info->dwFileAttributes = reply->attr;
595 info->dwVolumeSerialNumber = reply->serial;
596 info->nFileSizeHigh = reply->size_high;
597 info->nFileSizeLow = reply->size_low;
598 info->nNumberOfLinks = reply->links;
599 info->nFileIndexHigh = reply->index_high;
600 info->nFileIndexLow = reply->index_low;
604 SetLastError(ERROR_NOT_SUPPORTED);
614 /**************************************************************************
615 * GetFileAttributesW (KERNEL32.@)
617 DWORD WINAPI GetFileAttributesW( LPCWSTR name )
619 DOS_FULL_NAME full_name;
620 BY_HANDLE_FILE_INFORMATION info;
624 SetLastError( ERROR_INVALID_PARAMETER );
625 return INVALID_FILE_ATTRIBUTES;
627 if (!DOSFS_GetFullName( name, TRUE, &full_name) )
628 return INVALID_FILE_ATTRIBUTES;
629 if (!FILE_Stat( full_name.long_name, &info, NULL ))
630 return INVALID_FILE_ATTRIBUTES;
631 return info.dwFileAttributes;
635 /**************************************************************************
636 * GetFileAttributesA (KERNEL32.@)
638 DWORD WINAPI GetFileAttributesA( LPCSTR name )
640 UNICODE_STRING nameW;
641 DWORD ret = INVALID_FILE_ATTRIBUTES;
645 SetLastError( ERROR_INVALID_PARAMETER );
646 return INVALID_FILE_ATTRIBUTES;
649 if (RtlCreateUnicodeStringFromAsciiz(&nameW, name))
651 ret = GetFileAttributesW(nameW.Buffer);
652 RtlFreeUnicodeString(&nameW);
655 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
660 /**************************************************************************
661 * SetFileAttributesW (KERNEL32.@)
663 BOOL WINAPI SetFileAttributesW(LPCWSTR lpFileName, DWORD attributes)
666 DOS_FULL_NAME full_name;
670 SetLastError( ERROR_INVALID_PARAMETER );
674 TRACE("(%s,%lx)\n", debugstr_w(lpFileName), attributes);
676 if (!DOSFS_GetFullName( lpFileName, TRUE, &full_name ))
679 if(stat(full_name.long_name,&buf)==-1)
684 if (attributes & FILE_ATTRIBUTE_READONLY)
686 if(S_ISDIR(buf.st_mode))
688 WARN("FILE_ATTRIBUTE_READONLY ignored for directory.\n");
690 buf.st_mode &= ~0222; /* octal!, clear write permission bits */
691 attributes &= ~FILE_ATTRIBUTE_READONLY;
695 /* add write permission */
696 buf.st_mode |= (0600 | ((buf.st_mode & 044) >> 1)) & (~FILE_umask);
698 if (attributes & FILE_ATTRIBUTE_DIRECTORY)
700 if (!S_ISDIR(buf.st_mode))
701 FIXME("SetFileAttributes expected the file %s to be a directory\n",
702 debugstr_w(lpFileName));
703 attributes &= ~FILE_ATTRIBUTE_DIRECTORY;
705 attributes &= ~(FILE_ATTRIBUTE_NORMAL|FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_HIDDEN|
706 FILE_ATTRIBUTE_SYSTEM|FILE_ATTRIBUTE_TEMPORARY);
708 FIXME("(%s):%lx attribute(s) not implemented.\n", debugstr_w(lpFileName), attributes);
709 if (-1==chmod(full_name.long_name,buf.st_mode))
711 if (GetDriveTypeW(lpFileName) == DRIVE_CDROM)
713 SetLastError( ERROR_ACCESS_DENIED );
718 * FIXME: We don't return FALSE here because of differences between
719 * Linux and Windows privileges. Under Linux only the owner of
720 * the file is allowed to change file attributes. Under Windows,
721 * applications expect that if you can write to a file, you can also
722 * change its attributes (see GENERIC_WRITE). We could try to be
723 * clever here but that would break multi-user installations where
724 * users share read-only DLLs. This is because some installers like
725 * to change attributes of already installed DLLs.
727 FIXME("Couldn't set file attributes for existing file \"%s\".\n"
728 "Check permissions or set VFAT \"quiet\" mount flag\n", full_name.long_name);
734 /**************************************************************************
735 * SetFileAttributesA (KERNEL32.@)
737 BOOL WINAPI SetFileAttributesA(LPCSTR lpFileName, DWORD attributes)
739 UNICODE_STRING filenameW;
744 SetLastError( ERROR_INVALID_PARAMETER );
748 if (RtlCreateUnicodeStringFromAsciiz(&filenameW, lpFileName))
750 ret = SetFileAttributesW(filenameW.Buffer, attributes);
751 RtlFreeUnicodeString(&filenameW);
754 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
759 /******************************************************************************
760 * GetCompressedFileSizeA [KERNEL32.@]
762 DWORD WINAPI GetCompressedFileSizeA(
764 LPDWORD lpFileSizeHigh)
766 UNICODE_STRING filenameW;
769 if (RtlCreateUnicodeStringFromAsciiz(&filenameW, lpFileName))
771 ret = GetCompressedFileSizeW(filenameW.Buffer, lpFileSizeHigh);
772 RtlFreeUnicodeString(&filenameW);
776 ret = INVALID_FILE_SIZE;
777 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
783 /******************************************************************************
784 * GetCompressedFileSizeW [KERNEL32.@]
787 * Success: Low-order doubleword of number of bytes
788 * Failure: INVALID_FILE_SIZE
790 DWORD WINAPI GetCompressedFileSizeW(
791 LPCWSTR lpFileName, /* [in] Pointer to name of file */
792 LPDWORD lpFileSizeHigh) /* [out] Receives high-order doubleword of size */
794 DOS_FULL_NAME full_name;
798 TRACE("(%s,%p)\n",debugstr_w(lpFileName),lpFileSizeHigh);
800 if (!DOSFS_GetFullName( lpFileName, TRUE, &full_name )) return INVALID_FILE_SIZE;
801 if (stat(full_name.long_name, &st) != 0)
804 return INVALID_FILE_SIZE;
806 #if HAVE_STRUCT_STAT_ST_BLOCKS
807 /* blocks are 512 bytes long */
808 if (lpFileSizeHigh) *lpFileSizeHigh = (st.st_blocks >> 23);
809 low = (DWORD)(st.st_blocks << 9);
811 if (lpFileSizeHigh) *lpFileSizeHigh = (st.st_size >> 32);
812 low = (DWORD)st.st_size;
818 /***********************************************************************
819 * GetFileTime (KERNEL32.@)
821 BOOL WINAPI GetFileTime( HANDLE hFile, FILETIME *lpCreationTime,
822 FILETIME *lpLastAccessTime,
823 FILETIME *lpLastWriteTime )
825 BY_HANDLE_FILE_INFORMATION info;
826 if (!GetFileInformationByHandle( hFile, &info )) return FALSE;
827 if (lpCreationTime) *lpCreationTime = info.ftCreationTime;
828 if (lpLastAccessTime) *lpLastAccessTime = info.ftLastAccessTime;
829 if (lpLastWriteTime) *lpLastWriteTime = info.ftLastWriteTime;
834 /***********************************************************************
835 * GetTempFileNameA (KERNEL32.@)
837 UINT WINAPI GetTempFileNameA( LPCSTR path, LPCSTR prefix, UINT unique,
840 UNICODE_STRING pathW, prefixW;
841 WCHAR bufferW[MAX_PATH];
844 if ( !path || !prefix || !buffer )
846 SetLastError( ERROR_INVALID_PARAMETER );
850 RtlCreateUnicodeStringFromAsciiz(&pathW, path);
851 RtlCreateUnicodeStringFromAsciiz(&prefixW, prefix);
853 ret = GetTempFileNameW(pathW.Buffer, prefixW.Buffer, unique, bufferW);
855 WideCharToMultiByte(CP_ACP, 0, bufferW, -1, buffer, MAX_PATH, NULL, NULL);
857 RtlFreeUnicodeString(&pathW);
858 RtlFreeUnicodeString(&prefixW);
862 /***********************************************************************
863 * GetTempFileNameW (KERNEL32.@)
865 UINT WINAPI GetTempFileNameW( LPCWSTR path, LPCWSTR prefix, UINT unique,
868 static const WCHAR formatW[] = {'%','x','.','t','m','p',0};
870 DOS_FULL_NAME full_name;
874 if ( !path || !prefix || !buffer )
876 SetLastError( ERROR_INVALID_PARAMETER );
880 strcpyW( buffer, path );
881 p = buffer + strlenW(buffer);
883 /* add a \, if there isn't one */
884 if ((p == buffer) || (p[-1] != '\\')) *p++ = '\\';
886 for (i = 3; (i > 0) && (*prefix); i--) *p++ = *prefix++;
890 if (unique) sprintfW( p, formatW, unique );
893 /* get a "random" unique number and try to create the file */
895 UINT num = GetTickCount() & 0xffff;
901 sprintfW( p, formatW, unique );
902 handle = CreateFileW( buffer, GENERIC_WRITE, 0, NULL,
903 CREATE_NEW, FILE_ATTRIBUTE_NORMAL, 0 );
904 if (handle != INVALID_HANDLE_VALUE)
905 { /* We created it */
906 TRACE("created %s\n", debugstr_w(buffer) );
907 CloseHandle( handle );
910 if (GetLastError() != ERROR_FILE_EXISTS &&
911 GetLastError() != ERROR_SHARING_VIOLATION)
912 break; /* No need to go on */
913 if (!(++unique & 0xffff)) unique = 1;
914 } while (unique != num);
917 /* Get the full path name */
919 if (DOSFS_GetFullName( buffer, FALSE, &full_name ))
922 /* Check if we have write access in the directory */
923 if ((slash = strrchr( full_name.long_name, '/' ))) *slash = '\0';
924 if (access( full_name.long_name, W_OK ) == -1)
925 WARN("returns %s, which doesn't seem to be writeable.\n",
926 debugstr_w(buffer) );
928 TRACE("returning %s\n", debugstr_w(buffer) );
933 /***********************************************************************
936 * Implementation of OpenFile16() and OpenFile32().
938 static HFILE FILE_DoOpenFile( LPCSTR name, OFSTRUCT *ofs, UINT mode, BOOL win32 )
943 WORD filedatetime[2];
944 DOS_FULL_NAME full_name;
945 DWORD access, sharing;
947 WCHAR buffer[MAX_PATH];
950 if (!ofs) return HFILE_ERROR;
952 TRACE("%s %s %s %s%s%s%s%s%s%s%s%s\n",name,
953 ((mode & 0x3 )==OF_READ)?"OF_READ":
954 ((mode & 0x3 )==OF_WRITE)?"OF_WRITE":
955 ((mode & 0x3 )==OF_READWRITE)?"OF_READWRITE":"unknown",
956 ((mode & 0x70 )==OF_SHARE_COMPAT)?"OF_SHARE_COMPAT":
957 ((mode & 0x70 )==OF_SHARE_DENY_NONE)?"OF_SHARE_DENY_NONE":
958 ((mode & 0x70 )==OF_SHARE_DENY_READ)?"OF_SHARE_DENY_READ":
959 ((mode & 0x70 )==OF_SHARE_DENY_WRITE)?"OF_SHARE_DENY_WRITE":
960 ((mode & 0x70 )==OF_SHARE_EXCLUSIVE)?"OF_SHARE_EXCLUSIVE":"unknown",
961 ((mode & OF_PARSE )==OF_PARSE)?"OF_PARSE ":"",
962 ((mode & OF_DELETE )==OF_DELETE)?"OF_DELETE ":"",
963 ((mode & OF_VERIFY )==OF_VERIFY)?"OF_VERIFY ":"",
964 ((mode & OF_SEARCH )==OF_SEARCH)?"OF_SEARCH ":"",
965 ((mode & OF_CANCEL )==OF_CANCEL)?"OF_CANCEL ":"",
966 ((mode & OF_CREATE )==OF_CREATE)?"OF_CREATE ":"",
967 ((mode & OF_PROMPT )==OF_PROMPT)?"OF_PROMPT ":"",
968 ((mode & OF_EXIST )==OF_EXIST)?"OF_EXIST ":"",
969 ((mode & OF_REOPEN )==OF_REOPEN)?"OF_REOPEN ":""
973 ofs->cBytes = sizeof(OFSTRUCT);
975 if (mode & OF_REOPEN) name = ofs->szPathName;
978 ERR("called with `name' set to NULL ! Please debug.\n");
982 TRACE("%s %04x\n", name, mode );
984 /* the watcom 10.6 IDE relies on a valid path returned in ofs->szPathName
985 Are there any cases where getting the path here is wrong?
986 Uwe Bonnes 1997 Apr 2 */
987 if (!GetFullPathNameA( name, sizeof(ofs->szPathName),
988 ofs->szPathName, NULL )) goto error;
989 FILE_ConvertOFMode( mode, &access, &sharing );
991 /* OF_PARSE simply fills the structure */
995 ofs->fFixedDisk = (GetDriveType16( ofs->szPathName[0]-'A' )
997 TRACE("(%s): OF_PARSE, res = '%s'\n",
998 name, ofs->szPathName );
1002 /* OF_CREATE is completely different from all other options, so
1005 if (mode & OF_CREATE)
1007 if ((handle = CreateFileA( name, GENERIC_READ | GENERIC_WRITE,
1008 sharing, NULL, CREATE_ALWAYS,
1009 FILE_ATTRIBUTE_NORMAL, 0 ))== INVALID_HANDLE_VALUE)
1014 MultiByteToWideChar(CP_ACP, 0, name, -1, buffer, MAX_PATH);
1017 /* If OF_SEARCH is set, ignore the given path */
1019 if ((mode & OF_SEARCH) && !(mode & OF_REOPEN))
1021 /* First try the file name as is */
1022 if (DOSFS_GetFullName( nameW, TRUE, &full_name )) goto found;
1023 /* Now remove the path */
1024 if (nameW[0] && (nameW[1] == ':')) nameW += 2;
1025 if ((p = strrchrW( nameW, '\\' ))) nameW = p + 1;
1026 if ((p = strrchrW( nameW, '/' ))) nameW = p + 1;
1027 if (!nameW[0]) goto not_found;
1030 /* Now look for the file */
1032 if (!DIR_SearchPath( NULL, nameW, NULL, &full_name, win32 )) goto not_found;
1035 TRACE("found %s = %s\n",
1036 full_name.long_name, debugstr_w(full_name.short_name) );
1037 WideCharToMultiByte(CP_ACP, 0, full_name.short_name, -1,
1038 ofs->szPathName, sizeof(ofs->szPathName), NULL, NULL);
1040 if (mode & OF_DELETE)
1042 handle = FILE_CreateFile( full_name.long_name, GENERIC_READ|GENERIC_WRITE, 0,
1043 NULL, OPEN_EXISTING, 0, 0, TRUE,
1044 GetDriveTypeW( full_name.short_name ) );
1045 if (!handle) goto error;
1046 CloseHandle( handle );
1047 if (unlink( full_name.long_name ) == -1) goto not_found;
1048 TRACE("(%s): OF_DELETE return = OK\n", name);
1052 handle = FILE_CreateFile( full_name.long_name, access, sharing,
1053 NULL, OPEN_EXISTING, 0, 0,
1054 DRIVE_GetFlags(full_name.drive) & DRIVE_FAIL_READ_ONLY,
1055 GetDriveTypeW( full_name.short_name ) );
1056 if (!handle) goto not_found;
1058 GetFileTime( handle, NULL, NULL, &filetime );
1059 FileTimeToDosDateTime( &filetime, &filedatetime[0], &filedatetime[1] );
1060 if ((mode & OF_VERIFY) && (mode & OF_REOPEN))
1062 if (ofs->Reserved1 != filedatetime[0] || ofs->Reserved2 != filedatetime[1] )
1064 CloseHandle( handle );
1065 WARN("(%s): OF_VERIFY failed\n", name );
1066 /* FIXME: what error here? */
1067 SetLastError( ERROR_FILE_NOT_FOUND );
1071 ofs->Reserved1 = filedatetime[0];
1072 ofs->Reserved2 = filedatetime[1];
1074 success: /* We get here if the open was successful */
1075 TRACE("(%s): OK, return = %p\n", name, handle );
1078 hFileRet = (HFILE)handle;
1079 if (mode & OF_EXIST) /* Return the handle, but close it first */
1080 CloseHandle( handle );
1084 hFileRet = Win32HandleToDosFileHandle( handle );
1085 if (hFileRet == HFILE_ERROR16) goto error;
1086 if (mode & OF_EXIST) /* Return the handle, but close it first */
1087 _lclose16( hFileRet );
1091 not_found: /* We get here if the file does not exist */
1092 WARN("'%s' not found or sharing violation\n", name );
1093 SetLastError( ERROR_FILE_NOT_FOUND );
1096 error: /* We get here if there was an error opening the file */
1097 ofs->nErrCode = GetLastError();
1098 WARN("(%s): return = HFILE_ERROR error= %d\n",
1099 name,ofs->nErrCode );
1104 /***********************************************************************
1105 * OpenFile (KERNEL.74)
1106 * OpenFileEx (KERNEL.360)
1108 HFILE16 WINAPI OpenFile16( LPCSTR name, OFSTRUCT *ofs, UINT16 mode )
1110 return FILE_DoOpenFile( name, ofs, mode, FALSE );
1114 /***********************************************************************
1115 * OpenFile (KERNEL32.@)
1117 HFILE WINAPI OpenFile( LPCSTR name, OFSTRUCT *ofs, UINT mode )
1119 return FILE_DoOpenFile( name, ofs, mode, TRUE );
1123 /******************************************************************
1124 * FILE_ReadWriteApc (internal)
1128 static void WINAPI FILE_ReadWriteApc(void* apc_user, PIO_STATUS_BLOCK io_status, ULONG len)
1130 LPOVERLAPPED_COMPLETION_ROUTINE cr = (LPOVERLAPPED_COMPLETION_ROUTINE)apc_user;
1132 cr(RtlNtStatusToDosError(io_status->u.Status), len, (LPOVERLAPPED)io_status);
1135 /***********************************************************************
1136 * ReadFileEx (KERNEL32.@)
1138 BOOL WINAPI ReadFileEx(HANDLE hFile, LPVOID buffer, DWORD bytesToRead,
1139 LPOVERLAPPED overlapped,
1140 LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine)
1142 LARGE_INTEGER offset;
1144 PIO_STATUS_BLOCK io_status;
1148 SetLastError(ERROR_INVALID_PARAMETER);
1152 offset.u.LowPart = overlapped->Offset;
1153 offset.u.HighPart = overlapped->OffsetHigh;
1154 io_status = (PIO_STATUS_BLOCK)overlapped;
1155 io_status->u.Status = STATUS_PENDING;
1157 status = NtReadFile(hFile, NULL, FILE_ReadWriteApc, lpCompletionRoutine,
1158 io_status, buffer, bytesToRead, &offset, NULL);
1162 SetLastError( RtlNtStatusToDosError(status) );
1168 /***********************************************************************
1169 * ReadFile (KERNEL32.@)
1171 BOOL WINAPI ReadFile( HANDLE hFile, LPVOID buffer, DWORD bytesToRead,
1172 LPDWORD bytesRead, LPOVERLAPPED overlapped )
1174 LARGE_INTEGER offset;
1175 PLARGE_INTEGER poffset = NULL;
1176 IO_STATUS_BLOCK iosb;
1177 PIO_STATUS_BLOCK io_status = &iosb;
1181 TRACE("%p %p %ld %p %p\n", hFile, buffer, bytesToRead,
1182 bytesRead, overlapped );
1184 if (bytesRead) *bytesRead = 0; /* Do this before anything else */
1185 if (!bytesToRead) return TRUE;
1187 if (IsBadReadPtr(buffer, bytesToRead))
1189 SetLastError(ERROR_WRITE_FAULT); /* FIXME */
1192 if (is_console_handle(hFile))
1193 return ReadConsoleA(hFile, buffer, bytesToRead, bytesRead, NULL);
1195 if (overlapped != NULL)
1197 offset.u.LowPart = overlapped->Offset;
1198 offset.u.HighPart = overlapped->OffsetHigh;
1200 hEvent = overlapped->hEvent;
1201 io_status = (PIO_STATUS_BLOCK)overlapped;
1203 io_status->u.Status = STATUS_PENDING;
1204 io_status->Information = 0;
1206 status = NtReadFile(hFile, hEvent, NULL, NULL, io_status, buffer, bytesToRead, poffset, NULL);
1208 if (status != STATUS_PENDING && bytesRead)
1209 *bytesRead = io_status->Information;
1211 if (status && status != STATUS_END_OF_FILE)
1213 SetLastError( RtlNtStatusToDosError(status) );
1220 /***********************************************************************
1221 * WriteFileEx (KERNEL32.@)
1223 BOOL WINAPI WriteFileEx(HANDLE hFile, LPCVOID buffer, DWORD bytesToWrite,
1224 LPOVERLAPPED overlapped,
1225 LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine)
1227 LARGE_INTEGER offset;
1229 PIO_STATUS_BLOCK io_status;
1231 TRACE("%p %p %ld %p %p\n",
1232 hFile, buffer, bytesToWrite, overlapped, lpCompletionRoutine);
1234 if (overlapped == NULL)
1236 SetLastError(ERROR_INVALID_PARAMETER);
1239 offset.u.LowPart = overlapped->Offset;
1240 offset.u.HighPart = overlapped->OffsetHigh;
1242 io_status = (PIO_STATUS_BLOCK)overlapped;
1243 io_status->u.Status = STATUS_PENDING;
1245 status = NtWriteFile(hFile, NULL, FILE_ReadWriteApc, lpCompletionRoutine,
1246 io_status, buffer, bytesToWrite, &offset, NULL);
1248 if (status) SetLastError( RtlNtStatusToDosError(status) );
1252 /***********************************************************************
1253 * WriteFile (KERNEL32.@)
1255 BOOL WINAPI WriteFile( HANDLE hFile, LPCVOID buffer, DWORD bytesToWrite,
1256 LPDWORD bytesWritten, LPOVERLAPPED overlapped )
1258 HANDLE hEvent = NULL;
1259 LARGE_INTEGER offset;
1260 PLARGE_INTEGER poffset = NULL;
1262 IO_STATUS_BLOCK iosb;
1263 PIO_STATUS_BLOCK piosb = &iosb;
1265 TRACE("%p %p %ld %p %p\n",
1266 hFile, buffer, bytesToWrite, bytesWritten, overlapped );
1268 if (is_console_handle(hFile))
1269 return WriteConsoleA(hFile, buffer, bytesToWrite, bytesWritten, NULL);
1271 if (IsBadReadPtr(buffer, bytesToWrite))
1273 SetLastError(ERROR_READ_FAULT); /* FIXME */
1279 offset.u.LowPart = overlapped->Offset;
1280 offset.u.HighPart = overlapped->OffsetHigh;
1282 hEvent = overlapped->hEvent;
1283 piosb = (PIO_STATUS_BLOCK)overlapped;
1285 piosb->u.Status = STATUS_PENDING;
1286 piosb->Information = 0;
1288 status = NtWriteFile(hFile, hEvent, NULL, NULL, piosb,
1289 buffer, bytesToWrite, poffset, NULL);
1292 SetLastError( RtlNtStatusToDosError(status) );
1295 if (bytesWritten) *bytesWritten = piosb->Information;
1301 /***********************************************************************
1302 * SetFilePointer (KERNEL32.@)
1304 DWORD WINAPI SetFilePointer( HANDLE hFile, LONG distance, LONG *highword,
1307 DWORD ret = INVALID_SET_FILE_POINTER;
1309 TRACE("handle %p offset %ld high %ld origin %ld\n",
1310 hFile, distance, highword?*highword:0, method );
1312 SERVER_START_REQ( set_file_pointer )
1314 req->handle = hFile;
1315 req->low = distance;
1316 req->high = highword ? *highword : (distance >= 0) ? 0 : -1;
1317 /* FIXME: assumes 1:1 mapping between Windows and Unix seek constants */
1318 req->whence = method;
1320 if (!wine_server_call_err( req ))
1322 ret = reply->new_low;
1323 if (highword) *highword = reply->new_high;
1331 /*************************************************************************
1332 * SetHandleCount (KERNEL32.@)
1334 UINT WINAPI SetHandleCount( UINT count )
1336 return min( 256, count );
1340 /**************************************************************************
1341 * SetEndOfFile (KERNEL32.@)
1343 BOOL WINAPI SetEndOfFile( HANDLE hFile )
1346 SERVER_START_REQ( truncate_file )
1348 req->handle = hFile;
1349 ret = !wine_server_call_err( req );
1356 /***********************************************************************
1357 * DeleteFileW (KERNEL32.@)
1359 BOOL WINAPI DeleteFileW( LPCWSTR path )
1361 DOS_FULL_NAME full_name;
1364 TRACE("%s\n", debugstr_w(path) );
1365 if (!path || !*path)
1367 SetLastError(ERROR_PATH_NOT_FOUND);
1370 if (RtlIsDosDeviceName_U( path ))
1372 WARN("cannot remove DOS device %s!\n", debugstr_w(path));
1373 SetLastError( ERROR_FILE_NOT_FOUND );
1377 if (!DOSFS_GetFullName( path, TRUE, &full_name )) return FALSE;
1379 /* check if we are allowed to delete the source */
1380 hFile = FILE_CreateFile( full_name.long_name, GENERIC_READ|GENERIC_WRITE, 0,
1381 NULL, OPEN_EXISTING, 0, 0, TRUE,
1382 GetDriveTypeW( full_name.short_name ) );
1383 if (!hFile) return FALSE;
1385 if (unlink( full_name.long_name ) == -1)
1396 /***********************************************************************
1397 * DeleteFileA (KERNEL32.@)
1399 BOOL WINAPI DeleteFileA( LPCSTR path )
1401 UNICODE_STRING pathW;
1406 SetLastError(ERROR_INVALID_PARAMETER);
1410 if (RtlCreateUnicodeStringFromAsciiz(&pathW, path))
1412 ret = DeleteFileW(pathW.Buffer);
1413 RtlFreeUnicodeString(&pathW);
1416 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1421 /***********************************************************************
1422 * GetFileType (KERNEL32.@)
1424 DWORD WINAPI GetFileType( HANDLE hFile )
1426 DWORD ret = FILE_TYPE_UNKNOWN;
1428 if (is_console_handle( hFile ))
1429 return FILE_TYPE_CHAR;
1431 SERVER_START_REQ( get_file_info )
1433 req->handle = hFile;
1434 if (!wine_server_call_err( req )) ret = reply->type;
1441 /* check if a file name is for an executable file (.exe or .com) */
1442 inline static BOOL is_executable( const char *name )
1444 int len = strlen(name);
1446 if (len < 4) return FALSE;
1447 return (!strcasecmp( name + len - 4, ".exe" ) ||
1448 !strcasecmp( name + len - 4, ".com" ));
1452 /***********************************************************************
1453 * FILE_AddBootRenameEntry
1455 * Adds an entry to the registry that is loaded when windows boots and
1456 * checks if there are some files to be removed or renamed/moved.
1457 * <fn1> has to be valid and <fn2> may be NULL. If both pointers are
1458 * non-NULL then the file is moved, otherwise it is deleted. The
1459 * entry of the registrykey is always appended with two zero
1460 * terminated strings. If <fn2> is NULL then the second entry is
1461 * simply a single 0-byte. Otherwise the second filename goes
1462 * there. The entries are prepended with \??\ before the path and the
1463 * second filename gets also a '!' as the first character if
1464 * MOVEFILE_REPLACE_EXISTING is set. After the final string another
1465 * 0-byte follows to indicate the end of the strings.
1467 * \??\D:\test\file1[0]
1468 * !\??\D:\test\file1_renamed[0]
1469 * \??\D:\Test|delete[0]
1470 * [0] <- file is to be deleted, second string empty
1471 * \??\D:\test\file2[0]
1472 * !\??\D:\test\file2_renamed[0]
1473 * [0] <- indicates end of strings
1476 * \??\D:\test\file1[0]
1477 * !\??\D:\test\file1_renamed[0]
1478 * \??\D:\Test|delete[0]
1479 * [0] <- file is to be deleted, second string empty
1480 * [0] <- indicates end of strings
1483 static BOOL FILE_AddBootRenameEntry( LPCWSTR fn1, LPCWSTR fn2, DWORD flags )
1485 static const WCHAR PreString[] = {'\\','?','?','\\',0};
1486 static const WCHAR ValueName[] = {'P','e','n','d','i','n','g',
1487 'F','i','l','e','R','e','n','a','m','e',
1488 'O','p','e','r','a','t','i','o','n','s',0};
1489 static const WCHAR SessionW[] = {'M','a','c','h','i','n','e','\\',
1490 'S','y','s','t','e','m','\\',
1491 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
1492 'C','o','n','t','r','o','l','\\',
1493 'S','e','s','s','i','o','n',' ','M','a','n','a','g','e','r',0};
1494 static const int info_size = FIELD_OFFSET( KEY_VALUE_PARTIAL_INFORMATION, Data );
1496 OBJECT_ATTRIBUTES attr;
1497 UNICODE_STRING nameW;
1498 KEY_VALUE_PARTIAL_INFORMATION *info;
1501 DWORD len0, len1, len2;
1503 BYTE *Buffer = NULL;
1506 attr.Length = sizeof(attr);
1507 attr.RootDirectory = 0;
1508 attr.ObjectName = &nameW;
1509 attr.Attributes = 0;
1510 attr.SecurityDescriptor = NULL;
1511 attr.SecurityQualityOfService = NULL;
1512 RtlInitUnicodeString( &nameW, SessionW );
1514 if (NtCreateKey( &Reboot, KEY_ALL_ACCESS, &attr, 0, NULL, 0, NULL ) != STATUS_SUCCESS)
1516 WARN("Error creating key for reboot managment [%s]\n",
1517 "SYSTEM\\CurrentControlSet\\Control\\Session Manager");
1521 len0 = strlenW(PreString);
1522 len1 = strlenW(fn1) + len0 + 1;
1525 len2 = strlenW(fn2) + len0 + 1;
1526 if (flags & MOVEFILE_REPLACE_EXISTING) len2++; /* Plus 1 because of the leading '!' */
1528 else len2 = 1; /* minimum is the 0 characters for the empty second string */
1530 /* convert characters to bytes */
1531 len0 *= sizeof(WCHAR);
1532 len1 *= sizeof(WCHAR);
1533 len2 *= sizeof(WCHAR);
1535 RtlInitUnicodeString( &nameW, ValueName );
1537 /* First we check if the key exists and if so how many bytes it already contains. */
1538 if (NtQueryValueKey( Reboot, &nameW, KeyValuePartialInformation,
1539 NULL, 0, &DataSize ) == STATUS_BUFFER_OVERFLOW)
1541 if (!(Buffer = HeapAlloc( GetProcessHeap(), 0, DataSize + len1 + len2 + sizeof(WCHAR) )))
1543 if (NtQueryValueKey( Reboot, &nameW, KeyValuePartialInformation,
1544 Buffer, DataSize, &DataSize )) goto Quit;
1545 info = (KEY_VALUE_PARTIAL_INFORMATION *)Buffer;
1546 if (info->Type != REG_MULTI_SZ) goto Quit;
1547 if (DataSize > sizeof(info)) DataSize -= sizeof(WCHAR); /* remove terminating null (will be added back later) */
1551 DataSize = info_size;
1552 if (!(Buffer = HeapAlloc( GetProcessHeap(), 0, DataSize + len1 + len2 + sizeof(WCHAR) )))
1556 p = (WCHAR *)(Buffer + DataSize);
1557 strcpyW( p, PreString );
1562 p = (WCHAR *)(Buffer + DataSize);
1563 if (flags & MOVEFILE_REPLACE_EXISTING)
1565 strcpyW( p, PreString );
1571 p = (WCHAR *)(Buffer + DataSize);
1573 DataSize += sizeof(WCHAR);
1576 /* add final null */
1577 p = (WCHAR *)(Buffer + DataSize);
1579 DataSize += sizeof(WCHAR);
1581 rc = !NtSetValueKey(Reboot, &nameW, 0, REG_MULTI_SZ, Buffer + info_size, DataSize - info_size);
1584 if (Reboot) NtClose(Reboot);
1585 if (Buffer) HeapFree( GetProcessHeap(), 0, Buffer );
1590 /**************************************************************************
1591 * MoveFileExW (KERNEL32.@)
1593 BOOL WINAPI MoveFileExW( LPCWSTR fn1, LPCWSTR fn2, DWORD flag )
1595 DOS_FULL_NAME full_name1, full_name2;
1597 DWORD attr = INVALID_FILE_ATTRIBUTES;
1599 TRACE("(%s,%s,%04lx)\n", debugstr_w(fn1), debugstr_w(fn2), flag);
1601 /* FIXME: <Gerhard W. Gruber>sparhawk@gmx.at
1602 In case of W9x and lesser this function should return 120 (ERROR_CALL_NOT_IMPLEMENTED)
1603 to be really compatible. Most programs won't have any problems though. In case
1604 you encounter one, this is what you should return here. I don't know what's up
1605 with NT 3.5. Is this function available there or not?
1606 Does anybody really care about 3.5? :)
1609 /* Filename1 has to be always set to a valid path. Filename2 may be NULL
1610 if the source file has to be deleted.
1613 SetLastError(ERROR_INVALID_PARAMETER);
1617 /* This function has to be run through in order to process the name properly.
1618 If the BOOTDELAY flag is set, the file doesn't need to exist though. At least
1619 that is the behaviour on NT 4.0. The operation accepts the filenames as
1620 they are given but it can't reply with a reasonable returncode. Success
1621 means in that case success for entering the values into the registry.
1623 if(!DOSFS_GetFullName( fn1, TRUE, &full_name1 ))
1625 if(!(flag & MOVEFILE_DELAY_UNTIL_REBOOT))
1629 if (fn2) /* !fn2 means delete fn1 */
1631 if (DOSFS_GetFullName( fn2, TRUE, &full_name2 ))
1633 if(!(flag & MOVEFILE_DELAY_UNTIL_REBOOT))
1635 /* target exists, check if we may overwrite */
1636 if (!(flag & MOVEFILE_REPLACE_EXISTING))
1638 SetLastError( ERROR_ALREADY_EXISTS );
1645 if (!DOSFS_GetFullName( fn2, FALSE, &full_name2 ))
1647 if(!(flag & MOVEFILE_DELAY_UNTIL_REBOOT))
1652 /* Source name and target path are valid */
1654 if (flag & MOVEFILE_DELAY_UNTIL_REBOOT)
1656 return FILE_AddBootRenameEntry( fn1, fn2, flag );
1659 attr = GetFileAttributesW( fn1 );
1660 if ( attr == INVALID_FILE_ATTRIBUTES ) return FALSE;
1662 /* check if we are allowed to rename the source */
1663 hFile = FILE_CreateFile( full_name1.long_name, 0, 0,
1664 NULL, OPEN_EXISTING, 0, 0, TRUE,
1665 GetDriveTypeW( full_name1.short_name ) );
1668 if (GetLastError() != ERROR_ACCESS_DENIED) return FALSE;
1669 if ( !(attr & FILE_ATTRIBUTE_DIRECTORY) ) return FALSE;
1670 /* if it's a directory we can continue */
1672 else CloseHandle(hFile);
1674 /* check, if we are allowed to delete the destination,
1675 ** (but the file not being there is fine) */
1676 hFile = FILE_CreateFile( full_name2.long_name, GENERIC_READ|GENERIC_WRITE, 0,
1677 NULL, OPEN_EXISTING, 0, 0, TRUE,
1678 GetDriveTypeW( full_name2.short_name ) );
1679 if(!hFile && GetLastError() != ERROR_FILE_NOT_FOUND) return FALSE;
1682 if (full_name1.drive != full_name2.drive)
1684 if (!(flag & MOVEFILE_COPY_ALLOWED))
1686 SetLastError( ERROR_NOT_SAME_DEVICE );
1689 else if ( attr & FILE_ATTRIBUTE_DIRECTORY )
1691 /* Strange, but that's what Windows returns */
1692 SetLastError ( ERROR_ACCESS_DENIED );
1696 if (rename( full_name1.long_name, full_name2.long_name ) == -1)
1697 /* Try copy/delete unless it's a directory. */
1698 /* FIXME: This does not handle the (unlikely) case that the two locations
1699 are on the same Wine drive, but on different Unix file systems. */
1701 if ( attr & FILE_ATTRIBUTE_DIRECTORY )
1708 if ( ! CopyFileW( fn1, fn2, !(flag & MOVEFILE_REPLACE_EXISTING) ))
1710 if ( ! DeleteFileW ( fn1 ) )
1714 if (is_executable( full_name1.long_name ) != is_executable( full_name2.long_name ))
1717 if (stat( full_name2.long_name, &fstat ) != -1)
1719 if (is_executable( full_name2.long_name ))
1720 /* set executable bit where read bit is set */
1721 fstat.st_mode |= (fstat.st_mode & 0444) >> 2;
1723 fstat.st_mode &= ~0111;
1724 chmod( full_name2.long_name, fstat.st_mode );
1729 else /* fn2 == NULL means delete source */
1731 if (flag & MOVEFILE_DELAY_UNTIL_REBOOT)
1733 if (flag & MOVEFILE_COPY_ALLOWED) {
1734 WARN("Illegal flag\n");
1735 SetLastError( ERROR_GEN_FAILURE );
1739 return FILE_AddBootRenameEntry( fn1, NULL, flag );
1742 if (unlink( full_name1.long_name ) == -1)
1747 return TRUE; /* successfully deleted */
1751 /**************************************************************************
1752 * MoveFileExA (KERNEL32.@)
1754 BOOL WINAPI MoveFileExA( LPCSTR fn1, LPCSTR fn2, DWORD flag )
1756 UNICODE_STRING fn1W, fn2W;
1761 SetLastError(ERROR_INVALID_PARAMETER);
1765 RtlCreateUnicodeStringFromAsciiz(&fn1W, fn1);
1766 if (fn2) RtlCreateUnicodeStringFromAsciiz(&fn2W, fn2);
1767 else fn2W.Buffer = NULL;
1769 ret = MoveFileExW( fn1W.Buffer, fn2W.Buffer, flag );
1771 RtlFreeUnicodeString(&fn1W);
1772 RtlFreeUnicodeString(&fn2W);
1777 /**************************************************************************
1778 * MoveFileW (KERNEL32.@)
1780 * Move file or directory
1782 BOOL WINAPI MoveFileW( LPCWSTR fn1, LPCWSTR fn2 )
1784 return MoveFileExW( fn1, fn2, MOVEFILE_COPY_ALLOWED );
1788 /**************************************************************************
1789 * MoveFileA (KERNEL32.@)
1791 BOOL WINAPI MoveFileA( LPCSTR fn1, LPCSTR fn2 )
1793 return MoveFileExA( fn1, fn2, MOVEFILE_COPY_ALLOWED );
1797 /**************************************************************************
1798 * CopyFileW (KERNEL32.@)
1800 BOOL WINAPI CopyFileW( LPCWSTR source, LPCWSTR dest, BOOL fail_if_exists )
1803 BY_HANDLE_FILE_INFORMATION info;
1808 if (!source || !dest)
1810 SetLastError(ERROR_INVALID_PARAMETER);
1814 TRACE("%s -> %s\n", debugstr_w(source), debugstr_w(dest));
1816 if ((h1 = CreateFileW(source, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE,
1817 NULL, OPEN_EXISTING, 0, 0)) == INVALID_HANDLE_VALUE)
1819 WARN("Unable to open source %s\n", debugstr_w(source));
1823 if (!GetFileInformationByHandle( h1, &info ))
1825 WARN("GetFileInformationByHandle returned error for %s\n", debugstr_w(source));
1830 if ((h2 = CreateFileW( dest, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
1831 fail_if_exists ? CREATE_NEW : CREATE_ALWAYS,
1832 info.dwFileAttributes, h1 )) == INVALID_HANDLE_VALUE)
1834 WARN("Unable to open dest %s\n", debugstr_w(dest));
1839 while (ReadFile( h1, buffer, sizeof(buffer), &count, NULL ) && count)
1845 if (!WriteFile( h2, p, count, &res, NULL ) || !res) goto done;
1858 /**************************************************************************
1859 * CopyFileA (KERNEL32.@)
1861 BOOL WINAPI CopyFileA( LPCSTR source, LPCSTR dest, BOOL fail_if_exists)
1863 UNICODE_STRING sourceW, destW;
1866 if (!source || !dest)
1868 SetLastError(ERROR_INVALID_PARAMETER);
1872 RtlCreateUnicodeStringFromAsciiz(&sourceW, source);
1873 RtlCreateUnicodeStringFromAsciiz(&destW, dest);
1875 ret = CopyFileW(sourceW.Buffer, destW.Buffer, fail_if_exists);
1877 RtlFreeUnicodeString(&sourceW);
1878 RtlFreeUnicodeString(&destW);
1883 /**************************************************************************
1884 * CopyFileExW (KERNEL32.@)
1886 * This implementation ignores most of the extra parameters passed-in into
1887 * the "ex" version of the method and calls the CopyFile method.
1888 * It will have to be fixed eventually.
1890 BOOL WINAPI CopyFileExW(LPCWSTR sourceFilename, LPCWSTR destFilename,
1891 LPPROGRESS_ROUTINE progressRoutine, LPVOID appData,
1892 LPBOOL cancelFlagPointer, DWORD copyFlags)
1895 * Interpret the only flag that CopyFile can interpret.
1897 return CopyFileW(sourceFilename, destFilename, (copyFlags & COPY_FILE_FAIL_IF_EXISTS) != 0);
1901 /**************************************************************************
1902 * CopyFileExA (KERNEL32.@)
1904 BOOL WINAPI CopyFileExA(LPCSTR sourceFilename, LPCSTR destFilename,
1905 LPPROGRESS_ROUTINE progressRoutine, LPVOID appData,
1906 LPBOOL cancelFlagPointer, DWORD copyFlags)
1908 UNICODE_STRING sourceW, destW;
1911 if (!sourceFilename || !destFilename)
1913 SetLastError(ERROR_INVALID_PARAMETER);
1917 RtlCreateUnicodeStringFromAsciiz(&sourceW, sourceFilename);
1918 RtlCreateUnicodeStringFromAsciiz(&destW, destFilename);
1920 ret = CopyFileExW(sourceW.Buffer, destW.Buffer, progressRoutine, appData,
1921 cancelFlagPointer, copyFlags);
1923 RtlFreeUnicodeString(&sourceW);
1924 RtlFreeUnicodeString(&destW);
1929 /***********************************************************************
1930 * SetFileTime (KERNEL32.@)
1932 BOOL WINAPI SetFileTime( HANDLE hFile,
1933 const FILETIME *lpCreationTime,
1934 const FILETIME *lpLastAccessTime,
1935 const FILETIME *lpLastWriteTime )
1938 SERVER_START_REQ( set_file_time )
1940 req->handle = hFile;
1941 if (lpLastAccessTime)
1942 RtlTimeToSecondsSince1970( (PLARGE_INTEGER) lpLastAccessTime, (DWORD *)&req->access_time );
1944 req->access_time = 0; /* FIXME */
1945 if (lpLastWriteTime)
1946 RtlTimeToSecondsSince1970( (PLARGE_INTEGER) lpLastWriteTime, (DWORD *)&req->write_time );
1948 req->write_time = 0; /* FIXME */
1949 ret = !wine_server_call_err( req );
1956 /**************************************************************************
1957 * GetFileAttributesExW (KERNEL32.@)
1959 BOOL WINAPI GetFileAttributesExW(
1960 LPCWSTR lpFileName, GET_FILEEX_INFO_LEVELS fInfoLevelId,
1961 LPVOID lpFileInformation)
1963 DOS_FULL_NAME full_name;
1964 BY_HANDLE_FILE_INFORMATION info;
1966 if (!lpFileName || !lpFileInformation)
1968 SetLastError(ERROR_INVALID_PARAMETER);
1972 if (fInfoLevelId == GetFileExInfoStandard) {
1973 LPWIN32_FILE_ATTRIBUTE_DATA lpFad =
1974 (LPWIN32_FILE_ATTRIBUTE_DATA) lpFileInformation;
1975 if (!DOSFS_GetFullName( lpFileName, TRUE, &full_name )) return FALSE;
1976 if (!FILE_Stat( full_name.long_name, &info, NULL )) return FALSE;
1978 lpFad->dwFileAttributes = info.dwFileAttributes;
1979 lpFad->ftCreationTime = info.ftCreationTime;
1980 lpFad->ftLastAccessTime = info.ftLastAccessTime;
1981 lpFad->ftLastWriteTime = info.ftLastWriteTime;
1982 lpFad->nFileSizeHigh = info.nFileSizeHigh;
1983 lpFad->nFileSizeLow = info.nFileSizeLow;
1986 FIXME("invalid info level %d!\n", fInfoLevelId);
1994 /**************************************************************************
1995 * GetFileAttributesExA (KERNEL32.@)
1997 BOOL WINAPI GetFileAttributesExA(
1998 LPCSTR filename, GET_FILEEX_INFO_LEVELS fInfoLevelId,
1999 LPVOID lpFileInformation)
2001 UNICODE_STRING filenameW;
2004 if (!filename || !lpFileInformation)
2006 SetLastError(ERROR_INVALID_PARAMETER);
2010 if (RtlCreateUnicodeStringFromAsciiz(&filenameW, filename))
2012 ret = GetFileAttributesExW(filenameW.Buffer, fInfoLevelId, lpFileInformation);
2013 RtlFreeUnicodeString(&filenameW);
2016 SetLastError(ERROR_NOT_ENOUGH_MEMORY);