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
,
192 case CREATE_ALWAYS
: disp
= FILE_OVERWRITE_IF
; break;
193 case CREATE_NEW
: disp
= FILE_CREATE
; break;
194 case OPEN_ALWAYS
: disp
= FILE_OPEN_IF
; break;
195 case OPEN_EXISTING
: disp
= FILE_OPEN
; break;
196 case TRUNCATE_EXISTING
: disp
= FILE_OVERWRITE
; break;
198 SetLastError( ERROR_INVALID_PARAMETER
);
203 if (attributes
& FILE_FLAG_BACKUP_SEMANTICS
)
204 options
|= FILE_OPEN_FOR_BACKUP_INTENT
;
205 if (attributes
& FILE_FLAG_DELETE_ON_CLOSE
)
206 options
|= FILE_DELETE_ON_CLOSE
;
207 if (!(attributes
& FILE_FLAG_OVERLAPPED
))
208 options
|= FILE_SYNCHRONOUS_IO_ALERT
;
209 if (attributes
& FILE_FLAG_RANDOM_ACCESS
)
210 options
|= FILE_RANDOM_ACCESS
;
211 attributes
&= FILE_ATTRIBUTE_VALID_FLAGS
;
215 SERVER_START_REQ( create_file
)
217 req
->access
= access
;
218 req
->inherit
= (sa
&& (sa
->nLength
>=sizeof(*sa
)) && sa
->bInheritHandle
);
219 req
->sharing
= sharing
;
221 req
->options
= options
;
222 req
->attrs
= attributes
;
223 req
->removable
= (drive_type
== DRIVE_REMOVABLE
|| drive_type
== DRIVE_CDROM
);
224 wine_server_add_data( req
, filename
, strlen(filename
) );
226 err
= wine_server_call( req
);
231 /* If write access failed, retry without GENERIC_WRITE */
233 if (!ret
&& !fail_read_only
&& (access
& GENERIC_WRITE
))
235 if ((err
== STATUS_MEDIA_WRITE_PROTECTED
) || (err
== STATUS_ACCESS_DENIED
))
237 TRACE("Write access failed for file '%s', trying without "
238 "write access\n", filename
);
239 access
&= ~GENERIC_WRITE
;
246 /* In the case file creation was rejected due to CREATE_NEW flag
247 * was specified and file with that name already exists, correct
248 * last error is ERROR_FILE_EXISTS and not ERROR_ALREADY_EXISTS.
249 * Note: RtlNtStatusToDosError is not the subject to blame here.
251 if (err
== STATUS_OBJECT_NAME_COLLISION
)
252 SetLastError( ERROR_FILE_EXISTS
);
254 SetLastError( RtlNtStatusToDosError(err
) );
257 if (!ret
) WARN("Unable to create file '%s' (GLE %ld)\n", filename
, GetLastError());
263 static HANDLE
FILE_OpenPipe(LPCWSTR name
, DWORD access
, LPSECURITY_ATTRIBUTES sa
)
268 if (name
&& (len
= strlenW(name
)) > MAX_PATH
)
270 SetLastError( ERROR_FILENAME_EXCED_RANGE
);
273 SERVER_START_REQ( open_named_pipe
)
275 req
->access
= access
;
276 req
->inherit
= (sa
&& (sa
->nLength
>=sizeof(*sa
)) && sa
->bInheritHandle
);
278 wine_server_add_data( req
, name
, len
* sizeof(WCHAR
) );
279 wine_server_call_err( req
);
283 TRACE("Returned %p\n",ret
);
287 /*************************************************************************
288 * CreateFileW [KERNEL32.@] Creates or opens a file or other object
290 * Creates or opens an object, and returns a handle that can be used to
291 * access that object.
295 * filename [in] pointer to filename to be accessed
296 * access [in] access mode requested
297 * sharing [in] share mode
298 * sa [in] pointer to security attributes
299 * creation [in] how to create the file
300 * attributes [in] attributes for newly created file
301 * template [in] handle to file with extended attributes to copy
304 * Success: Open handle to specified file
305 * Failure: INVALID_HANDLE_VALUE
308 * Should call SetLastError() on failure.
312 * Doesn't support character devices, template files, or a
313 * lot of the 'attributes' flags yet.
315 HANDLE WINAPI
CreateFileW( LPCWSTR filename
, DWORD access
, DWORD sharing
,
316 LPSECURITY_ATTRIBUTES sa
, DWORD creation
,
317 DWORD attributes
, HANDLE
template )
319 DOS_FULL_NAME full_name
;
322 static const WCHAR bkslashes_with_question_markW
[] = {'\\','\\','?','\\',0};
323 static const WCHAR bkslashes_with_dotW
[] = {'\\','\\','.','\\',0};
324 static const WCHAR bkslashesW
[] = {'\\','\\',0};
325 static const WCHAR coninW
[] = {'C','O','N','I','N','$',0};
326 static const WCHAR conoutW
[] = {'C','O','N','O','U','T','$',0};
330 SetLastError( ERROR_INVALID_PARAMETER
);
331 return INVALID_HANDLE_VALUE
;
333 TRACE("%s %s%s%s%s%s%s%s attributes 0x%lx\n", debugstr_w(filename
),
334 ((access
& GENERIC_READ
)==GENERIC_READ
)?"GENERIC_READ ":"",
335 ((access
& GENERIC_WRITE
)==GENERIC_WRITE
)?"GENERIC_WRITE ":"",
336 (!access
)?"QUERY_ACCESS ":"",
337 ((sharing
& FILE_SHARE_READ
)==FILE_SHARE_READ
)?"FILE_SHARE_READ ":"",
338 ((sharing
& FILE_SHARE_WRITE
)==FILE_SHARE_WRITE
)?"FILE_SHARE_WRITE ":"",
339 ((sharing
& FILE_SHARE_DELETE
)==FILE_SHARE_DELETE
)?"FILE_SHARE_DELETE ":"",
340 (creation
==CREATE_NEW
)?"CREATE_NEW":
341 (creation
==CREATE_ALWAYS
)?"CREATE_ALWAYS ":
342 (creation
==OPEN_EXISTING
)?"OPEN_EXISTING ":
343 (creation
==OPEN_ALWAYS
)?"OPEN_ALWAYS ":
344 (creation
==TRUNCATE_EXISTING
)?"TRUNCATE_EXISTING ":"", attributes
);
346 /* Open a console for CONIN$ or CONOUT$ */
347 if (!strcmpiW(filename
, coninW
) || !strcmpiW(filename
, conoutW
))
349 ret
= OpenConsoleW(filename
, access
, (sa
&& sa
->bInheritHandle
), creation
);
353 /* If the name starts with '\\?\', ignore the first 4 chars. */
354 if (!strncmpW(filename
, bkslashes_with_question_markW
, 4))
356 static const WCHAR uncW
[] = {'U','N','C','\\',0};
358 if (!strncmpiW(filename
, uncW
, 4))
360 FIXME("UNC name (%s) not supported.\n", debugstr_w(filename
) );
361 SetLastError( ERROR_PATH_NOT_FOUND
);
362 return INVALID_HANDLE_VALUE
;
366 if (!strncmpW(filename
, bkslashes_with_dotW
, 4))
368 static const WCHAR pipeW
[] = {'P','I','P','E','\\',0};
369 if(!strncmpiW(filename
+ 4, pipeW
, 5))
371 TRACE("Opening a pipe: %s\n", debugstr_w(filename
));
372 ret
= FILE_OpenPipe( filename
, access
, sa
);
375 else if (isalphaW(filename
[4]) && filename
[5] == ':' && filename
[6] == '\0')
377 const char *device
= DRIVE_GetDevice( toupperW(filename
[4]) - 'A' );
380 ret
= FILE_CreateFile( device
, access
, sharing
, sa
, creation
,
381 attributes
, template, TRUE
, DRIVE_FIXED
);
385 SetLastError( ERROR_ACCESS_DENIED
);
386 ret
= INVALID_HANDLE_VALUE
;
390 else if ((dosdev
= RtlIsDosDeviceName_U( filename
+ 4 )))
392 dosdev
+= MAKELONG( 0, 4*sizeof(WCHAR
) ); /* adjust position to start of filename */
396 ret
= VXD_Open( filename
+4, access
, sa
);
400 else dosdev
= RtlIsDosDeviceName_U( filename
);
404 static const WCHAR conW
[] = {'C','O','N',0};
407 memcpy( dev
, filename
+ HIWORD(dosdev
)/sizeof(WCHAR
), LOWORD(dosdev
) );
408 dev
[LOWORD(dosdev
)/sizeof(WCHAR
)] = 0;
410 TRACE("opening device %s\n", debugstr_w(dev
) );
412 if (!strcmpiW( dev
, conW
))
414 switch (access
& (GENERIC_READ
|GENERIC_WRITE
))
417 ret
= OpenConsoleW(coninW
, access
, (sa
&& sa
->bInheritHandle
), creation
);
420 ret
= OpenConsoleW(conoutW
, access
, (sa
&& sa
->bInheritHandle
), creation
);
423 FIXME("can't open CON read/write\n");
424 SetLastError( ERROR_FILE_NOT_FOUND
);
425 return INVALID_HANDLE_VALUE
;
429 ret
= VOLUME_OpenDevice( dev
, access
, sharing
, sa
, attributes
);
433 /* If the name still starts with '\\', it's a UNC name. */
434 if (!strncmpW(filename
, bkslashesW
, 2))
436 ret
= SMB_CreateFileW(filename
, access
, sharing
, sa
, creation
, attributes
, template );
440 /* If the name contains a DOS wild card (* or ?), do no create a file */
441 if(strchrW(filename
, '*') || strchrW(filename
, '?'))
443 SetLastError(ERROR_BAD_PATHNAME
);
444 return INVALID_HANDLE_VALUE
;
447 /* check for filename, don't check for last entry if creating */
448 if (!DOSFS_GetFullName( filename
,
449 (creation
== OPEN_EXISTING
) ||
450 (creation
== TRUNCATE_EXISTING
),
452 WARN("Unable to get full filename from %s (GLE %ld)\n",
453 debugstr_w(filename
), GetLastError());
454 return INVALID_HANDLE_VALUE
;
457 ret
= FILE_CreateFile( full_name
.long_name
, access
, sharing
,
458 sa
, creation
, attributes
, template,
459 DRIVE_GetFlags(full_name
.drive
) & DRIVE_FAIL_READ_ONLY
,
460 GetDriveTypeW( full_name
.short_name
) );
462 if (!ret
) ret
= INVALID_HANDLE_VALUE
;
463 TRACE("returning %p\n", ret
);
469 /*************************************************************************
470 * CreateFileA (KERNEL32.@)
472 HANDLE WINAPI
CreateFileA( LPCSTR filename
, DWORD access
, DWORD sharing
,
473 LPSECURITY_ATTRIBUTES sa
, DWORD creation
,
474 DWORD attributes
, HANDLE
template)
476 UNICODE_STRING filenameW
;
477 HANDLE ret
= INVALID_HANDLE_VALUE
;
481 SetLastError( ERROR_INVALID_PARAMETER
);
482 return INVALID_HANDLE_VALUE
;
485 if (RtlCreateUnicodeStringFromAsciiz(&filenameW
, filename
))
487 ret
= CreateFileW(filenameW
.Buffer
, access
, sharing
, sa
, creation
,
488 attributes
, template);
489 RtlFreeUnicodeString(&filenameW
);
492 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
497 /***********************************************************************
500 * Fill a file information from a struct stat.
502 static void FILE_FillInfo( struct stat
*st
, BY_HANDLE_FILE_INFORMATION
*info
)
504 if (S_ISDIR(st
->st_mode
))
505 info
->dwFileAttributes
= FILE_ATTRIBUTE_DIRECTORY
;
507 info
->dwFileAttributes
= FILE_ATTRIBUTE_ARCHIVE
;
508 if (!(st
->st_mode
& S_IWUSR
))
509 info
->dwFileAttributes
|= FILE_ATTRIBUTE_READONLY
;
511 RtlSecondsSince1970ToTime( st
->st_mtime
, (LARGE_INTEGER
*)&info
->ftCreationTime
);
512 RtlSecondsSince1970ToTime( st
->st_mtime
, (LARGE_INTEGER
*)&info
->ftLastWriteTime
);
513 RtlSecondsSince1970ToTime( st
->st_atime
, (LARGE_INTEGER
*)&info
->ftLastAccessTime
);
515 info
->dwVolumeSerialNumber
= 0; /* FIXME */
516 info
->nFileSizeHigh
= 0;
517 info
->nFileSizeLow
= 0;
518 if (!S_ISDIR(st
->st_mode
)) {
519 info
->nFileSizeHigh
= st
->st_size
>> 32;
520 info
->nFileSizeLow
= st
->st_size
& 0xffffffff;
522 info
->nNumberOfLinks
= st
->st_nlink
;
523 info
->nFileIndexHigh
= 0;
524 info
->nFileIndexLow
= st
->st_ino
;
528 /***********************************************************************
529 * get_show_dot_files_option
531 static BOOL
get_show_dot_files_option(void)
533 static const WCHAR WineW
[] = {'M','a','c','h','i','n','e','\\',
534 'S','o','f','t','w','a','r','e','\\',
535 'W','i','n','e','\\','W','i','n','e','\\',
536 'C','o','n','f','i','g','\\','W','i','n','e',0};
537 static const WCHAR ShowDotFilesW
[] = {'S','h','o','w','D','o','t','F','i','l','e','s',0};
542 OBJECT_ATTRIBUTES attr
;
543 UNICODE_STRING nameW
;
546 attr
.Length
= sizeof(attr
);
547 attr
.RootDirectory
= 0;
548 attr
.ObjectName
= &nameW
;
550 attr
.SecurityDescriptor
= NULL
;
551 attr
.SecurityQualityOfService
= NULL
;
552 RtlInitUnicodeString( &nameW
, WineW
);
554 if (!NtOpenKey( &hkey
, KEY_ALL_ACCESS
, &attr
))
556 RtlInitUnicodeString( &nameW
, ShowDotFilesW
);
557 if (!NtQueryValueKey( hkey
, &nameW
, KeyValuePartialInformation
, tmp
, sizeof(tmp
), &dummy
))
559 WCHAR
*str
= (WCHAR
*)((KEY_VALUE_PARTIAL_INFORMATION
*)tmp
)->Data
;
560 ret
= IS_OPTION_TRUE( str
[0] );
568 /***********************************************************************
571 * Stat a Unix path name. Return TRUE if OK.
573 BOOL
FILE_Stat( LPCSTR unixName
, BY_HANDLE_FILE_INFORMATION
*info
, BOOL
*is_symlink_ptr
)
579 if (lstat( unixName
, &st
) == -1)
584 is_symlink
= S_ISLNK(st
.st_mode
);
587 /* do a "real" stat to find out
588 about the type of the symlink destination */
589 if (stat( unixName
, &st
) == -1)
596 /* fill in the information we gathered so far */
597 FILE_FillInfo( &st
, info
);
599 /* and now see if this is a hidden file, based on the name */
600 p
= strrchr( unixName
, '/');
601 p
= p
? p
+ 1 : unixName
;
602 if (*p
== '.' && *(p
+1) && (*(p
+1) != '.' || *(p
+2)))
604 static int show_dot_files
= -1;
605 if (show_dot_files
== -1)
606 show_dot_files
= get_show_dot_files_option();
608 info
->dwFileAttributes
|= FILE_ATTRIBUTE_HIDDEN
;
610 if (is_symlink_ptr
) *is_symlink_ptr
= is_symlink
;
615 /***********************************************************************
616 * GetFileInformationByHandle (KERNEL32.@)
618 DWORD WINAPI
GetFileInformationByHandle( HANDLE hFile
,
619 BY_HANDLE_FILE_INFORMATION
*info
)
624 TRACE("%p\n", hFile
);
626 SERVER_START_REQ( get_file_info
)
629 if ((ret
= !wine_server_call_err( req
)))
631 /* FIXME: which file types are supported ?
632 * Serial ports (FILE_TYPE_CHAR) are not,
633 * and MSDN also says that pipes are not supported.
634 * FILE_TYPE_REMOTE seems to be supported according to
635 * MSDN q234741.txt */
636 if ((reply
->type
== FILE_TYPE_DISK
) || (reply
->type
== FILE_TYPE_REMOTE
))
638 RtlSecondsSince1970ToTime( reply
->write_time
, (LARGE_INTEGER
*)&info
->ftCreationTime
);
639 RtlSecondsSince1970ToTime( reply
->write_time
, (LARGE_INTEGER
*)&info
->ftLastWriteTime
);
640 RtlSecondsSince1970ToTime( reply
->access_time
, (LARGE_INTEGER
*)&info
->ftLastAccessTime
);
641 info
->dwFileAttributes
= reply
->attr
;
642 info
->dwVolumeSerialNumber
= reply
->serial
;
643 info
->nFileSizeHigh
= reply
->size_high
;
644 info
->nFileSizeLow
= reply
->size_low
;
645 info
->nNumberOfLinks
= reply
->links
;
646 info
->nFileIndexHigh
= reply
->index_high
;
647 info
->nFileIndexLow
= reply
->index_low
;
651 SetLastError(ERROR_NOT_SUPPORTED
);
661 /**************************************************************************
662 * GetFileAttributesW (KERNEL32.@)
664 DWORD WINAPI
GetFileAttributesW( LPCWSTR name
)
666 DOS_FULL_NAME full_name
;
667 BY_HANDLE_FILE_INFORMATION info
;
671 SetLastError( ERROR_INVALID_PARAMETER
);
672 return INVALID_FILE_ATTRIBUTES
;
674 if (!DOSFS_GetFullName( name
, TRUE
, &full_name
) )
675 return INVALID_FILE_ATTRIBUTES
;
676 if (!FILE_Stat( full_name
.long_name
, &info
, NULL
))
677 return INVALID_FILE_ATTRIBUTES
;
678 return info
.dwFileAttributes
;
682 /**************************************************************************
683 * GetFileAttributesA (KERNEL32.@)
685 DWORD WINAPI
GetFileAttributesA( LPCSTR name
)
687 UNICODE_STRING nameW
;
688 DWORD ret
= INVALID_FILE_ATTRIBUTES
;
692 SetLastError( ERROR_INVALID_PARAMETER
);
693 return INVALID_FILE_ATTRIBUTES
;
696 if (RtlCreateUnicodeStringFromAsciiz(&nameW
, name
))
698 ret
= GetFileAttributesW(nameW
.Buffer
);
699 RtlFreeUnicodeString(&nameW
);
702 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
707 /**************************************************************************
708 * SetFileAttributesW (KERNEL32.@)
710 BOOL WINAPI
SetFileAttributesW(LPCWSTR lpFileName
, DWORD attributes
)
713 DOS_FULL_NAME full_name
;
717 SetLastError( ERROR_INVALID_PARAMETER
);
721 TRACE("(%s,%lx)\n", debugstr_w(lpFileName
), attributes
);
723 if (!DOSFS_GetFullName( lpFileName
, TRUE
, &full_name
))
726 if(stat(full_name
.long_name
,&buf
)==-1)
731 if (attributes
& FILE_ATTRIBUTE_READONLY
)
733 if(S_ISDIR(buf
.st_mode
))
735 WARN("FILE_ATTRIBUTE_READONLY ignored for directory.\n");
737 buf
.st_mode
&= ~0222; /* octal!, clear write permission bits */
738 attributes
&= ~FILE_ATTRIBUTE_READONLY
;
742 /* add write permission */
743 buf
.st_mode
|= (0600 | ((buf
.st_mode
& 044) >> 1)) & (~FILE_umask
);
745 if (attributes
& FILE_ATTRIBUTE_DIRECTORY
)
747 if (!S_ISDIR(buf
.st_mode
))
748 FIXME("SetFileAttributes expected the file %s to be a directory\n",
749 debugstr_w(lpFileName
));
750 attributes
&= ~FILE_ATTRIBUTE_DIRECTORY
;
752 attributes
&= ~(FILE_ATTRIBUTE_NORMAL
|FILE_ATTRIBUTE_ARCHIVE
|FILE_ATTRIBUTE_HIDDEN
|
753 FILE_ATTRIBUTE_SYSTEM
|FILE_ATTRIBUTE_TEMPORARY
);
755 FIXME("(%s):%lx attribute(s) not implemented.\n", debugstr_w(lpFileName
), attributes
);
756 if (-1==chmod(full_name
.long_name
,buf
.st_mode
))
758 if (GetDriveTypeW(lpFileName
) == DRIVE_CDROM
)
760 SetLastError( ERROR_ACCESS_DENIED
);
765 * FIXME: We don't return FALSE here because of differences between
766 * Linux and Windows privileges. Under Linux only the owner of
767 * the file is allowed to change file attributes. Under Windows,
768 * applications expect that if you can write to a file, you can also
769 * change its attributes (see GENERIC_WRITE). We could try to be
770 * clever here but that would break multi-user installations where
771 * users share read-only DLLs. This is because some installers like
772 * to change attributes of already installed DLLs.
774 FIXME("Couldn't set file attributes for existing file \"%s\".\n"
775 "Check permissions or set VFAT \"quiet\" mount flag\n", full_name
.long_name
);
781 /**************************************************************************
782 * SetFileAttributesA (KERNEL32.@)
784 BOOL WINAPI
SetFileAttributesA(LPCSTR lpFileName
, DWORD attributes
)
786 UNICODE_STRING filenameW
;
791 SetLastError( ERROR_INVALID_PARAMETER
);
795 if (RtlCreateUnicodeStringFromAsciiz(&filenameW
, lpFileName
))
797 ret
= SetFileAttributesW(filenameW
.Buffer
, attributes
);
798 RtlFreeUnicodeString(&filenameW
);
801 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
806 /******************************************************************************
807 * GetCompressedFileSizeA [KERNEL32.@]
809 DWORD WINAPI
GetCompressedFileSizeA(
811 LPDWORD lpFileSizeHigh
)
813 UNICODE_STRING filenameW
;
816 if (RtlCreateUnicodeStringFromAsciiz(&filenameW
, lpFileName
))
818 ret
= GetCompressedFileSizeW(filenameW
.Buffer
, lpFileSizeHigh
);
819 RtlFreeUnicodeString(&filenameW
);
823 ret
= INVALID_FILE_SIZE
;
824 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
830 /******************************************************************************
831 * GetCompressedFileSizeW [KERNEL32.@]
834 * Success: Low-order doubleword of number of bytes
835 * Failure: INVALID_FILE_SIZE
837 DWORD WINAPI
GetCompressedFileSizeW(
838 LPCWSTR lpFileName
, /* [in] Pointer to name of file */
839 LPDWORD lpFileSizeHigh
) /* [out] Receives high-order doubleword of size */
841 DOS_FULL_NAME full_name
;
845 TRACE("(%s,%p)\n",debugstr_w(lpFileName
),lpFileSizeHigh
);
847 if (!DOSFS_GetFullName( lpFileName
, TRUE
, &full_name
)) return INVALID_FILE_SIZE
;
848 if (stat(full_name
.long_name
, &st
) != 0)
851 return INVALID_FILE_SIZE
;
853 #if HAVE_STRUCT_STAT_ST_BLOCKS
854 /* blocks are 512 bytes long */
855 if (lpFileSizeHigh
) *lpFileSizeHigh
= (st
.st_blocks
>> 23);
856 low
= (DWORD
)(st
.st_blocks
<< 9);
858 if (lpFileSizeHigh
) *lpFileSizeHigh
= (st
.st_size
>> 32);
859 low
= (DWORD
)st
.st_size
;
865 /***********************************************************************
866 * GetFileTime (KERNEL32.@)
868 BOOL WINAPI
GetFileTime( HANDLE hFile
, FILETIME
*lpCreationTime
,
869 FILETIME
*lpLastAccessTime
,
870 FILETIME
*lpLastWriteTime
)
872 BY_HANDLE_FILE_INFORMATION info
;
873 if (!GetFileInformationByHandle( hFile
, &info
)) return FALSE
;
874 if (lpCreationTime
) *lpCreationTime
= info
.ftCreationTime
;
875 if (lpLastAccessTime
) *lpLastAccessTime
= info
.ftLastAccessTime
;
876 if (lpLastWriteTime
) *lpLastWriteTime
= info
.ftLastWriteTime
;
881 /***********************************************************************
882 * GetTempFileNameA (KERNEL32.@)
884 UINT WINAPI
GetTempFileNameA( LPCSTR path
, LPCSTR prefix
, UINT unique
,
887 UNICODE_STRING pathW
, prefixW
;
888 WCHAR bufferW
[MAX_PATH
];
891 if ( !path
|| !prefix
|| !buffer
)
893 SetLastError( ERROR_INVALID_PARAMETER
);
897 RtlCreateUnicodeStringFromAsciiz(&pathW
, path
);
898 RtlCreateUnicodeStringFromAsciiz(&prefixW
, prefix
);
900 ret
= GetTempFileNameW(pathW
.Buffer
, prefixW
.Buffer
, unique
, bufferW
);
902 WideCharToMultiByte(CP_ACP
, 0, bufferW
, -1, buffer
, MAX_PATH
, NULL
, NULL
);
904 RtlFreeUnicodeString(&pathW
);
905 RtlFreeUnicodeString(&prefixW
);
909 /***********************************************************************
910 * GetTempFileNameW (KERNEL32.@)
912 UINT WINAPI
GetTempFileNameW( LPCWSTR path
, LPCWSTR prefix
, UINT unique
,
915 static const WCHAR formatW
[] = {'%','x','.','t','m','p',0};
917 DOS_FULL_NAME full_name
;
921 if ( !path
|| !prefix
|| !buffer
)
923 SetLastError( ERROR_INVALID_PARAMETER
);
927 strcpyW( buffer
, path
);
928 p
= buffer
+ strlenW(buffer
);
930 /* add a \, if there isn't one */
931 if ((p
== buffer
) || (p
[-1] != '\\')) *p
++ = '\\';
933 for (i
= 3; (i
> 0) && (*prefix
); i
--) *p
++ = *prefix
++;
937 if (unique
) sprintfW( p
, formatW
, unique
);
940 /* get a "random" unique number and try to create the file */
942 UINT num
= GetTickCount() & 0xffff;
948 sprintfW( p
, formatW
, unique
);
949 handle
= CreateFileW( buffer
, GENERIC_WRITE
, 0, NULL
,
950 CREATE_NEW
, FILE_ATTRIBUTE_NORMAL
, 0 );
951 if (handle
!= INVALID_HANDLE_VALUE
)
952 { /* We created it */
953 TRACE("created %s\n", debugstr_w(buffer
) );
954 CloseHandle( handle
);
957 if (GetLastError() != ERROR_FILE_EXISTS
&&
958 GetLastError() != ERROR_SHARING_VIOLATION
)
959 break; /* No need to go on */
960 if (!(++unique
& 0xffff)) unique
= 1;
961 } while (unique
!= num
);
964 /* Get the full path name */
966 if (DOSFS_GetFullName( buffer
, FALSE
, &full_name
))
969 /* Check if we have write access in the directory */
970 if ((slash
= strrchr( full_name
.long_name
, '/' ))) *slash
= '\0';
971 if (access( full_name
.long_name
, W_OK
) == -1)
972 WARN("returns %s, which doesn't seem to be writeable.\n",
973 debugstr_w(buffer
) );
975 TRACE("returning %s\n", debugstr_w(buffer
) );
980 /******************************************************************
981 * FILE_ReadWriteApc (internal)
985 static void WINAPI
FILE_ReadWriteApc(void* apc_user
, PIO_STATUS_BLOCK io_status
, ULONG len
)
987 LPOVERLAPPED_COMPLETION_ROUTINE cr
= (LPOVERLAPPED_COMPLETION_ROUTINE
)apc_user
;
989 cr(RtlNtStatusToDosError(io_status
->u
.Status
), len
, (LPOVERLAPPED
)io_status
);
992 /***********************************************************************
993 * ReadFileEx (KERNEL32.@)
995 BOOL WINAPI
ReadFileEx(HANDLE hFile
, LPVOID buffer
, DWORD bytesToRead
,
996 LPOVERLAPPED overlapped
,
997 LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine
)
999 LARGE_INTEGER offset
;
1001 PIO_STATUS_BLOCK io_status
;
1005 SetLastError(ERROR_INVALID_PARAMETER
);
1009 offset
.u
.LowPart
= overlapped
->Offset
;
1010 offset
.u
.HighPart
= overlapped
->OffsetHigh
;
1011 io_status
= (PIO_STATUS_BLOCK
)overlapped
;
1012 io_status
->u
.Status
= STATUS_PENDING
;
1014 status
= NtReadFile(hFile
, NULL
, FILE_ReadWriteApc
, lpCompletionRoutine
,
1015 io_status
, buffer
, bytesToRead
, &offset
, NULL
);
1019 SetLastError( RtlNtStatusToDosError(status
) );
1025 /***********************************************************************
1026 * ReadFile (KERNEL32.@)
1028 BOOL WINAPI
ReadFile( HANDLE hFile
, LPVOID buffer
, DWORD bytesToRead
,
1029 LPDWORD bytesRead
, LPOVERLAPPED overlapped
)
1031 LARGE_INTEGER offset
;
1032 PLARGE_INTEGER poffset
= NULL
;
1033 IO_STATUS_BLOCK iosb
;
1034 PIO_STATUS_BLOCK io_status
= &iosb
;
1038 TRACE("%p %p %ld %p %p\n", hFile
, buffer
, bytesToRead
,
1039 bytesRead
, overlapped
);
1041 if (bytesRead
) *bytesRead
= 0; /* Do this before anything else */
1042 if (!bytesToRead
) return TRUE
;
1044 if (IsBadReadPtr(buffer
, bytesToRead
))
1046 SetLastError(ERROR_WRITE_FAULT
); /* FIXME */
1049 if (is_console_handle(hFile
))
1050 return ReadConsoleA(hFile
, buffer
, bytesToRead
, bytesRead
, NULL
);
1052 if (overlapped
!= NULL
)
1054 offset
.u
.LowPart
= overlapped
->Offset
;
1055 offset
.u
.HighPart
= overlapped
->OffsetHigh
;
1057 hEvent
= overlapped
->hEvent
;
1058 io_status
= (PIO_STATUS_BLOCK
)overlapped
;
1060 io_status
->u
.Status
= STATUS_PENDING
;
1061 io_status
->Information
= 0;
1063 status
= NtReadFile(hFile
, hEvent
, NULL
, NULL
, io_status
, buffer
, bytesToRead
, poffset
, NULL
);
1065 if (status
!= STATUS_PENDING
&& bytesRead
)
1066 *bytesRead
= io_status
->Information
;
1068 if (status
&& status
!= STATUS_END_OF_FILE
)
1070 SetLastError( RtlNtStatusToDosError(status
) );
1077 /***********************************************************************
1078 * WriteFileEx (KERNEL32.@)
1080 BOOL WINAPI
WriteFileEx(HANDLE hFile
, LPCVOID buffer
, DWORD bytesToWrite
,
1081 LPOVERLAPPED overlapped
,
1082 LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine
)
1084 LARGE_INTEGER offset
;
1086 PIO_STATUS_BLOCK io_status
;
1088 TRACE("%p %p %ld %p %p\n",
1089 hFile
, buffer
, bytesToWrite
, overlapped
, lpCompletionRoutine
);
1091 if (overlapped
== NULL
)
1093 SetLastError(ERROR_INVALID_PARAMETER
);
1096 offset
.u
.LowPart
= overlapped
->Offset
;
1097 offset
.u
.HighPart
= overlapped
->OffsetHigh
;
1099 io_status
= (PIO_STATUS_BLOCK
)overlapped
;
1100 io_status
->u
.Status
= STATUS_PENDING
;
1102 status
= NtWriteFile(hFile
, NULL
, FILE_ReadWriteApc
, lpCompletionRoutine
,
1103 io_status
, buffer
, bytesToWrite
, &offset
, NULL
);
1105 if (status
) SetLastError( RtlNtStatusToDosError(status
) );
1109 /***********************************************************************
1110 * WriteFile (KERNEL32.@)
1112 BOOL WINAPI
WriteFile( HANDLE hFile
, LPCVOID buffer
, DWORD bytesToWrite
,
1113 LPDWORD bytesWritten
, LPOVERLAPPED overlapped
)
1115 HANDLE hEvent
= NULL
;
1116 LARGE_INTEGER offset
;
1117 PLARGE_INTEGER poffset
= NULL
;
1119 IO_STATUS_BLOCK iosb
;
1120 PIO_STATUS_BLOCK piosb
= &iosb
;
1122 TRACE("%p %p %ld %p %p\n",
1123 hFile
, buffer
, bytesToWrite
, bytesWritten
, overlapped
);
1125 if (is_console_handle(hFile
))
1126 return WriteConsoleA(hFile
, buffer
, bytesToWrite
, bytesWritten
, NULL
);
1128 if (IsBadReadPtr(buffer
, bytesToWrite
))
1130 SetLastError(ERROR_READ_FAULT
); /* FIXME */
1136 offset
.u
.LowPart
= overlapped
->Offset
;
1137 offset
.u
.HighPart
= overlapped
->OffsetHigh
;
1139 hEvent
= overlapped
->hEvent
;
1140 piosb
= (PIO_STATUS_BLOCK
)overlapped
;
1142 piosb
->u
.Status
= STATUS_PENDING
;
1143 piosb
->Information
= 0;
1145 status
= NtWriteFile(hFile
, hEvent
, NULL
, NULL
, piosb
,
1146 buffer
, bytesToWrite
, poffset
, NULL
);
1149 SetLastError( RtlNtStatusToDosError(status
) );
1152 if (bytesWritten
) *bytesWritten
= piosb
->Information
;
1158 /***********************************************************************
1159 * SetFilePointer (KERNEL32.@)
1161 DWORD WINAPI
SetFilePointer( HANDLE hFile
, LONG distance
, LONG
*highword
,
1164 DWORD ret
= INVALID_SET_FILE_POINTER
;
1166 TRACE("handle %p offset %ld high %ld origin %ld\n",
1167 hFile
, distance
, highword
?*highword
:0, method
);
1169 SERVER_START_REQ( set_file_pointer
)
1171 req
->handle
= hFile
;
1172 req
->low
= distance
;
1173 req
->high
= highword
? *highword
: (distance
>= 0) ? 0 : -1;
1174 /* FIXME: assumes 1:1 mapping between Windows and Unix seek constants */
1175 req
->whence
= method
;
1177 if (!wine_server_call_err( req
))
1179 ret
= reply
->new_low
;
1180 if (highword
) *highword
= reply
->new_high
;
1188 /*************************************************************************
1189 * SetHandleCount (KERNEL32.@)
1191 UINT WINAPI
SetHandleCount( UINT count
)
1193 return min( 256, count
);
1197 /**************************************************************************
1198 * SetEndOfFile (KERNEL32.@)
1200 BOOL WINAPI
SetEndOfFile( HANDLE hFile
)
1203 SERVER_START_REQ( truncate_file
)
1205 req
->handle
= hFile
;
1206 ret
= !wine_server_call_err( req
);
1213 /***********************************************************************
1214 * DeleteFileW (KERNEL32.@)
1216 BOOL WINAPI
DeleteFileW( LPCWSTR path
)
1218 DOS_FULL_NAME full_name
;
1221 TRACE("%s\n", debugstr_w(path
) );
1222 if (!path
|| !*path
)
1224 SetLastError(ERROR_PATH_NOT_FOUND
);
1227 if (RtlIsDosDeviceName_U( path
))
1229 WARN("cannot remove DOS device %s!\n", debugstr_w(path
));
1230 SetLastError( ERROR_FILE_NOT_FOUND
);
1234 if (!DOSFS_GetFullName( path
, TRUE
, &full_name
)) return FALSE
;
1236 /* check if we are allowed to delete the source */
1237 hFile
= FILE_CreateFile( full_name
.long_name
, GENERIC_READ
|GENERIC_WRITE
, 0,
1238 NULL
, OPEN_EXISTING
, 0, 0, TRUE
,
1239 GetDriveTypeW( full_name
.short_name
) );
1240 if (!hFile
) return FALSE
;
1242 if (unlink( full_name
.long_name
) == -1)
1253 /***********************************************************************
1254 * DeleteFileA (KERNEL32.@)
1256 BOOL WINAPI
DeleteFileA( LPCSTR path
)
1258 UNICODE_STRING pathW
;
1263 SetLastError(ERROR_INVALID_PARAMETER
);
1267 if (RtlCreateUnicodeStringFromAsciiz(&pathW
, path
))
1269 ret
= DeleteFileW(pathW
.Buffer
);
1270 RtlFreeUnicodeString(&pathW
);
1273 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
1278 /***********************************************************************
1279 * GetFileType (KERNEL32.@)
1281 DWORD WINAPI
GetFileType( HANDLE hFile
)
1283 DWORD ret
= FILE_TYPE_UNKNOWN
;
1285 if (is_console_handle( hFile
))
1286 return FILE_TYPE_CHAR
;
1288 SERVER_START_REQ( get_file_info
)
1290 req
->handle
= hFile
;
1291 if (!wine_server_call_err( req
)) ret
= reply
->type
;
1298 /* check if a file name is for an executable file (.exe or .com) */
1299 inline static BOOL
is_executable( const char *name
)
1301 int len
= strlen(name
);
1303 if (len
< 4) return FALSE
;
1304 return (!strcasecmp( name
+ len
- 4, ".exe" ) ||
1305 !strcasecmp( name
+ len
- 4, ".com" ));
1309 /***********************************************************************
1310 * FILE_AddBootRenameEntry
1312 * Adds an entry to the registry that is loaded when windows boots and
1313 * checks if there are some files to be removed or renamed/moved.
1314 * <fn1> has to be valid and <fn2> may be NULL. If both pointers are
1315 * non-NULL then the file is moved, otherwise it is deleted. The
1316 * entry of the registrykey is always appended with two zero
1317 * terminated strings. If <fn2> is NULL then the second entry is
1318 * simply a single 0-byte. Otherwise the second filename goes
1319 * there. The entries are prepended with \??\ before the path and the
1320 * second filename gets also a '!' as the first character if
1321 * MOVEFILE_REPLACE_EXISTING is set. After the final string another
1322 * 0-byte follows to indicate the end of the strings.
1324 * \??\D:\test\file1[0]
1325 * !\??\D:\test\file1_renamed[0]
1326 * \??\D:\Test|delete[0]
1327 * [0] <- file is to be deleted, second string empty
1328 * \??\D:\test\file2[0]
1329 * !\??\D:\test\file2_renamed[0]
1330 * [0] <- indicates end of strings
1333 * \??\D:\test\file1[0]
1334 * !\??\D:\test\file1_renamed[0]
1335 * \??\D:\Test|delete[0]
1336 * [0] <- file is to be deleted, second string empty
1337 * [0] <- indicates end of strings
1340 static BOOL
FILE_AddBootRenameEntry( LPCWSTR fn1
, LPCWSTR fn2
, DWORD flags
)
1342 static const WCHAR PreString
[] = {'\\','?','?','\\',0};
1343 static const WCHAR ValueName
[] = {'P','e','n','d','i','n','g',
1344 'F','i','l','e','R','e','n','a','m','e',
1345 'O','p','e','r','a','t','i','o','n','s',0};
1346 static const WCHAR SessionW
[] = {'M','a','c','h','i','n','e','\\',
1347 'S','y','s','t','e','m','\\',
1348 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
1349 'C','o','n','t','r','o','l','\\',
1350 'S','e','s','s','i','o','n',' ','M','a','n','a','g','e','r',0};
1351 static const int info_size
= FIELD_OFFSET( KEY_VALUE_PARTIAL_INFORMATION
, Data
);
1353 OBJECT_ATTRIBUTES attr
;
1354 UNICODE_STRING nameW
;
1355 KEY_VALUE_PARTIAL_INFORMATION
*info
;
1358 DWORD len0
, len1
, len2
;
1360 BYTE
*Buffer
= NULL
;
1363 attr
.Length
= sizeof(attr
);
1364 attr
.RootDirectory
= 0;
1365 attr
.ObjectName
= &nameW
;
1366 attr
.Attributes
= 0;
1367 attr
.SecurityDescriptor
= NULL
;
1368 attr
.SecurityQualityOfService
= NULL
;
1369 RtlInitUnicodeString( &nameW
, SessionW
);
1371 if (NtCreateKey( &Reboot
, KEY_ALL_ACCESS
, &attr
, 0, NULL
, 0, NULL
) != STATUS_SUCCESS
)
1373 WARN("Error creating key for reboot managment [%s]\n",
1374 "SYSTEM\\CurrentControlSet\\Control\\Session Manager");
1378 len0
= strlenW(PreString
);
1379 len1
= strlenW(fn1
) + len0
+ 1;
1382 len2
= strlenW(fn2
) + len0
+ 1;
1383 if (flags
& MOVEFILE_REPLACE_EXISTING
) len2
++; /* Plus 1 because of the leading '!' */
1385 else len2
= 1; /* minimum is the 0 characters for the empty second string */
1387 /* convert characters to bytes */
1388 len0
*= sizeof(WCHAR
);
1389 len1
*= sizeof(WCHAR
);
1390 len2
*= sizeof(WCHAR
);
1392 RtlInitUnicodeString( &nameW
, ValueName
);
1394 /* First we check if the key exists and if so how many bytes it already contains. */
1395 if (NtQueryValueKey( Reboot
, &nameW
, KeyValuePartialInformation
,
1396 NULL
, 0, &DataSize
) == STATUS_BUFFER_OVERFLOW
)
1398 if (!(Buffer
= HeapAlloc( GetProcessHeap(), 0, DataSize
+ len1
+ len2
+ sizeof(WCHAR
) )))
1400 if (NtQueryValueKey( Reboot
, &nameW
, KeyValuePartialInformation
,
1401 Buffer
, DataSize
, &DataSize
)) goto Quit
;
1402 info
= (KEY_VALUE_PARTIAL_INFORMATION
*)Buffer
;
1403 if (info
->Type
!= REG_MULTI_SZ
) goto Quit
;
1404 if (DataSize
> sizeof(info
)) DataSize
-= sizeof(WCHAR
); /* remove terminating null (will be added back later) */
1408 DataSize
= info_size
;
1409 if (!(Buffer
= HeapAlloc( GetProcessHeap(), 0, DataSize
+ len1
+ len2
+ sizeof(WCHAR
) )))
1413 p
= (WCHAR
*)(Buffer
+ DataSize
);
1414 strcpyW( p
, PreString
);
1419 p
= (WCHAR
*)(Buffer
+ DataSize
);
1420 if (flags
& MOVEFILE_REPLACE_EXISTING
)
1422 strcpyW( p
, PreString
);
1428 p
= (WCHAR
*)(Buffer
+ DataSize
);
1430 DataSize
+= sizeof(WCHAR
);
1433 /* add final null */
1434 p
= (WCHAR
*)(Buffer
+ DataSize
);
1436 DataSize
+= sizeof(WCHAR
);
1438 rc
= !NtSetValueKey(Reboot
, &nameW
, 0, REG_MULTI_SZ
, Buffer
+ info_size
, DataSize
- info_size
);
1441 if (Reboot
) NtClose(Reboot
);
1442 if (Buffer
) HeapFree( GetProcessHeap(), 0, Buffer
);
1447 /**************************************************************************
1448 * MoveFileExW (KERNEL32.@)
1450 BOOL WINAPI
MoveFileExW( LPCWSTR fn1
, LPCWSTR fn2
, DWORD flag
)
1452 DOS_FULL_NAME full_name1
, full_name2
;
1454 DWORD attr
= INVALID_FILE_ATTRIBUTES
;
1456 TRACE("(%s,%s,%04lx)\n", debugstr_w(fn1
), debugstr_w(fn2
), flag
);
1458 /* FIXME: <Gerhard W. Gruber>sparhawk@gmx.at
1459 In case of W9x and lesser this function should return 120 (ERROR_CALL_NOT_IMPLEMENTED)
1460 to be really compatible. Most programs won't have any problems though. In case
1461 you encounter one, this is what you should return here. I don't know what's up
1462 with NT 3.5. Is this function available there or not?
1463 Does anybody really care about 3.5? :)
1466 /* Filename1 has to be always set to a valid path. Filename2 may be NULL
1467 if the source file has to be deleted.
1470 SetLastError(ERROR_INVALID_PARAMETER
);
1474 /* This function has to be run through in order to process the name properly.
1475 If the BOOTDELAY flag is set, the file doesn't need to exist though. At least
1476 that is the behaviour on NT 4.0. The operation accepts the filenames as
1477 they are given but it can't reply with a reasonable returncode. Success
1478 means in that case success for entering the values into the registry.
1480 if(!DOSFS_GetFullName( fn1
, TRUE
, &full_name1
))
1482 if(!(flag
& MOVEFILE_DELAY_UNTIL_REBOOT
))
1486 if (fn2
) /* !fn2 means delete fn1 */
1488 if (DOSFS_GetFullName( fn2
, TRUE
, &full_name2
))
1490 if(!(flag
& MOVEFILE_DELAY_UNTIL_REBOOT
))
1492 /* target exists, check if we may overwrite */
1493 if (!(flag
& MOVEFILE_REPLACE_EXISTING
))
1495 SetLastError( ERROR_ALREADY_EXISTS
);
1502 if (!DOSFS_GetFullName( fn2
, FALSE
, &full_name2
))
1504 if(!(flag
& MOVEFILE_DELAY_UNTIL_REBOOT
))
1509 /* Source name and target path are valid */
1511 if (flag
& MOVEFILE_DELAY_UNTIL_REBOOT
)
1513 return FILE_AddBootRenameEntry( fn1
, fn2
, flag
);
1516 attr
= GetFileAttributesW( fn1
);
1517 if ( attr
== INVALID_FILE_ATTRIBUTES
) return FALSE
;
1519 /* check if we are allowed to rename the source */
1520 hFile
= FILE_CreateFile( full_name1
.long_name
, 0, 0,
1521 NULL
, OPEN_EXISTING
, 0, 0, TRUE
,
1522 GetDriveTypeW( full_name1
.short_name
) );
1525 if (GetLastError() != ERROR_ACCESS_DENIED
) return FALSE
;
1526 if ( !(attr
& FILE_ATTRIBUTE_DIRECTORY
) ) return FALSE
;
1527 /* if it's a directory we can continue */
1529 else CloseHandle(hFile
);
1531 /* check, if we are allowed to delete the destination,
1532 ** (but the file not being there is fine) */
1533 hFile
= FILE_CreateFile( full_name2
.long_name
, GENERIC_READ
|GENERIC_WRITE
, 0,
1534 NULL
, OPEN_EXISTING
, 0, 0, TRUE
,
1535 GetDriveTypeW( full_name2
.short_name
) );
1536 if(!hFile
&& GetLastError() != ERROR_FILE_NOT_FOUND
) return FALSE
;
1539 if (full_name1
.drive
!= full_name2
.drive
)
1541 if (!(flag
& MOVEFILE_COPY_ALLOWED
))
1543 SetLastError( ERROR_NOT_SAME_DEVICE
);
1546 else if ( attr
& FILE_ATTRIBUTE_DIRECTORY
)
1548 /* Strange, but that's what Windows returns */
1549 SetLastError ( ERROR_ACCESS_DENIED
);
1553 if (rename( full_name1
.long_name
, full_name2
.long_name
) == -1)
1554 /* Try copy/delete unless it's a directory. */
1555 /* FIXME: This does not handle the (unlikely) case that the two locations
1556 are on the same Wine drive, but on different Unix file systems. */
1558 if ( attr
& FILE_ATTRIBUTE_DIRECTORY
)
1565 if ( ! CopyFileW( fn1
, fn2
, !(flag
& MOVEFILE_REPLACE_EXISTING
) ))
1567 if ( ! DeleteFileW ( fn1
) )
1571 if (is_executable( full_name1
.long_name
) != is_executable( full_name2
.long_name
))
1574 if (stat( full_name2
.long_name
, &fstat
) != -1)
1576 if (is_executable( full_name2
.long_name
))
1577 /* set executable bit where read bit is set */
1578 fstat
.st_mode
|= (fstat
.st_mode
& 0444) >> 2;
1580 fstat
.st_mode
&= ~0111;
1581 chmod( full_name2
.long_name
, fstat
.st_mode
);
1586 else /* fn2 == NULL means delete source */
1588 if (flag
& MOVEFILE_DELAY_UNTIL_REBOOT
)
1590 if (flag
& MOVEFILE_COPY_ALLOWED
) {
1591 WARN("Illegal flag\n");
1592 SetLastError( ERROR_GEN_FAILURE
);
1596 return FILE_AddBootRenameEntry( fn1
, NULL
, flag
);
1599 if (unlink( full_name1
.long_name
) == -1)
1604 return TRUE
; /* successfully deleted */
1608 /**************************************************************************
1609 * MoveFileExA (KERNEL32.@)
1611 BOOL WINAPI
MoveFileExA( LPCSTR fn1
, LPCSTR fn2
, DWORD flag
)
1613 UNICODE_STRING fn1W
, fn2W
;
1618 SetLastError(ERROR_INVALID_PARAMETER
);
1622 RtlCreateUnicodeStringFromAsciiz(&fn1W
, fn1
);
1623 if (fn2
) RtlCreateUnicodeStringFromAsciiz(&fn2W
, fn2
);
1624 else fn2W
.Buffer
= NULL
;
1626 ret
= MoveFileExW( fn1W
.Buffer
, fn2W
.Buffer
, flag
);
1628 RtlFreeUnicodeString(&fn1W
);
1629 RtlFreeUnicodeString(&fn2W
);
1634 /**************************************************************************
1635 * MoveFileW (KERNEL32.@)
1637 * Move file or directory
1639 BOOL WINAPI
MoveFileW( LPCWSTR fn1
, LPCWSTR fn2
)
1641 return MoveFileExW( fn1
, fn2
, MOVEFILE_COPY_ALLOWED
);
1645 /**************************************************************************
1646 * MoveFileA (KERNEL32.@)
1648 BOOL WINAPI
MoveFileA( LPCSTR fn1
, LPCSTR fn2
)
1650 return MoveFileExA( fn1
, fn2
, MOVEFILE_COPY_ALLOWED
);
1654 /**************************************************************************
1655 * CopyFileW (KERNEL32.@)
1657 BOOL WINAPI
CopyFileW( LPCWSTR source
, LPCWSTR dest
, BOOL fail_if_exists
)
1660 BY_HANDLE_FILE_INFORMATION info
;
1665 if (!source
|| !dest
)
1667 SetLastError(ERROR_INVALID_PARAMETER
);
1671 TRACE("%s -> %s\n", debugstr_w(source
), debugstr_w(dest
));
1673 if ((h1
= CreateFileW(source
, GENERIC_READ
, FILE_SHARE_READ
| FILE_SHARE_WRITE
,
1674 NULL
, OPEN_EXISTING
, 0, 0)) == INVALID_HANDLE_VALUE
)
1676 WARN("Unable to open source %s\n", debugstr_w(source
));
1680 if (!GetFileInformationByHandle( h1
, &info
))
1682 WARN("GetFileInformationByHandle returned error for %s\n", debugstr_w(source
));
1687 if ((h2
= CreateFileW( dest
, GENERIC_WRITE
, FILE_SHARE_READ
| FILE_SHARE_WRITE
, NULL
,
1688 fail_if_exists
? CREATE_NEW
: CREATE_ALWAYS
,
1689 info
.dwFileAttributes
, h1
)) == INVALID_HANDLE_VALUE
)
1691 WARN("Unable to open dest %s\n", debugstr_w(dest
));
1696 while (ReadFile( h1
, buffer
, sizeof(buffer
), &count
, NULL
) && count
)
1702 if (!WriteFile( h2
, p
, count
, &res
, NULL
) || !res
) goto done
;
1715 /**************************************************************************
1716 * CopyFileA (KERNEL32.@)
1718 BOOL WINAPI
CopyFileA( LPCSTR source
, LPCSTR dest
, BOOL fail_if_exists
)
1720 UNICODE_STRING sourceW
, destW
;
1723 if (!source
|| !dest
)
1725 SetLastError(ERROR_INVALID_PARAMETER
);
1729 RtlCreateUnicodeStringFromAsciiz(&sourceW
, source
);
1730 RtlCreateUnicodeStringFromAsciiz(&destW
, dest
);
1732 ret
= CopyFileW(sourceW
.Buffer
, destW
.Buffer
, fail_if_exists
);
1734 RtlFreeUnicodeString(&sourceW
);
1735 RtlFreeUnicodeString(&destW
);
1740 /**************************************************************************
1741 * CopyFileExW (KERNEL32.@)
1743 * This implementation ignores most of the extra parameters passed-in into
1744 * the "ex" version of the method and calls the CopyFile method.
1745 * It will have to be fixed eventually.
1747 BOOL WINAPI
CopyFileExW(LPCWSTR sourceFilename
, LPCWSTR destFilename
,
1748 LPPROGRESS_ROUTINE progressRoutine
, LPVOID appData
,
1749 LPBOOL cancelFlagPointer
, DWORD copyFlags
)
1752 * Interpret the only flag that CopyFile can interpret.
1754 return CopyFileW(sourceFilename
, destFilename
, (copyFlags
& COPY_FILE_FAIL_IF_EXISTS
) != 0);
1758 /**************************************************************************
1759 * CopyFileExA (KERNEL32.@)
1761 BOOL WINAPI
CopyFileExA(LPCSTR sourceFilename
, LPCSTR destFilename
,
1762 LPPROGRESS_ROUTINE progressRoutine
, LPVOID appData
,
1763 LPBOOL cancelFlagPointer
, DWORD copyFlags
)
1765 UNICODE_STRING sourceW
, destW
;
1768 if (!sourceFilename
|| !destFilename
)
1770 SetLastError(ERROR_INVALID_PARAMETER
);
1774 RtlCreateUnicodeStringFromAsciiz(&sourceW
, sourceFilename
);
1775 RtlCreateUnicodeStringFromAsciiz(&destW
, destFilename
);
1777 ret
= CopyFileExW(sourceW
.Buffer
, destW
.Buffer
, progressRoutine
, appData
,
1778 cancelFlagPointer
, copyFlags
);
1780 RtlFreeUnicodeString(&sourceW
);
1781 RtlFreeUnicodeString(&destW
);
1786 /***********************************************************************
1787 * SetFileTime (KERNEL32.@)
1789 BOOL WINAPI
SetFileTime( HANDLE hFile
,
1790 const FILETIME
*lpCreationTime
,
1791 const FILETIME
*lpLastAccessTime
,
1792 const FILETIME
*lpLastWriteTime
)
1795 SERVER_START_REQ( set_file_time
)
1797 req
->handle
= hFile
;
1798 if (lpLastAccessTime
)
1799 RtlTimeToSecondsSince1970( (PLARGE_INTEGER
) lpLastAccessTime
, (DWORD
*)&req
->access_time
);
1801 req
->access_time
= 0; /* FIXME */
1802 if (lpLastWriteTime
)
1803 RtlTimeToSecondsSince1970( (PLARGE_INTEGER
) lpLastWriteTime
, (DWORD
*)&req
->write_time
);
1805 req
->write_time
= 0; /* FIXME */
1806 ret
= !wine_server_call_err( req
);
1813 /**************************************************************************
1814 * GetFileAttributesExW (KERNEL32.@)
1816 BOOL WINAPI
GetFileAttributesExW(
1817 LPCWSTR lpFileName
, GET_FILEEX_INFO_LEVELS fInfoLevelId
,
1818 LPVOID lpFileInformation
)
1820 DOS_FULL_NAME full_name
;
1821 BY_HANDLE_FILE_INFORMATION info
;
1823 if (!lpFileName
|| !lpFileInformation
)
1825 SetLastError(ERROR_INVALID_PARAMETER
);
1829 if (fInfoLevelId
== GetFileExInfoStandard
) {
1830 LPWIN32_FILE_ATTRIBUTE_DATA lpFad
=
1831 (LPWIN32_FILE_ATTRIBUTE_DATA
) lpFileInformation
;
1832 if (!DOSFS_GetFullName( lpFileName
, TRUE
, &full_name
)) return FALSE
;
1833 if (!FILE_Stat( full_name
.long_name
, &info
, NULL
)) return FALSE
;
1835 lpFad
->dwFileAttributes
= info
.dwFileAttributes
;
1836 lpFad
->ftCreationTime
= info
.ftCreationTime
;
1837 lpFad
->ftLastAccessTime
= info
.ftLastAccessTime
;
1838 lpFad
->ftLastWriteTime
= info
.ftLastWriteTime
;
1839 lpFad
->nFileSizeHigh
= info
.nFileSizeHigh
;
1840 lpFad
->nFileSizeLow
= info
.nFileSizeLow
;
1843 FIXME("invalid info level %d!\n", fInfoLevelId
);
1851 /**************************************************************************
1852 * GetFileAttributesExA (KERNEL32.@)
1854 BOOL WINAPI
GetFileAttributesExA(
1855 LPCSTR filename
, GET_FILEEX_INFO_LEVELS fInfoLevelId
,
1856 LPVOID lpFileInformation
)
1858 UNICODE_STRING filenameW
;
1861 if (!filename
|| !lpFileInformation
)
1863 SetLastError(ERROR_INVALID_PARAMETER
);
1867 if (RtlCreateUnicodeStringFromAsciiz(&filenameW
, filename
))
1869 ret
= GetFileAttributesExW(filenameW
.Buffer
, fInfoLevelId
, lpFileInformation
);
1870 RtlFreeUnicodeString(&filenameW
);
1873 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);