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')
86 #define SECSPERDAY 86400
87 #define SECS_1601_TO_1970 ((369 * 365 + 89) * (ULONGLONG)SECSPERDAY)
91 /***********************************************************************
94 * Convert OF_* mode into flags for CreateFile.
96 void FILE_ConvertOFMode( INT mode
, DWORD
*access
, DWORD
*sharing
)
100 case OF_READ
: *access
= GENERIC_READ
; break;
101 case OF_WRITE
: *access
= GENERIC_WRITE
; break;
102 case OF_READWRITE
: *access
= GENERIC_READ
| GENERIC_WRITE
; break;
103 default: *access
= 0; break;
107 case OF_SHARE_EXCLUSIVE
: *sharing
= 0; break;
108 case OF_SHARE_DENY_WRITE
: *sharing
= FILE_SHARE_READ
; break;
109 case OF_SHARE_DENY_READ
: *sharing
= FILE_SHARE_WRITE
; break;
110 case OF_SHARE_DENY_NONE
:
111 case OF_SHARE_COMPAT
:
112 default: *sharing
= FILE_SHARE_READ
| FILE_SHARE_WRITE
; break;
117 /***********************************************************************
120 * Set the DOS error code from errno.
122 void FILE_SetDosError(void)
124 int save_errno
= errno
; /* errno gets overwritten by printf */
126 TRACE("errno = %d %s\n", errno
, strerror(errno
));
130 SetLastError( ERROR_SHARING_VIOLATION
);
133 SetLastError( ERROR_INVALID_HANDLE
);
136 SetLastError( ERROR_HANDLE_DISK_FULL
);
141 SetLastError( ERROR_ACCESS_DENIED
);
144 SetLastError( ERROR_LOCK_VIOLATION
);
147 SetLastError( ERROR_FILE_NOT_FOUND
);
150 SetLastError( ERROR_CANNOT_MAKE
);
154 SetLastError( ERROR_NO_MORE_FILES
);
157 SetLastError( ERROR_FILE_EXISTS
);
161 SetLastError( ERROR_SEEK
);
164 SetLastError( ERROR_DIR_NOT_EMPTY
);
167 SetLastError( ERROR_BAD_FORMAT
);
170 WARN("unknown file error: %s\n", strerror(save_errno
) );
171 SetLastError( ERROR_GEN_FAILURE
);
178 /***********************************************************************
181 * Implementation of CreateFile. Takes a Unix path name.
182 * Returns 0 on failure.
184 HANDLE
FILE_CreateFile( LPCSTR filename
, DWORD access
, DWORD sharing
,
185 LPSECURITY_ATTRIBUTES sa
, DWORD creation
,
186 DWORD attributes
, HANDLE
template )
194 case CREATE_ALWAYS
: disp
= FILE_OVERWRITE_IF
; break;
195 case CREATE_NEW
: disp
= FILE_CREATE
; break;
196 case OPEN_ALWAYS
: disp
= FILE_OPEN_IF
; break;
197 case OPEN_EXISTING
: disp
= FILE_OPEN
; break;
198 case TRUNCATE_EXISTING
: disp
= FILE_OVERWRITE
; break;
200 SetLastError( ERROR_INVALID_PARAMETER
);
205 if (attributes
& FILE_FLAG_BACKUP_SEMANTICS
)
206 options
|= FILE_OPEN_FOR_BACKUP_INTENT
;
207 if (attributes
& FILE_FLAG_DELETE_ON_CLOSE
)
208 options
|= FILE_DELETE_ON_CLOSE
;
209 if (!(attributes
& FILE_FLAG_OVERLAPPED
))
210 options
|= FILE_SYNCHRONOUS_IO_ALERT
;
211 if (attributes
& FILE_FLAG_RANDOM_ACCESS
)
212 options
|= FILE_RANDOM_ACCESS
;
213 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 wine_server_add_data( req
, filename
, strlen(filename
) );
225 err
= wine_server_call( req
);
232 /* In the case file creation was rejected due to CREATE_NEW flag
233 * was specified and file with that name already exists, correct
234 * last error is ERROR_FILE_EXISTS and not ERROR_ALREADY_EXISTS.
235 * Note: RtlNtStatusToDosError is not the subject to blame here.
237 if (err
== STATUS_OBJECT_NAME_COLLISION
)
238 SetLastError( ERROR_FILE_EXISTS
);
240 SetLastError( RtlNtStatusToDosError(err
) );
243 if (!ret
) WARN("Unable to create file '%s' (GLE %ld)\n", filename
, GetLastError());
248 static HANDLE
FILE_OpenPipe(LPCWSTR name
, DWORD access
, LPSECURITY_ATTRIBUTES sa
)
253 if (name
&& (len
= strlenW(name
)) > MAX_PATH
)
255 SetLastError( ERROR_FILENAME_EXCED_RANGE
);
258 SERVER_START_REQ( open_named_pipe
)
260 req
->access
= access
;
261 req
->inherit
= (sa
&& (sa
->nLength
>=sizeof(*sa
)) && sa
->bInheritHandle
);
263 wine_server_add_data( req
, name
, len
* sizeof(WCHAR
) );
264 wine_server_call_err( req
);
268 TRACE("Returned %p\n",ret
);
272 /*************************************************************************
273 * CreateFileW [KERNEL32.@] Creates or opens a file or other object
275 * Creates or opens an object, and returns a handle that can be used to
276 * access that object.
280 * filename [in] pointer to filename to be accessed
281 * access [in] access mode requested
282 * sharing [in] share mode
283 * sa [in] pointer to security attributes
284 * creation [in] how to create the file
285 * attributes [in] attributes for newly created file
286 * template [in] handle to file with extended attributes to copy
289 * Success: Open handle to specified file
290 * Failure: INVALID_HANDLE_VALUE
293 * Should call SetLastError() on failure.
297 * Doesn't support character devices, template files, or a
298 * lot of the 'attributes' flags yet.
300 HANDLE WINAPI
CreateFileW( LPCWSTR filename
, DWORD access
, DWORD sharing
,
301 LPSECURITY_ATTRIBUTES sa
, DWORD creation
,
302 DWORD attributes
, HANDLE
template )
304 DOS_FULL_NAME full_name
;
307 static const WCHAR bkslashes_with_question_markW
[] = {'\\','\\','?','\\',0};
308 static const WCHAR bkslashes_with_dotW
[] = {'\\','\\','.','\\',0};
309 static const WCHAR bkslashesW
[] = {'\\','\\',0};
310 static const WCHAR coninW
[] = {'C','O','N','I','N','$',0};
311 static const WCHAR conoutW
[] = {'C','O','N','O','U','T','$',0};
313 if (!filename
|| !filename
[0])
315 SetLastError( ERROR_PATH_NOT_FOUND
);
316 return INVALID_HANDLE_VALUE
;
319 TRACE("%s %s%s%s%s%s%s%s attributes 0x%lx\n", debugstr_w(filename
),
320 ((access
& GENERIC_READ
)==GENERIC_READ
)?"GENERIC_READ ":"",
321 ((access
& GENERIC_WRITE
)==GENERIC_WRITE
)?"GENERIC_WRITE ":"",
322 (!access
)?"QUERY_ACCESS ":"",
323 ((sharing
& FILE_SHARE_READ
)==FILE_SHARE_READ
)?"FILE_SHARE_READ ":"",
324 ((sharing
& FILE_SHARE_WRITE
)==FILE_SHARE_WRITE
)?"FILE_SHARE_WRITE ":"",
325 ((sharing
& FILE_SHARE_DELETE
)==FILE_SHARE_DELETE
)?"FILE_SHARE_DELETE ":"",
326 (creation
==CREATE_NEW
)?"CREATE_NEW":
327 (creation
==CREATE_ALWAYS
)?"CREATE_ALWAYS ":
328 (creation
==OPEN_EXISTING
)?"OPEN_EXISTING ":
329 (creation
==OPEN_ALWAYS
)?"OPEN_ALWAYS ":
330 (creation
==TRUNCATE_EXISTING
)?"TRUNCATE_EXISTING ":"", attributes
);
332 /* Open a console for CONIN$ or CONOUT$ */
333 if (!strcmpiW(filename
, coninW
) || !strcmpiW(filename
, conoutW
))
335 ret
= OpenConsoleW(filename
, access
, (sa
&& sa
->bInheritHandle
), creation
);
339 /* If the name starts with '\\?\', ignore the first 4 chars. */
340 if (!strncmpW(filename
, bkslashes_with_question_markW
, 4))
342 static const WCHAR uncW
[] = {'U','N','C','\\',0};
344 if (!strncmpiW(filename
, uncW
, 4))
346 FIXME("UNC name (%s) not supported.\n", debugstr_w(filename
) );
347 SetLastError( ERROR_PATH_NOT_FOUND
);
348 return INVALID_HANDLE_VALUE
;
352 if (!strncmpW(filename
, bkslashes_with_dotW
, 4))
354 static const WCHAR pipeW
[] = {'P','I','P','E','\\',0};
355 if(!strncmpiW(filename
+ 4, pipeW
, 5))
357 TRACE("Opening a pipe: %s\n", debugstr_w(filename
));
358 ret
= FILE_OpenPipe( filename
, access
, sa
);
361 else if (isalphaW(filename
[4]) && filename
[5] == ':' && filename
[6] == '\0')
363 const char *device
= DRIVE_GetDevice( toupperW(filename
[4]) - 'A' );
366 ret
= FILE_CreateFile( device
, access
, sharing
, sa
, creation
,
367 attributes
, template );
371 SetLastError( ERROR_ACCESS_DENIED
);
372 ret
= INVALID_HANDLE_VALUE
;
376 else if ((dosdev
= RtlIsDosDeviceName_U( filename
+ 4 )))
378 dosdev
+= MAKELONG( 0, 4*sizeof(WCHAR
) ); /* adjust position to start of filename */
382 ret
= VXD_Open( filename
+4, access
, sa
);
386 else dosdev
= RtlIsDosDeviceName_U( filename
);
390 static const WCHAR conW
[] = {'C','O','N',0};
393 memcpy( dev
, filename
+ HIWORD(dosdev
)/sizeof(WCHAR
), LOWORD(dosdev
) );
394 dev
[LOWORD(dosdev
)/sizeof(WCHAR
)] = 0;
396 TRACE("opening device %s\n", debugstr_w(dev
) );
398 if (!strcmpiW( dev
, conW
))
400 switch (access
& (GENERIC_READ
|GENERIC_WRITE
))
403 ret
= OpenConsoleW(coninW
, access
, (sa
&& sa
->bInheritHandle
), creation
);
406 ret
= OpenConsoleW(conoutW
, access
, (sa
&& sa
->bInheritHandle
), creation
);
409 FIXME("can't open CON read/write\n");
410 SetLastError( ERROR_FILE_NOT_FOUND
);
411 return INVALID_HANDLE_VALUE
;
415 ret
= VOLUME_OpenDevice( dev
, access
, sharing
, sa
, attributes
);
419 /* If the name still starts with '\\', it's a UNC name. */
420 if (!strncmpW(filename
, bkslashesW
, 2))
422 ret
= SMB_CreateFileW(filename
, access
, sharing
, sa
, creation
, attributes
, template );
426 /* If the name contains a DOS wild card (* or ?), do no create a file */
427 if(strchrW(filename
, '*') || strchrW(filename
, '?'))
429 SetLastError(ERROR_BAD_PATHNAME
);
430 return INVALID_HANDLE_VALUE
;
433 /* check for filename, don't check for last entry if creating */
434 if (!DOSFS_GetFullName( filename
,
435 (creation
== OPEN_EXISTING
) ||
436 (creation
== TRUNCATE_EXISTING
),
438 WARN("Unable to get full filename from %s (GLE %ld)\n",
439 debugstr_w(filename
), GetLastError());
440 return INVALID_HANDLE_VALUE
;
443 ret
= FILE_CreateFile( full_name
.long_name
, access
, sharing
,
444 sa
, creation
, attributes
, template );
446 if (!ret
) ret
= INVALID_HANDLE_VALUE
;
447 TRACE("returning %p\n", ret
);
453 /*************************************************************************
454 * CreateFileA (KERNEL32.@)
456 HANDLE WINAPI
CreateFileA( LPCSTR filename
, DWORD access
, DWORD sharing
,
457 LPSECURITY_ATTRIBUTES sa
, DWORD creation
,
458 DWORD attributes
, HANDLE
template)
460 UNICODE_STRING filenameW
;
461 HANDLE ret
= INVALID_HANDLE_VALUE
;
465 SetLastError( ERROR_INVALID_PARAMETER
);
466 return INVALID_HANDLE_VALUE
;
469 if (RtlCreateUnicodeStringFromAsciiz(&filenameW
, filename
))
471 ret
= CreateFileW(filenameW
.Buffer
, access
, sharing
, sa
, creation
,
472 attributes
, template);
473 RtlFreeUnicodeString(&filenameW
);
476 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
481 /***********************************************************************
484 * Fill a file information from a struct stat.
486 static void FILE_FillInfo( struct stat
*st
, BY_HANDLE_FILE_INFORMATION
*info
)
488 if (S_ISDIR(st
->st_mode
))
489 info
->dwFileAttributes
= FILE_ATTRIBUTE_DIRECTORY
;
491 info
->dwFileAttributes
= FILE_ATTRIBUTE_ARCHIVE
;
492 if (!(st
->st_mode
& S_IWUSR
))
493 info
->dwFileAttributes
|= FILE_ATTRIBUTE_READONLY
;
495 RtlSecondsSince1970ToTime( st
->st_mtime
, (LARGE_INTEGER
*)&info
->ftCreationTime
);
496 RtlSecondsSince1970ToTime( st
->st_mtime
, (LARGE_INTEGER
*)&info
->ftLastWriteTime
);
497 RtlSecondsSince1970ToTime( st
->st_atime
, (LARGE_INTEGER
*)&info
->ftLastAccessTime
);
499 info
->dwVolumeSerialNumber
= 0; /* FIXME */
500 if (S_ISDIR(st
->st_mode
))
502 info
->nFileSizeHigh
= 0;
503 info
->nFileSizeLow
= 0;
504 info
->nNumberOfLinks
= 1;
508 info
->nFileSizeHigh
= st
->st_size
>> 32;
509 info
->nFileSizeLow
= (DWORD
)st
->st_size
;
510 info
->nNumberOfLinks
= st
->st_nlink
;
512 info
->nFileIndexHigh
= st
->st_ino
>> 32;
513 info
->nFileIndexLow
= (DWORD
)st
->st_ino
;
517 /***********************************************************************
518 * get_show_dot_files_option
520 static BOOL
get_show_dot_files_option(void)
522 static const WCHAR WineW
[] = {'M','a','c','h','i','n','e','\\',
523 'S','o','f','t','w','a','r','e','\\',
524 'W','i','n','e','\\','W','i','n','e','\\',
525 'C','o','n','f','i','g','\\','W','i','n','e',0};
526 static const WCHAR ShowDotFilesW
[] = {'S','h','o','w','D','o','t','F','i','l','e','s',0};
531 OBJECT_ATTRIBUTES attr
;
532 UNICODE_STRING nameW
;
535 attr
.Length
= sizeof(attr
);
536 attr
.RootDirectory
= 0;
537 attr
.ObjectName
= &nameW
;
539 attr
.SecurityDescriptor
= NULL
;
540 attr
.SecurityQualityOfService
= NULL
;
541 RtlInitUnicodeString( &nameW
, WineW
);
543 if (!NtOpenKey( &hkey
, KEY_ALL_ACCESS
, &attr
))
545 RtlInitUnicodeString( &nameW
, ShowDotFilesW
);
546 if (!NtQueryValueKey( hkey
, &nameW
, KeyValuePartialInformation
, tmp
, sizeof(tmp
), &dummy
))
548 WCHAR
*str
= (WCHAR
*)((KEY_VALUE_PARTIAL_INFORMATION
*)tmp
)->Data
;
549 ret
= IS_OPTION_TRUE( str
[0] );
557 /***********************************************************************
560 * Stat a Unix path name. Return TRUE if OK.
562 BOOL
FILE_Stat( LPCSTR unixName
, BY_HANDLE_FILE_INFORMATION
*info
, BOOL
*is_symlink_ptr
)
568 if (lstat( unixName
, &st
) == -1)
573 is_symlink
= S_ISLNK(st
.st_mode
);
576 /* do a "real" stat to find out
577 about the type of the symlink destination */
578 if (stat( unixName
, &st
) == -1)
585 /* fill in the information we gathered so far */
586 FILE_FillInfo( &st
, info
);
588 /* and now see if this is a hidden file, based on the name */
589 p
= strrchr( unixName
, '/');
590 p
= p
? p
+ 1 : unixName
;
591 if (*p
== '.' && *(p
+1) && (*(p
+1) != '.' || *(p
+2)))
593 static int show_dot_files
= -1;
594 if (show_dot_files
== -1)
595 show_dot_files
= get_show_dot_files_option();
597 info
->dwFileAttributes
|= FILE_ATTRIBUTE_HIDDEN
;
599 if (is_symlink_ptr
) *is_symlink_ptr
= is_symlink
;
604 /***********************************************************************
605 * GetFileInformationByHandle (KERNEL32.@)
607 BOOL WINAPI
GetFileInformationByHandle( HANDLE hFile
, BY_HANDLE_FILE_INFORMATION
*info
)
613 TRACE("%p,%p\n", hFile
, info
);
617 if (!(status
= wine_server_handle_to_fd( hFile
, 0, &fd
, NULL
, NULL
)))
621 if (fstat( fd
, &st
) == -1)
623 else if (!S_ISREG(st
.st_mode
) && !S_ISDIR(st
.st_mode
))
624 SetLastError( ERROR_INVALID_FUNCTION
);
627 FILE_FillInfo( &st
, info
);
630 wine_server_release_fd( hFile
, fd
);
632 else SetLastError( RtlNtStatusToDosError(status
) );
638 /**************************************************************************
639 * GetFileAttributesW (KERNEL32.@)
641 DWORD WINAPI
GetFileAttributesW( LPCWSTR name
)
643 DOS_FULL_NAME full_name
;
644 BY_HANDLE_FILE_INFORMATION info
;
648 SetLastError( ERROR_INVALID_PARAMETER
);
649 return INVALID_FILE_ATTRIBUTES
;
651 if (!DOSFS_GetFullName( name
, TRUE
, &full_name
) )
652 return INVALID_FILE_ATTRIBUTES
;
653 if (!FILE_Stat( full_name
.long_name
, &info
, NULL
))
654 return INVALID_FILE_ATTRIBUTES
;
655 return info
.dwFileAttributes
;
659 /**************************************************************************
660 * GetFileAttributesA (KERNEL32.@)
662 DWORD WINAPI
GetFileAttributesA( LPCSTR name
)
664 UNICODE_STRING nameW
;
665 DWORD ret
= INVALID_FILE_ATTRIBUTES
;
669 SetLastError( ERROR_INVALID_PARAMETER
);
670 return INVALID_FILE_ATTRIBUTES
;
673 if (RtlCreateUnicodeStringFromAsciiz(&nameW
, name
))
675 ret
= GetFileAttributesW(nameW
.Buffer
);
676 RtlFreeUnicodeString(&nameW
);
679 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
684 /**************************************************************************
685 * SetFileAttributesW (KERNEL32.@)
687 BOOL WINAPI
SetFileAttributesW(LPCWSTR lpFileName
, DWORD attributes
)
690 DOS_FULL_NAME full_name
;
694 SetLastError( ERROR_INVALID_PARAMETER
);
698 TRACE("(%s,%lx)\n", debugstr_w(lpFileName
), attributes
);
700 if (!DOSFS_GetFullName( lpFileName
, TRUE
, &full_name
))
703 if(stat(full_name
.long_name
,&buf
)==-1)
708 if (attributes
& FILE_ATTRIBUTE_READONLY
)
710 if(S_ISDIR(buf
.st_mode
))
712 WARN("FILE_ATTRIBUTE_READONLY ignored for directory.\n");
714 buf
.st_mode
&= ~0222; /* octal!, clear write permission bits */
715 attributes
&= ~FILE_ATTRIBUTE_READONLY
;
719 /* add write permission */
720 buf
.st_mode
|= (0600 | ((buf
.st_mode
& 044) >> 1)) & (~FILE_umask
);
722 if (attributes
& FILE_ATTRIBUTE_DIRECTORY
)
724 if (!S_ISDIR(buf
.st_mode
))
725 FIXME("SetFileAttributes expected the file %s to be a directory\n",
726 debugstr_w(lpFileName
));
727 attributes
&= ~FILE_ATTRIBUTE_DIRECTORY
;
729 attributes
&= ~(FILE_ATTRIBUTE_NORMAL
|FILE_ATTRIBUTE_ARCHIVE
|FILE_ATTRIBUTE_HIDDEN
|
730 FILE_ATTRIBUTE_SYSTEM
|FILE_ATTRIBUTE_TEMPORARY
);
732 FIXME("(%s):%lx attribute(s) not implemented.\n", debugstr_w(lpFileName
), attributes
);
733 if (-1==chmod(full_name
.long_name
,buf
.st_mode
))
735 if (GetDriveTypeW(lpFileName
) == DRIVE_CDROM
)
737 SetLastError( ERROR_ACCESS_DENIED
);
742 * FIXME: We don't return FALSE here because of differences between
743 * Linux and Windows privileges. Under Linux only the owner of
744 * the file is allowed to change file attributes. Under Windows,
745 * applications expect that if you can write to a file, you can also
746 * change its attributes (see GENERIC_WRITE). We could try to be
747 * clever here but that would break multi-user installations where
748 * users share read-only DLLs. This is because some installers like
749 * to change attributes of already installed DLLs.
751 FIXME("Couldn't set file attributes for existing file \"%s\".\n"
752 "Check permissions or set VFAT \"quiet\" mount flag\n", full_name
.long_name
);
758 /**************************************************************************
759 * SetFileAttributesA (KERNEL32.@)
761 BOOL WINAPI
SetFileAttributesA(LPCSTR lpFileName
, DWORD attributes
)
763 UNICODE_STRING filenameW
;
768 SetLastError( ERROR_INVALID_PARAMETER
);
772 if (RtlCreateUnicodeStringFromAsciiz(&filenameW
, lpFileName
))
774 ret
= SetFileAttributesW(filenameW
.Buffer
, attributes
);
775 RtlFreeUnicodeString(&filenameW
);
778 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
783 /******************************************************************************
784 * GetCompressedFileSizeA [KERNEL32.@]
786 DWORD WINAPI
GetCompressedFileSizeA(
788 LPDWORD lpFileSizeHigh
)
790 UNICODE_STRING filenameW
;
793 if (RtlCreateUnicodeStringFromAsciiz(&filenameW
, lpFileName
))
795 ret
= GetCompressedFileSizeW(filenameW
.Buffer
, lpFileSizeHigh
);
796 RtlFreeUnicodeString(&filenameW
);
800 ret
= INVALID_FILE_SIZE
;
801 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
807 /******************************************************************************
808 * GetCompressedFileSizeW [KERNEL32.@]
811 * Success: Low-order doubleword of number of bytes
812 * Failure: INVALID_FILE_SIZE
814 DWORD WINAPI
GetCompressedFileSizeW(
815 LPCWSTR lpFileName
, /* [in] Pointer to name of file */
816 LPDWORD lpFileSizeHigh
) /* [out] Receives high-order doubleword of size */
818 DOS_FULL_NAME full_name
;
822 TRACE("(%s,%p)\n",debugstr_w(lpFileName
),lpFileSizeHigh
);
824 if (!DOSFS_GetFullName( lpFileName
, TRUE
, &full_name
)) return INVALID_FILE_SIZE
;
825 if (stat(full_name
.long_name
, &st
) != 0)
828 return INVALID_FILE_SIZE
;
830 #if HAVE_STRUCT_STAT_ST_BLOCKS
831 /* blocks are 512 bytes long */
832 if (lpFileSizeHigh
) *lpFileSizeHigh
= (st
.st_blocks
>> 23);
833 low
= (DWORD
)(st
.st_blocks
<< 9);
835 if (lpFileSizeHigh
) *lpFileSizeHigh
= (st
.st_size
>> 32);
836 low
= (DWORD
)st
.st_size
;
842 /***********************************************************************
843 * GetFileTime (KERNEL32.@)
845 BOOL WINAPI
GetFileTime( HANDLE hFile
, FILETIME
*lpCreationTime
,
846 FILETIME
*lpLastAccessTime
,
847 FILETIME
*lpLastWriteTime
)
849 BY_HANDLE_FILE_INFORMATION info
;
850 if (!GetFileInformationByHandle( hFile
, &info
)) return FALSE
;
851 if (lpCreationTime
) *lpCreationTime
= info
.ftCreationTime
;
852 if (lpLastAccessTime
) *lpLastAccessTime
= info
.ftLastAccessTime
;
853 if (lpLastWriteTime
) *lpLastWriteTime
= info
.ftLastWriteTime
;
858 /***********************************************************************
859 * GetTempFileNameA (KERNEL32.@)
861 UINT WINAPI
GetTempFileNameA( LPCSTR path
, LPCSTR prefix
, UINT unique
,
864 UNICODE_STRING pathW
, prefixW
;
865 WCHAR bufferW
[MAX_PATH
];
868 if ( !path
|| !prefix
|| !buffer
)
870 SetLastError( ERROR_INVALID_PARAMETER
);
874 RtlCreateUnicodeStringFromAsciiz(&pathW
, path
);
875 RtlCreateUnicodeStringFromAsciiz(&prefixW
, prefix
);
877 ret
= GetTempFileNameW(pathW
.Buffer
, prefixW
.Buffer
, unique
, bufferW
);
879 WideCharToMultiByte(CP_ACP
, 0, bufferW
, -1, buffer
, MAX_PATH
, NULL
, NULL
);
881 RtlFreeUnicodeString(&pathW
);
882 RtlFreeUnicodeString(&prefixW
);
886 /***********************************************************************
887 * GetTempFileNameW (KERNEL32.@)
889 UINT WINAPI
GetTempFileNameW( LPCWSTR path
, LPCWSTR prefix
, UINT unique
,
892 static const WCHAR formatW
[] = {'%','x','.','t','m','p',0};
894 DOS_FULL_NAME full_name
;
898 if ( !path
|| !prefix
|| !buffer
)
900 SetLastError( ERROR_INVALID_PARAMETER
);
904 strcpyW( buffer
, path
);
905 p
= buffer
+ strlenW(buffer
);
907 /* add a \, if there isn't one */
908 if ((p
== buffer
) || (p
[-1] != '\\')) *p
++ = '\\';
910 for (i
= 3; (i
> 0) && (*prefix
); i
--) *p
++ = *prefix
++;
914 if (unique
) sprintfW( p
, formatW
, unique
);
917 /* get a "random" unique number and try to create the file */
919 UINT num
= GetTickCount() & 0xffff;
925 sprintfW( p
, formatW
, unique
);
926 handle
= CreateFileW( buffer
, GENERIC_WRITE
, 0, NULL
,
927 CREATE_NEW
, FILE_ATTRIBUTE_NORMAL
, 0 );
928 if (handle
!= INVALID_HANDLE_VALUE
)
929 { /* We created it */
930 TRACE("created %s\n", debugstr_w(buffer
) );
931 CloseHandle( handle
);
934 if (GetLastError() != ERROR_FILE_EXISTS
&&
935 GetLastError() != ERROR_SHARING_VIOLATION
)
936 break; /* No need to go on */
937 if (!(++unique
& 0xffff)) unique
= 1;
938 } while (unique
!= num
);
941 /* Get the full path name */
943 if (DOSFS_GetFullName( buffer
, FALSE
, &full_name
))
946 /* Check if we have write access in the directory */
947 if ((slash
= strrchr( full_name
.long_name
, '/' ))) *slash
= '\0';
948 if (access( full_name
.long_name
, W_OK
) == -1)
949 WARN("returns %s, which doesn't seem to be writeable.\n",
950 debugstr_w(buffer
) );
952 TRACE("returning %s\n", debugstr_w(buffer
) );
957 /******************************************************************
958 * FILE_ReadWriteApc (internal)
962 static void WINAPI
FILE_ReadWriteApc(void* apc_user
, PIO_STATUS_BLOCK io_status
, ULONG len
)
964 LPOVERLAPPED_COMPLETION_ROUTINE cr
= (LPOVERLAPPED_COMPLETION_ROUTINE
)apc_user
;
966 cr(RtlNtStatusToDosError(io_status
->u
.Status
), len
, (LPOVERLAPPED
)io_status
);
969 /***********************************************************************
970 * ReadFileEx (KERNEL32.@)
972 BOOL WINAPI
ReadFileEx(HANDLE hFile
, LPVOID buffer
, DWORD bytesToRead
,
973 LPOVERLAPPED overlapped
,
974 LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine
)
976 LARGE_INTEGER offset
;
978 PIO_STATUS_BLOCK io_status
;
982 SetLastError(ERROR_INVALID_PARAMETER
);
986 offset
.u
.LowPart
= overlapped
->Offset
;
987 offset
.u
.HighPart
= overlapped
->OffsetHigh
;
988 io_status
= (PIO_STATUS_BLOCK
)overlapped
;
989 io_status
->u
.Status
= STATUS_PENDING
;
991 status
= NtReadFile(hFile
, NULL
, FILE_ReadWriteApc
, lpCompletionRoutine
,
992 io_status
, buffer
, bytesToRead
, &offset
, NULL
);
996 SetLastError( RtlNtStatusToDosError(status
) );
1002 /***********************************************************************
1003 * ReadFile (KERNEL32.@)
1005 BOOL WINAPI
ReadFile( HANDLE hFile
, LPVOID buffer
, DWORD bytesToRead
,
1006 LPDWORD bytesRead
, LPOVERLAPPED overlapped
)
1008 LARGE_INTEGER offset
;
1009 PLARGE_INTEGER poffset
= NULL
;
1010 IO_STATUS_BLOCK iosb
;
1011 PIO_STATUS_BLOCK io_status
= &iosb
;
1015 TRACE("%p %p %ld %p %p\n", hFile
, buffer
, bytesToRead
,
1016 bytesRead
, overlapped
);
1018 if (bytesRead
) *bytesRead
= 0; /* Do this before anything else */
1019 if (!bytesToRead
) return TRUE
;
1021 if (IsBadReadPtr(buffer
, bytesToRead
))
1023 SetLastError(ERROR_WRITE_FAULT
); /* FIXME */
1026 if (is_console_handle(hFile
))
1027 return ReadConsoleA(hFile
, buffer
, bytesToRead
, bytesRead
, NULL
);
1029 if (overlapped
!= NULL
)
1031 offset
.u
.LowPart
= overlapped
->Offset
;
1032 offset
.u
.HighPart
= overlapped
->OffsetHigh
;
1034 hEvent
= overlapped
->hEvent
;
1035 io_status
= (PIO_STATUS_BLOCK
)overlapped
;
1037 io_status
->u
.Status
= STATUS_PENDING
;
1038 io_status
->Information
= 0;
1040 status
= NtReadFile(hFile
, hEvent
, NULL
, NULL
, io_status
, buffer
, bytesToRead
, poffset
, NULL
);
1042 if (status
!= STATUS_PENDING
&& bytesRead
)
1043 *bytesRead
= io_status
->Information
;
1045 if (status
&& status
!= STATUS_END_OF_FILE
)
1047 SetLastError( RtlNtStatusToDosError(status
) );
1054 /***********************************************************************
1055 * WriteFileEx (KERNEL32.@)
1057 BOOL WINAPI
WriteFileEx(HANDLE hFile
, LPCVOID buffer
, DWORD bytesToWrite
,
1058 LPOVERLAPPED overlapped
,
1059 LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine
)
1061 LARGE_INTEGER offset
;
1063 PIO_STATUS_BLOCK io_status
;
1065 TRACE("%p %p %ld %p %p\n",
1066 hFile
, buffer
, bytesToWrite
, overlapped
, lpCompletionRoutine
);
1068 if (overlapped
== NULL
)
1070 SetLastError(ERROR_INVALID_PARAMETER
);
1073 offset
.u
.LowPart
= overlapped
->Offset
;
1074 offset
.u
.HighPart
= overlapped
->OffsetHigh
;
1076 io_status
= (PIO_STATUS_BLOCK
)overlapped
;
1077 io_status
->u
.Status
= STATUS_PENDING
;
1079 status
= NtWriteFile(hFile
, NULL
, FILE_ReadWriteApc
, lpCompletionRoutine
,
1080 io_status
, buffer
, bytesToWrite
, &offset
, NULL
);
1082 if (status
) SetLastError( RtlNtStatusToDosError(status
) );
1086 /***********************************************************************
1087 * WriteFile (KERNEL32.@)
1089 BOOL WINAPI
WriteFile( HANDLE hFile
, LPCVOID buffer
, DWORD bytesToWrite
,
1090 LPDWORD bytesWritten
, LPOVERLAPPED overlapped
)
1092 HANDLE hEvent
= NULL
;
1093 LARGE_INTEGER offset
;
1094 PLARGE_INTEGER poffset
= NULL
;
1096 IO_STATUS_BLOCK iosb
;
1097 PIO_STATUS_BLOCK piosb
= &iosb
;
1099 TRACE("%p %p %ld %p %p\n",
1100 hFile
, buffer
, bytesToWrite
, bytesWritten
, overlapped
);
1102 if (is_console_handle(hFile
))
1103 return WriteConsoleA(hFile
, buffer
, bytesToWrite
, bytesWritten
, NULL
);
1105 if (IsBadReadPtr(buffer
, bytesToWrite
))
1107 SetLastError(ERROR_READ_FAULT
); /* FIXME */
1113 offset
.u
.LowPart
= overlapped
->Offset
;
1114 offset
.u
.HighPart
= overlapped
->OffsetHigh
;
1116 hEvent
= overlapped
->hEvent
;
1117 piosb
= (PIO_STATUS_BLOCK
)overlapped
;
1119 piosb
->u
.Status
= STATUS_PENDING
;
1120 piosb
->Information
= 0;
1122 status
= NtWriteFile(hFile
, hEvent
, NULL
, NULL
, piosb
,
1123 buffer
, bytesToWrite
, poffset
, NULL
);
1126 SetLastError( RtlNtStatusToDosError(status
) );
1129 if (bytesWritten
) *bytesWritten
= piosb
->Information
;
1135 /***********************************************************************
1136 * SetFilePointer (KERNEL32.@)
1138 DWORD WINAPI
SetFilePointer( HANDLE hFile
, LONG distance
, LONG
*highword
,
1141 static const int whence
[3] = { SEEK_SET
, SEEK_CUR
, SEEK_END
};
1142 DWORD ret
= INVALID_SET_FILE_POINTER
;
1146 TRACE("handle %p offset %ld high %ld origin %ld\n",
1147 hFile
, distance
, highword
?*highword
:0, method
);
1149 if (method
> FILE_END
)
1151 SetLastError( ERROR_INVALID_PARAMETER
);
1155 if (!(status
= wine_server_handle_to_fd( hFile
, 0, &fd
, NULL
, NULL
)))
1159 if (highword
) pos
= ((off_t
)*highword
<< 32) | (ULONG
)distance
;
1160 else pos
= (off_t
)distance
;
1161 if ((res
= lseek( fd
, pos
, whence
[method
] )) == (off_t
)-1)
1163 /* also check EPERM due to SuSE7 2.2.16 lseek() EPERM kernel bug */
1164 if (((errno
== EINVAL
) || (errno
== EPERM
)) && (method
!= FILE_BEGIN
) && (pos
< 0))
1165 SetLastError( ERROR_NEGATIVE_SEEK
);
1172 if (highword
) *highword
= (res
>> 32);
1173 if (ret
== INVALID_SET_FILE_POINTER
) SetLastError( 0 );
1175 wine_server_release_fd( hFile
, fd
);
1177 else SetLastError( RtlNtStatusToDosError(status
) );
1183 /*************************************************************************
1184 * SetHandleCount (KERNEL32.@)
1186 UINT WINAPI
SetHandleCount( UINT count
)
1188 return min( 256, count
);
1192 /**************************************************************************
1193 * SetEndOfFile (KERNEL32.@)
1195 BOOL WINAPI
SetEndOfFile( HANDLE hFile
)
1198 SERVER_START_REQ( truncate_file
)
1200 req
->handle
= hFile
;
1201 ret
= !wine_server_call_err( req
);
1208 /***********************************************************************
1209 * GetFileType (KERNEL32.@)
1211 DWORD WINAPI
GetFileType( HANDLE hFile
)
1215 DWORD ret
= FILE_TYPE_UNKNOWN
;
1217 if (is_console_handle( hFile
))
1218 return FILE_TYPE_CHAR
;
1220 if (!(status
= wine_server_handle_to_fd( hFile
, 0, &fd
, NULL
, NULL
)))
1224 if (fstat( fd
, &st
) == -1)
1226 else if (S_ISFIFO(st
.st_mode
) || S_ISSOCK(st
.st_mode
))
1227 ret
= FILE_TYPE_PIPE
;
1228 else if (S_ISCHR(st
.st_mode
))
1229 ret
= FILE_TYPE_CHAR
;
1231 ret
= FILE_TYPE_DISK
;
1232 wine_server_release_fd( hFile
, fd
);
1234 else SetLastError( RtlNtStatusToDosError(status
) );
1240 /* check if a file name is for an executable file (.exe or .com) */
1241 inline static BOOL
is_executable( const char *name
)
1243 int len
= strlen(name
);
1245 if (len
< 4) return FALSE
;
1246 return (!strcasecmp( name
+ len
- 4, ".exe" ) ||
1247 !strcasecmp( name
+ len
- 4, ".com" ));
1251 /***********************************************************************
1252 * FILE_AddBootRenameEntry
1254 * Adds an entry to the registry that is loaded when windows boots and
1255 * checks if there are some files to be removed or renamed/moved.
1256 * <fn1> has to be valid and <fn2> may be NULL. If both pointers are
1257 * non-NULL then the file is moved, otherwise it is deleted. The
1258 * entry of the registrykey is always appended with two zero
1259 * terminated strings. If <fn2> is NULL then the second entry is
1260 * simply a single 0-byte. Otherwise the second filename goes
1261 * there. The entries are prepended with \??\ before the path and the
1262 * second filename gets also a '!' as the first character if
1263 * MOVEFILE_REPLACE_EXISTING is set. After the final string another
1264 * 0-byte follows to indicate the end of the strings.
1266 * \??\D:\test\file1[0]
1267 * !\??\D:\test\file1_renamed[0]
1268 * \??\D:\Test|delete[0]
1269 * [0] <- file is to be deleted, second string empty
1270 * \??\D:\test\file2[0]
1271 * !\??\D:\test\file2_renamed[0]
1272 * [0] <- indicates end of strings
1275 * \??\D:\test\file1[0]
1276 * !\??\D:\test\file1_renamed[0]
1277 * \??\D:\Test|delete[0]
1278 * [0] <- file is to be deleted, second string empty
1279 * [0] <- indicates end of strings
1282 static BOOL
FILE_AddBootRenameEntry( LPCWSTR fn1
, LPCWSTR fn2
, DWORD flags
)
1284 static const WCHAR PreString
[] = {'\\','?','?','\\',0};
1285 static const WCHAR ValueName
[] = {'P','e','n','d','i','n','g',
1286 'F','i','l','e','R','e','n','a','m','e',
1287 'O','p','e','r','a','t','i','o','n','s',0};
1288 static const WCHAR SessionW
[] = {'M','a','c','h','i','n','e','\\',
1289 'S','y','s','t','e','m','\\',
1290 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
1291 'C','o','n','t','r','o','l','\\',
1292 'S','e','s','s','i','o','n',' ','M','a','n','a','g','e','r',0};
1293 static const int info_size
= FIELD_OFFSET( KEY_VALUE_PARTIAL_INFORMATION
, Data
);
1295 OBJECT_ATTRIBUTES attr
;
1296 UNICODE_STRING nameW
;
1297 KEY_VALUE_PARTIAL_INFORMATION
*info
;
1300 DWORD len0
, len1
, len2
;
1302 BYTE
*Buffer
= NULL
;
1305 attr
.Length
= sizeof(attr
);
1306 attr
.RootDirectory
= 0;
1307 attr
.ObjectName
= &nameW
;
1308 attr
.Attributes
= 0;
1309 attr
.SecurityDescriptor
= NULL
;
1310 attr
.SecurityQualityOfService
= NULL
;
1311 RtlInitUnicodeString( &nameW
, SessionW
);
1313 if (NtCreateKey( &Reboot
, KEY_ALL_ACCESS
, &attr
, 0, NULL
, 0, NULL
) != STATUS_SUCCESS
)
1315 WARN("Error creating key for reboot managment [%s]\n",
1316 "SYSTEM\\CurrentControlSet\\Control\\Session Manager");
1320 len0
= strlenW(PreString
);
1321 len1
= strlenW(fn1
) + len0
+ 1;
1324 len2
= strlenW(fn2
) + len0
+ 1;
1325 if (flags
& MOVEFILE_REPLACE_EXISTING
) len2
++; /* Plus 1 because of the leading '!' */
1327 else len2
= 1; /* minimum is the 0 characters for the empty second string */
1329 /* convert characters to bytes */
1330 len0
*= sizeof(WCHAR
);
1331 len1
*= sizeof(WCHAR
);
1332 len2
*= sizeof(WCHAR
);
1334 RtlInitUnicodeString( &nameW
, ValueName
);
1336 /* First we check if the key exists and if so how many bytes it already contains. */
1337 if (NtQueryValueKey( Reboot
, &nameW
, KeyValuePartialInformation
,
1338 NULL
, 0, &DataSize
) == STATUS_BUFFER_OVERFLOW
)
1340 if (!(Buffer
= HeapAlloc( GetProcessHeap(), 0, DataSize
+ len1
+ len2
+ sizeof(WCHAR
) )))
1342 if (NtQueryValueKey( Reboot
, &nameW
, KeyValuePartialInformation
,
1343 Buffer
, DataSize
, &DataSize
)) goto Quit
;
1344 info
= (KEY_VALUE_PARTIAL_INFORMATION
*)Buffer
;
1345 if (info
->Type
!= REG_MULTI_SZ
) goto Quit
;
1346 if (DataSize
> sizeof(info
)) DataSize
-= sizeof(WCHAR
); /* remove terminating null (will be added back later) */
1350 DataSize
= info_size
;
1351 if (!(Buffer
= HeapAlloc( GetProcessHeap(), 0, DataSize
+ len1
+ len2
+ sizeof(WCHAR
) )))
1355 p
= (WCHAR
*)(Buffer
+ DataSize
);
1356 strcpyW( p
, PreString
);
1361 p
= (WCHAR
*)(Buffer
+ DataSize
);
1362 if (flags
& MOVEFILE_REPLACE_EXISTING
)
1364 strcpyW( p
, PreString
);
1370 p
= (WCHAR
*)(Buffer
+ DataSize
);
1372 DataSize
+= sizeof(WCHAR
);
1375 /* add final null */
1376 p
= (WCHAR
*)(Buffer
+ DataSize
);
1378 DataSize
+= sizeof(WCHAR
);
1380 rc
= !NtSetValueKey(Reboot
, &nameW
, 0, REG_MULTI_SZ
, Buffer
+ info_size
, DataSize
- info_size
);
1383 if (Reboot
) NtClose(Reboot
);
1384 if (Buffer
) HeapFree( GetProcessHeap(), 0, Buffer
);
1389 /**************************************************************************
1390 * MoveFileExW (KERNEL32.@)
1392 BOOL WINAPI
MoveFileExW( LPCWSTR fn1
, LPCWSTR fn2
, DWORD flag
)
1394 DOS_FULL_NAME full_name1
, full_name2
;
1396 DWORD attr
= INVALID_FILE_ATTRIBUTES
;
1398 TRACE("(%s,%s,%04lx)\n", debugstr_w(fn1
), debugstr_w(fn2
), flag
);
1400 /* FIXME: <Gerhard W. Gruber>sparhawk@gmx.at
1401 In case of W9x and lesser this function should return 120 (ERROR_CALL_NOT_IMPLEMENTED)
1402 to be really compatible. Most programs won't have any problems though. In case
1403 you encounter one, this is what you should return here. I don't know what's up
1404 with NT 3.5. Is this function available there or not?
1405 Does anybody really care about 3.5? :)
1408 /* Filename1 has to be always set to a valid path. Filename2 may be NULL
1409 if the source file has to be deleted.
1412 SetLastError(ERROR_INVALID_PARAMETER
);
1416 /* This function has to be run through in order to process the name properly.
1417 If the BOOTDELAY flag is set, the file doesn't need to exist though. At least
1418 that is the behaviour on NT 4.0. The operation accepts the filenames as
1419 they are given but it can't reply with a reasonable returncode. Success
1420 means in that case success for entering the values into the registry.
1422 if(!DOSFS_GetFullName( fn1
, TRUE
, &full_name1
))
1424 if(!(flag
& MOVEFILE_DELAY_UNTIL_REBOOT
))
1428 if (fn2
) /* !fn2 means delete fn1 */
1430 if (DOSFS_GetFullName( fn2
, TRUE
, &full_name2
))
1432 if(!(flag
& MOVEFILE_DELAY_UNTIL_REBOOT
))
1434 /* target exists, check if we may overwrite */
1435 if (!(flag
& MOVEFILE_REPLACE_EXISTING
))
1437 SetLastError( ERROR_ALREADY_EXISTS
);
1444 if (!DOSFS_GetFullName( fn2
, FALSE
, &full_name2
))
1446 if(!(flag
& MOVEFILE_DELAY_UNTIL_REBOOT
))
1451 /* Source name and target path are valid */
1453 if (flag
& MOVEFILE_DELAY_UNTIL_REBOOT
)
1455 return FILE_AddBootRenameEntry( fn1
, fn2
, flag
);
1458 attr
= GetFileAttributesW( fn1
);
1459 if ( attr
== INVALID_FILE_ATTRIBUTES
) return FALSE
;
1461 /* check if we are allowed to rename the source */
1462 hFile
= FILE_CreateFile( full_name1
.long_name
, 0, 0,
1463 NULL
, OPEN_EXISTING
, 0, 0 );
1466 if (GetLastError() != ERROR_ACCESS_DENIED
) return FALSE
;
1467 if ( !(attr
& FILE_ATTRIBUTE_DIRECTORY
) ) return FALSE
;
1468 /* if it's a directory we can continue */
1470 else CloseHandle(hFile
);
1472 /* check, if we are allowed to delete the destination,
1473 ** (but the file not being there is fine) */
1474 hFile
= FILE_CreateFile( full_name2
.long_name
, GENERIC_READ
|GENERIC_WRITE
, 0,
1475 NULL
, OPEN_EXISTING
, 0, 0 );
1476 if(!hFile
&& GetLastError() != ERROR_FILE_NOT_FOUND
) return FALSE
;
1479 if (full_name1
.drive
!= full_name2
.drive
)
1481 if (!(flag
& MOVEFILE_COPY_ALLOWED
))
1483 SetLastError( ERROR_NOT_SAME_DEVICE
);
1486 else if ( attr
& FILE_ATTRIBUTE_DIRECTORY
)
1488 /* Strange, but that's what Windows returns */
1489 SetLastError ( ERROR_ACCESS_DENIED
);
1493 if (rename( full_name1
.long_name
, full_name2
.long_name
) == -1)
1494 /* Try copy/delete unless it's a directory. */
1495 /* FIXME: This does not handle the (unlikely) case that the two locations
1496 are on the same Wine drive, but on different Unix file systems. */
1498 if ( attr
& FILE_ATTRIBUTE_DIRECTORY
)
1505 if ( ! CopyFileW( fn1
, fn2
, !(flag
& MOVEFILE_REPLACE_EXISTING
) ))
1507 if ( ! DeleteFileW ( fn1
) )
1511 if (is_executable( full_name1
.long_name
) != is_executable( full_name2
.long_name
))
1514 if (stat( full_name2
.long_name
, &fstat
) != -1)
1516 if (is_executable( full_name2
.long_name
))
1517 /* set executable bit where read bit is set */
1518 fstat
.st_mode
|= (fstat
.st_mode
& 0444) >> 2;
1520 fstat
.st_mode
&= ~0111;
1521 chmod( full_name2
.long_name
, fstat
.st_mode
);
1526 else /* fn2 == NULL means delete source */
1528 if (flag
& MOVEFILE_DELAY_UNTIL_REBOOT
)
1530 if (flag
& MOVEFILE_COPY_ALLOWED
) {
1531 WARN("Illegal flag\n");
1532 SetLastError( ERROR_GEN_FAILURE
);
1536 return FILE_AddBootRenameEntry( fn1
, NULL
, flag
);
1539 if (unlink( full_name1
.long_name
) == -1)
1544 return TRUE
; /* successfully deleted */
1548 /**************************************************************************
1549 * MoveFileExA (KERNEL32.@)
1551 BOOL WINAPI
MoveFileExA( LPCSTR fn1
, LPCSTR fn2
, DWORD flag
)
1553 UNICODE_STRING fn1W
, fn2W
;
1558 SetLastError(ERROR_INVALID_PARAMETER
);
1562 RtlCreateUnicodeStringFromAsciiz(&fn1W
, fn1
);
1563 if (fn2
) RtlCreateUnicodeStringFromAsciiz(&fn2W
, fn2
);
1564 else fn2W
.Buffer
= NULL
;
1566 ret
= MoveFileExW( fn1W
.Buffer
, fn2W
.Buffer
, flag
);
1568 RtlFreeUnicodeString(&fn1W
);
1569 RtlFreeUnicodeString(&fn2W
);
1574 /**************************************************************************
1575 * MoveFileW (KERNEL32.@)
1577 * Move file or directory
1579 BOOL WINAPI
MoveFileW( LPCWSTR fn1
, LPCWSTR fn2
)
1581 return MoveFileExW( fn1
, fn2
, MOVEFILE_COPY_ALLOWED
);
1585 /**************************************************************************
1586 * MoveFileA (KERNEL32.@)
1588 BOOL WINAPI
MoveFileA( LPCSTR fn1
, LPCSTR fn2
)
1590 return MoveFileExA( fn1
, fn2
, MOVEFILE_COPY_ALLOWED
);
1594 /**************************************************************************
1595 * CopyFileW (KERNEL32.@)
1597 BOOL WINAPI
CopyFileW( LPCWSTR source
, LPCWSTR dest
, BOOL fail_if_exists
)
1600 BY_HANDLE_FILE_INFORMATION info
;
1605 if (!source
|| !dest
)
1607 SetLastError(ERROR_INVALID_PARAMETER
);
1611 TRACE("%s -> %s\n", debugstr_w(source
), debugstr_w(dest
));
1613 if ((h1
= CreateFileW(source
, GENERIC_READ
, FILE_SHARE_READ
| FILE_SHARE_WRITE
,
1614 NULL
, OPEN_EXISTING
, 0, 0)) == INVALID_HANDLE_VALUE
)
1616 WARN("Unable to open source %s\n", debugstr_w(source
));
1620 if (!GetFileInformationByHandle( h1
, &info
))
1622 WARN("GetFileInformationByHandle returned error for %s\n", debugstr_w(source
));
1627 if ((h2
= CreateFileW( dest
, GENERIC_WRITE
, FILE_SHARE_READ
| FILE_SHARE_WRITE
, NULL
,
1628 fail_if_exists
? CREATE_NEW
: CREATE_ALWAYS
,
1629 info
.dwFileAttributes
, h1
)) == INVALID_HANDLE_VALUE
)
1631 WARN("Unable to open dest %s\n", debugstr_w(dest
));
1636 while (ReadFile( h1
, buffer
, sizeof(buffer
), &count
, NULL
) && count
)
1642 if (!WriteFile( h2
, p
, count
, &res
, NULL
) || !res
) goto done
;
1655 /**************************************************************************
1656 * CopyFileA (KERNEL32.@)
1658 BOOL WINAPI
CopyFileA( LPCSTR source
, LPCSTR dest
, BOOL fail_if_exists
)
1660 UNICODE_STRING sourceW
, destW
;
1663 if (!source
|| !dest
)
1665 SetLastError(ERROR_INVALID_PARAMETER
);
1669 RtlCreateUnicodeStringFromAsciiz(&sourceW
, source
);
1670 RtlCreateUnicodeStringFromAsciiz(&destW
, dest
);
1672 ret
= CopyFileW(sourceW
.Buffer
, destW
.Buffer
, fail_if_exists
);
1674 RtlFreeUnicodeString(&sourceW
);
1675 RtlFreeUnicodeString(&destW
);
1680 /**************************************************************************
1681 * CopyFileExW (KERNEL32.@)
1683 * This implementation ignores most of the extra parameters passed-in into
1684 * the "ex" version of the method and calls the CopyFile method.
1685 * It will have to be fixed eventually.
1687 BOOL WINAPI
CopyFileExW(LPCWSTR sourceFilename
, LPCWSTR destFilename
,
1688 LPPROGRESS_ROUTINE progressRoutine
, LPVOID appData
,
1689 LPBOOL cancelFlagPointer
, DWORD copyFlags
)
1692 * Interpret the only flag that CopyFile can interpret.
1694 return CopyFileW(sourceFilename
, destFilename
, (copyFlags
& COPY_FILE_FAIL_IF_EXISTS
) != 0);
1698 /**************************************************************************
1699 * CopyFileExA (KERNEL32.@)
1701 BOOL WINAPI
CopyFileExA(LPCSTR sourceFilename
, LPCSTR destFilename
,
1702 LPPROGRESS_ROUTINE progressRoutine
, LPVOID appData
,
1703 LPBOOL cancelFlagPointer
, DWORD copyFlags
)
1705 UNICODE_STRING sourceW
, destW
;
1708 if (!sourceFilename
|| !destFilename
)
1710 SetLastError(ERROR_INVALID_PARAMETER
);
1714 RtlCreateUnicodeStringFromAsciiz(&sourceW
, sourceFilename
);
1715 RtlCreateUnicodeStringFromAsciiz(&destW
, destFilename
);
1717 ret
= CopyFileExW(sourceW
.Buffer
, destW
.Buffer
, progressRoutine
, appData
,
1718 cancelFlagPointer
, copyFlags
);
1720 RtlFreeUnicodeString(&sourceW
);
1721 RtlFreeUnicodeString(&destW
);
1726 /***********************************************************************
1727 * SetFileTime (KERNEL32.@)
1729 BOOL WINAPI
SetFileTime( HANDLE hFile
,
1730 const FILETIME
*ctime
,
1731 const FILETIME
*atime
,
1732 const FILETIME
*mtime
)
1738 if (!(status
= wine_server_handle_to_fd( hFile
, GENERIC_WRITE
, &fd
, NULL
, NULL
)))
1741 ULONGLONG sec
, nsec
;
1742 struct timeval tv
[2];
1744 if (!atime
|| !mtime
)
1748 tv
[0].tv_sec
= tv
[0].tv_usec
= 0;
1749 tv
[1].tv_sec
= tv
[1].tv_usec
= 0;
1750 if (!fstat( fd
, &st
))
1752 tv
[0].tv_sec
= st
.st_atime
;
1753 tv
[1].tv_sec
= st
.st_mtime
;
1758 sec
= ((ULONGLONG
)atime
->dwHighDateTime
<< 32) | atime
->dwLowDateTime
;
1759 sec
= RtlLargeIntegerDivide( sec
, 10000000, &nsec
);
1760 tv
[0].tv_sec
= sec
- SECS_1601_TO_1970
;
1761 tv
[0].tv_usec
= (UINT
)nsec
/ 10;
1765 sec
= ((ULONGLONG
)mtime
->dwHighDateTime
<< 32) | mtime
->dwLowDateTime
;
1766 sec
= RtlLargeIntegerDivide( sec
, 10000000, &nsec
);
1767 tv
[1].tv_sec
= sec
- SECS_1601_TO_1970
;
1768 tv
[1].tv_usec
= (UINT
)nsec
/ 10;
1771 if (!futimes( fd
, tv
)) ret
= TRUE
;
1772 else FILE_SetDosError();
1774 ret
= TRUE
; /* pretend it succeeded */
1776 wine_server_release_fd( hFile
, fd
);
1778 else SetLastError( RtlNtStatusToDosError(status
) );
1783 /**************************************************************************
1784 * GetFileAttributesExW (KERNEL32.@)
1786 BOOL WINAPI
GetFileAttributesExW(
1787 LPCWSTR lpFileName
, GET_FILEEX_INFO_LEVELS fInfoLevelId
,
1788 LPVOID lpFileInformation
)
1790 DOS_FULL_NAME full_name
;
1791 BY_HANDLE_FILE_INFORMATION info
;
1793 if (!lpFileName
|| !lpFileInformation
)
1795 SetLastError(ERROR_INVALID_PARAMETER
);
1799 if (fInfoLevelId
== GetFileExInfoStandard
) {
1800 LPWIN32_FILE_ATTRIBUTE_DATA lpFad
=
1801 (LPWIN32_FILE_ATTRIBUTE_DATA
) lpFileInformation
;
1802 if (!DOSFS_GetFullName( lpFileName
, TRUE
, &full_name
)) return FALSE
;
1803 if (!FILE_Stat( full_name
.long_name
, &info
, NULL
)) return FALSE
;
1805 lpFad
->dwFileAttributes
= info
.dwFileAttributes
;
1806 lpFad
->ftCreationTime
= info
.ftCreationTime
;
1807 lpFad
->ftLastAccessTime
= info
.ftLastAccessTime
;
1808 lpFad
->ftLastWriteTime
= info
.ftLastWriteTime
;
1809 lpFad
->nFileSizeHigh
= info
.nFileSizeHigh
;
1810 lpFad
->nFileSizeLow
= info
.nFileSizeLow
;
1813 FIXME("invalid info level %d!\n", fInfoLevelId
);
1821 /**************************************************************************
1822 * GetFileAttributesExA (KERNEL32.@)
1824 BOOL WINAPI
GetFileAttributesExA(
1825 LPCSTR filename
, GET_FILEEX_INFO_LEVELS fInfoLevelId
,
1826 LPVOID lpFileInformation
)
1828 UNICODE_STRING filenameW
;
1831 if (!filename
|| !lpFileInformation
)
1833 SetLastError(ERROR_INVALID_PARAMETER
);
1837 if (RtlCreateUnicodeStringFromAsciiz(&filenameW
, filename
))
1839 ret
= GetFileAttributesExW(filenameW
.Buffer
, fInfoLevelId
, lpFileInformation
);
1840 RtlFreeUnicodeString(&filenameW
);
1843 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);