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
;
208 options
|= FILE_NON_DIRECTORY_FILE
;
209 if (attributes
& FILE_FLAG_DELETE_ON_CLOSE
)
210 options
|= FILE_DELETE_ON_CLOSE
;
211 if (!(attributes
& FILE_FLAG_OVERLAPPED
))
212 options
|= FILE_SYNCHRONOUS_IO_ALERT
;
213 if (attributes
& FILE_FLAG_RANDOM_ACCESS
)
214 options
|= FILE_RANDOM_ACCESS
;
215 attributes
&= FILE_ATTRIBUTE_VALID_FLAGS
;
217 SERVER_START_REQ( create_file
)
219 req
->access
= access
;
220 req
->inherit
= (sa
&& (sa
->nLength
>=sizeof(*sa
)) && sa
->bInheritHandle
);
221 req
->sharing
= sharing
;
223 req
->options
= options
;
224 req
->attrs
= attributes
;
225 wine_server_add_data( req
, filename
, strlen(filename
) );
227 err
= wine_server_call( req
);
234 /* In the case file creation was rejected due to CREATE_NEW flag
235 * was specified and file with that name already exists, correct
236 * last error is ERROR_FILE_EXISTS and not ERROR_ALREADY_EXISTS.
237 * Note: RtlNtStatusToDosError is not the subject to blame here.
239 if (err
== STATUS_OBJECT_NAME_COLLISION
)
240 SetLastError( ERROR_FILE_EXISTS
);
242 SetLastError( RtlNtStatusToDosError(err
) );
245 if (!ret
) WARN("Unable to create file '%s' (GLE %ld)\n", filename
, GetLastError());
250 static HANDLE
FILE_OpenPipe(LPCWSTR name
, DWORD access
, LPSECURITY_ATTRIBUTES sa
)
255 if (name
&& (len
= strlenW(name
)) > MAX_PATH
)
257 SetLastError( ERROR_FILENAME_EXCED_RANGE
);
260 SERVER_START_REQ( open_named_pipe
)
262 req
->access
= access
;
263 req
->inherit
= (sa
&& (sa
->nLength
>=sizeof(*sa
)) && sa
->bInheritHandle
);
265 wine_server_add_data( req
, name
, len
* sizeof(WCHAR
) );
266 wine_server_call_err( req
);
270 TRACE("Returned %p\n",ret
);
274 /*************************************************************************
275 * CreateFileW [KERNEL32.@] Creates or opens a file or other object
277 * Creates or opens an object, and returns a handle that can be used to
278 * access that object.
282 * filename [in] pointer to filename to be accessed
283 * access [in] access mode requested
284 * sharing [in] share mode
285 * sa [in] pointer to security attributes
286 * creation [in] how to create the file
287 * attributes [in] attributes for newly created file
288 * template [in] handle to file with extended attributes to copy
291 * Success: Open handle to specified file
292 * Failure: INVALID_HANDLE_VALUE
295 * Should call SetLastError() on failure.
299 * Doesn't support character devices, template files, or a
300 * lot of the 'attributes' flags yet.
302 HANDLE WINAPI
CreateFileW( LPCWSTR filename
, DWORD access
, DWORD sharing
,
303 LPSECURITY_ATTRIBUTES sa
, DWORD creation
,
304 DWORD attributes
, HANDLE
template )
306 DOS_FULL_NAME full_name
;
309 static const WCHAR bkslashes_with_question_markW
[] = {'\\','\\','?','\\',0};
310 static const WCHAR bkslashes_with_dotW
[] = {'\\','\\','.','\\',0};
311 static const WCHAR bkslashesW
[] = {'\\','\\',0};
312 static const WCHAR coninW
[] = {'C','O','N','I','N','$',0};
313 static const WCHAR conoutW
[] = {'C','O','N','O','U','T','$',0};
315 if (!filename
|| !filename
[0])
317 SetLastError( ERROR_PATH_NOT_FOUND
);
318 return INVALID_HANDLE_VALUE
;
321 TRACE("%s %s%s%s%s%s%s%s attributes 0x%lx\n", debugstr_w(filename
),
322 ((access
& GENERIC_READ
)==GENERIC_READ
)?"GENERIC_READ ":"",
323 ((access
& GENERIC_WRITE
)==GENERIC_WRITE
)?"GENERIC_WRITE ":"",
324 (!access
)?"QUERY_ACCESS ":"",
325 ((sharing
& FILE_SHARE_READ
)==FILE_SHARE_READ
)?"FILE_SHARE_READ ":"",
326 ((sharing
& FILE_SHARE_WRITE
)==FILE_SHARE_WRITE
)?"FILE_SHARE_WRITE ":"",
327 ((sharing
& FILE_SHARE_DELETE
)==FILE_SHARE_DELETE
)?"FILE_SHARE_DELETE ":"",
328 (creation
==CREATE_NEW
)?"CREATE_NEW":
329 (creation
==CREATE_ALWAYS
)?"CREATE_ALWAYS ":
330 (creation
==OPEN_EXISTING
)?"OPEN_EXISTING ":
331 (creation
==OPEN_ALWAYS
)?"OPEN_ALWAYS ":
332 (creation
==TRUNCATE_EXISTING
)?"TRUNCATE_EXISTING ":"", attributes
);
334 /* Open a console for CONIN$ or CONOUT$ */
335 if (!strcmpiW(filename
, coninW
) || !strcmpiW(filename
, conoutW
))
337 ret
= OpenConsoleW(filename
, access
, (sa
&& sa
->bInheritHandle
), creation
);
341 /* If the name starts with '\\?\', ignore the first 4 chars. */
342 if (!strncmpW(filename
, bkslashes_with_question_markW
, 4))
344 static const WCHAR uncW
[] = {'U','N','C','\\',0};
346 if (!strncmpiW(filename
, uncW
, 4))
348 FIXME("UNC name (%s) not supported.\n", debugstr_w(filename
) );
349 SetLastError( ERROR_PATH_NOT_FOUND
);
350 return INVALID_HANDLE_VALUE
;
354 if (!strncmpW(filename
, bkslashes_with_dotW
, 4))
356 static const WCHAR pipeW
[] = {'P','I','P','E','\\',0};
357 if(!strncmpiW(filename
+ 4, pipeW
, 5))
359 TRACE("Opening a pipe: %s\n", debugstr_w(filename
));
360 ret
= FILE_OpenPipe( filename
, access
, sa
);
363 else if (isalphaW(filename
[4]) && filename
[5] == ':' && filename
[6] == '\0')
365 const char *device
= DRIVE_GetDevice( toupperW(filename
[4]) - 'A' );
368 ret
= FILE_CreateFile( device
, access
, sharing
, sa
, creation
,
369 attributes
, template );
373 SetLastError( ERROR_ACCESS_DENIED
);
374 ret
= INVALID_HANDLE_VALUE
;
378 else if ((dosdev
= RtlIsDosDeviceName_U( filename
+ 4 )))
380 dosdev
+= MAKELONG( 0, 4*sizeof(WCHAR
) ); /* adjust position to start of filename */
384 ret
= VXD_Open( filename
+4, access
, sa
);
388 else dosdev
= RtlIsDosDeviceName_U( filename
);
392 static const WCHAR conW
[] = {'C','O','N',0};
395 memcpy( dev
, filename
+ HIWORD(dosdev
)/sizeof(WCHAR
), LOWORD(dosdev
) );
396 dev
[LOWORD(dosdev
)/sizeof(WCHAR
)] = 0;
398 TRACE("opening device %s\n", debugstr_w(dev
) );
400 if (!strcmpiW( dev
, conW
))
402 switch (access
& (GENERIC_READ
|GENERIC_WRITE
))
405 ret
= OpenConsoleW(coninW
, access
, (sa
&& sa
->bInheritHandle
), creation
);
408 ret
= OpenConsoleW(conoutW
, access
, (sa
&& sa
->bInheritHandle
), creation
);
411 FIXME("can't open CON read/write\n");
412 SetLastError( ERROR_FILE_NOT_FOUND
);
413 return INVALID_HANDLE_VALUE
;
417 ret
= VOLUME_OpenDevice( dev
, access
, sharing
, sa
, attributes
);
421 /* If the name still starts with '\\', it's a UNC name. */
422 if (!strncmpW(filename
, bkslashesW
, 2))
424 ret
= SMB_CreateFileW(filename
, access
, sharing
, sa
, creation
, attributes
, template );
428 /* If the name contains a DOS wild card (* or ?), do no create a file */
429 if(strchrW(filename
, '*') || strchrW(filename
, '?'))
431 SetLastError(ERROR_BAD_PATHNAME
);
432 return INVALID_HANDLE_VALUE
;
435 /* check for filename, don't check for last entry if creating */
436 if (!DOSFS_GetFullName( filename
,
437 (creation
== OPEN_EXISTING
) ||
438 (creation
== TRUNCATE_EXISTING
),
440 WARN("Unable to get full filename from %s (GLE %ld)\n",
441 debugstr_w(filename
), GetLastError());
442 return INVALID_HANDLE_VALUE
;
445 ret
= FILE_CreateFile( full_name
.long_name
, access
, sharing
,
446 sa
, creation
, attributes
, template );
448 if (!ret
) ret
= INVALID_HANDLE_VALUE
;
449 TRACE("returning %p\n", ret
);
455 /*************************************************************************
456 * CreateFileA (KERNEL32.@)
458 HANDLE WINAPI
CreateFileA( LPCSTR filename
, DWORD access
, DWORD sharing
,
459 LPSECURITY_ATTRIBUTES sa
, DWORD creation
,
460 DWORD attributes
, HANDLE
template)
462 UNICODE_STRING filenameW
;
463 HANDLE ret
= INVALID_HANDLE_VALUE
;
467 SetLastError( ERROR_INVALID_PARAMETER
);
468 return INVALID_HANDLE_VALUE
;
471 if (RtlCreateUnicodeStringFromAsciiz(&filenameW
, filename
))
473 ret
= CreateFileW(filenameW
.Buffer
, access
, sharing
, sa
, creation
,
474 attributes
, template);
475 RtlFreeUnicodeString(&filenameW
);
478 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
483 /***********************************************************************
486 * Fill a file information from a struct stat.
488 static void FILE_FillInfo( struct stat
*st
, BY_HANDLE_FILE_INFORMATION
*info
)
490 if (S_ISDIR(st
->st_mode
))
491 info
->dwFileAttributes
= FILE_ATTRIBUTE_DIRECTORY
;
493 info
->dwFileAttributes
= FILE_ATTRIBUTE_ARCHIVE
;
494 if (!(st
->st_mode
& S_IWUSR
))
495 info
->dwFileAttributes
|= FILE_ATTRIBUTE_READONLY
;
497 RtlSecondsSince1970ToTime( st
->st_mtime
, (LARGE_INTEGER
*)&info
->ftCreationTime
);
498 RtlSecondsSince1970ToTime( st
->st_mtime
, (LARGE_INTEGER
*)&info
->ftLastWriteTime
);
499 RtlSecondsSince1970ToTime( st
->st_atime
, (LARGE_INTEGER
*)&info
->ftLastAccessTime
);
501 info
->dwVolumeSerialNumber
= 0; /* FIXME */
502 if (S_ISDIR(st
->st_mode
))
504 info
->nFileSizeHigh
= 0;
505 info
->nFileSizeLow
= 0;
506 info
->nNumberOfLinks
= 1;
510 info
->nFileSizeHigh
= st
->st_size
>> 32;
511 info
->nFileSizeLow
= (DWORD
)st
->st_size
;
512 info
->nNumberOfLinks
= st
->st_nlink
;
514 info
->nFileIndexHigh
= st
->st_ino
>> 32;
515 info
->nFileIndexLow
= (DWORD
)st
->st_ino
;
519 /***********************************************************************
520 * get_show_dot_files_option
522 static BOOL
get_show_dot_files_option(void)
524 static const WCHAR WineW
[] = {'M','a','c','h','i','n','e','\\',
525 'S','o','f','t','w','a','r','e','\\',
526 'W','i','n','e','\\','W','i','n','e','\\',
527 'C','o','n','f','i','g','\\','W','i','n','e',0};
528 static const WCHAR ShowDotFilesW
[] = {'S','h','o','w','D','o','t','F','i','l','e','s',0};
533 OBJECT_ATTRIBUTES attr
;
534 UNICODE_STRING nameW
;
537 attr
.Length
= sizeof(attr
);
538 attr
.RootDirectory
= 0;
539 attr
.ObjectName
= &nameW
;
541 attr
.SecurityDescriptor
= NULL
;
542 attr
.SecurityQualityOfService
= NULL
;
543 RtlInitUnicodeString( &nameW
, WineW
);
545 if (!NtOpenKey( &hkey
, KEY_ALL_ACCESS
, &attr
))
547 RtlInitUnicodeString( &nameW
, ShowDotFilesW
);
548 if (!NtQueryValueKey( hkey
, &nameW
, KeyValuePartialInformation
, tmp
, sizeof(tmp
), &dummy
))
550 WCHAR
*str
= (WCHAR
*)((KEY_VALUE_PARTIAL_INFORMATION
*)tmp
)->Data
;
551 ret
= IS_OPTION_TRUE( str
[0] );
559 /***********************************************************************
562 * Stat a Unix path name. Return TRUE if OK.
564 BOOL
FILE_Stat( LPCSTR unixName
, BY_HANDLE_FILE_INFORMATION
*info
, BOOL
*is_symlink_ptr
)
570 if (lstat( unixName
, &st
) == -1)
575 is_symlink
= S_ISLNK(st
.st_mode
);
578 /* do a "real" stat to find out
579 about the type of the symlink destination */
580 if (stat( unixName
, &st
) == -1)
587 /* fill in the information we gathered so far */
588 FILE_FillInfo( &st
, info
);
590 /* and now see if this is a hidden file, based on the name */
591 p
= strrchr( unixName
, '/');
592 p
= p
? p
+ 1 : unixName
;
593 if (*p
== '.' && *(p
+1) && (*(p
+1) != '.' || *(p
+2)))
595 static int show_dot_files
= -1;
596 if (show_dot_files
== -1)
597 show_dot_files
= get_show_dot_files_option();
599 info
->dwFileAttributes
|= FILE_ATTRIBUTE_HIDDEN
;
601 if (is_symlink_ptr
) *is_symlink_ptr
= is_symlink
;
606 /***********************************************************************
607 * GetFileInformationByHandle (KERNEL32.@)
609 BOOL WINAPI
GetFileInformationByHandle( HANDLE hFile
, BY_HANDLE_FILE_INFORMATION
*info
)
615 TRACE("%p,%p\n", hFile
, info
);
619 if (!(status
= wine_server_handle_to_fd( hFile
, 0, &fd
, NULL
, NULL
)))
623 if (fstat( fd
, &st
) == -1)
625 else if (!S_ISREG(st
.st_mode
) && !S_ISDIR(st
.st_mode
))
626 SetLastError( ERROR_INVALID_FUNCTION
);
629 FILE_FillInfo( &st
, info
);
632 wine_server_release_fd( hFile
, fd
);
634 else SetLastError( RtlNtStatusToDosError(status
) );
640 /**************************************************************************
641 * GetFileAttributesW (KERNEL32.@)
643 DWORD WINAPI
GetFileAttributesW( LPCWSTR name
)
645 DOS_FULL_NAME full_name
;
646 BY_HANDLE_FILE_INFORMATION info
;
650 SetLastError( ERROR_INVALID_PARAMETER
);
651 return INVALID_FILE_ATTRIBUTES
;
653 if (!DOSFS_GetFullName( name
, TRUE
, &full_name
) )
654 return INVALID_FILE_ATTRIBUTES
;
655 if (!FILE_Stat( full_name
.long_name
, &info
, NULL
))
656 return INVALID_FILE_ATTRIBUTES
;
657 return info
.dwFileAttributes
;
661 /**************************************************************************
662 * GetFileAttributesA (KERNEL32.@)
664 DWORD WINAPI
GetFileAttributesA( LPCSTR name
)
666 UNICODE_STRING nameW
;
667 DWORD ret
= INVALID_FILE_ATTRIBUTES
;
671 SetLastError( ERROR_INVALID_PARAMETER
);
672 return INVALID_FILE_ATTRIBUTES
;
675 if (RtlCreateUnicodeStringFromAsciiz(&nameW
, name
))
677 ret
= GetFileAttributesW(nameW
.Buffer
);
678 RtlFreeUnicodeString(&nameW
);
681 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
686 /**************************************************************************
687 * SetFileAttributesW (KERNEL32.@)
689 BOOL WINAPI
SetFileAttributesW(LPCWSTR lpFileName
, DWORD attributes
)
692 DOS_FULL_NAME full_name
;
696 SetLastError( ERROR_INVALID_PARAMETER
);
700 TRACE("(%s,%lx)\n", debugstr_w(lpFileName
), attributes
);
702 if (!DOSFS_GetFullName( lpFileName
, TRUE
, &full_name
))
705 if(stat(full_name
.long_name
,&buf
)==-1)
710 if (attributes
& FILE_ATTRIBUTE_READONLY
)
712 if(S_ISDIR(buf
.st_mode
))
714 WARN("FILE_ATTRIBUTE_READONLY ignored for directory.\n");
716 buf
.st_mode
&= ~0222; /* octal!, clear write permission bits */
717 attributes
&= ~FILE_ATTRIBUTE_READONLY
;
721 /* add write permission */
722 buf
.st_mode
|= (0600 | ((buf
.st_mode
& 044) >> 1)) & (~FILE_umask
);
724 if (attributes
& FILE_ATTRIBUTE_DIRECTORY
)
726 if (!S_ISDIR(buf
.st_mode
))
727 FIXME("SetFileAttributes expected the file %s to be a directory\n",
728 debugstr_w(lpFileName
));
729 attributes
&= ~FILE_ATTRIBUTE_DIRECTORY
;
731 attributes
&= ~(FILE_ATTRIBUTE_NORMAL
|FILE_ATTRIBUTE_ARCHIVE
|FILE_ATTRIBUTE_HIDDEN
|
732 FILE_ATTRIBUTE_SYSTEM
|FILE_ATTRIBUTE_TEMPORARY
);
734 FIXME("(%s):%lx attribute(s) not implemented.\n", debugstr_w(lpFileName
), attributes
);
735 if (-1==chmod(full_name
.long_name
,buf
.st_mode
))
737 if (GetDriveTypeW(lpFileName
) == DRIVE_CDROM
)
739 SetLastError( ERROR_ACCESS_DENIED
);
744 * FIXME: We don't return FALSE here because of differences between
745 * Linux and Windows privileges. Under Linux only the owner of
746 * the file is allowed to change file attributes. Under Windows,
747 * applications expect that if you can write to a file, you can also
748 * change its attributes (see GENERIC_WRITE). We could try to be
749 * clever here but that would break multi-user installations where
750 * users share read-only DLLs. This is because some installers like
751 * to change attributes of already installed DLLs.
753 FIXME("Couldn't set file attributes for existing file \"%s\".\n"
754 "Check permissions or set VFAT \"quiet\" mount flag\n", full_name
.long_name
);
760 /**************************************************************************
761 * SetFileAttributesA (KERNEL32.@)
763 BOOL WINAPI
SetFileAttributesA(LPCSTR lpFileName
, DWORD attributes
)
765 UNICODE_STRING filenameW
;
770 SetLastError( ERROR_INVALID_PARAMETER
);
774 if (RtlCreateUnicodeStringFromAsciiz(&filenameW
, lpFileName
))
776 ret
= SetFileAttributesW(filenameW
.Buffer
, attributes
);
777 RtlFreeUnicodeString(&filenameW
);
780 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
785 /******************************************************************************
786 * GetCompressedFileSizeA [KERNEL32.@]
788 DWORD WINAPI
GetCompressedFileSizeA(
790 LPDWORD lpFileSizeHigh
)
792 UNICODE_STRING filenameW
;
795 if (RtlCreateUnicodeStringFromAsciiz(&filenameW
, lpFileName
))
797 ret
= GetCompressedFileSizeW(filenameW
.Buffer
, lpFileSizeHigh
);
798 RtlFreeUnicodeString(&filenameW
);
802 ret
= INVALID_FILE_SIZE
;
803 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
809 /******************************************************************************
810 * GetCompressedFileSizeW [KERNEL32.@]
813 * Success: Low-order doubleword of number of bytes
814 * Failure: INVALID_FILE_SIZE
816 DWORD WINAPI
GetCompressedFileSizeW(
817 LPCWSTR lpFileName
, /* [in] Pointer to name of file */
818 LPDWORD lpFileSizeHigh
) /* [out] Receives high-order doubleword of size */
820 DOS_FULL_NAME full_name
;
824 TRACE("(%s,%p)\n",debugstr_w(lpFileName
),lpFileSizeHigh
);
826 if (!DOSFS_GetFullName( lpFileName
, TRUE
, &full_name
)) return INVALID_FILE_SIZE
;
827 if (stat(full_name
.long_name
, &st
) != 0)
830 return INVALID_FILE_SIZE
;
832 #if HAVE_STRUCT_STAT_ST_BLOCKS
833 /* blocks are 512 bytes long */
834 if (lpFileSizeHigh
) *lpFileSizeHigh
= (st
.st_blocks
>> 23);
835 low
= (DWORD
)(st
.st_blocks
<< 9);
837 if (lpFileSizeHigh
) *lpFileSizeHigh
= (st
.st_size
>> 32);
838 low
= (DWORD
)st
.st_size
;
844 /***********************************************************************
845 * GetFileTime (KERNEL32.@)
847 BOOL WINAPI
GetFileTime( HANDLE hFile
, FILETIME
*lpCreationTime
,
848 FILETIME
*lpLastAccessTime
,
849 FILETIME
*lpLastWriteTime
)
851 BY_HANDLE_FILE_INFORMATION info
;
852 if (!GetFileInformationByHandle( hFile
, &info
)) return FALSE
;
853 if (lpCreationTime
) *lpCreationTime
= info
.ftCreationTime
;
854 if (lpLastAccessTime
) *lpLastAccessTime
= info
.ftLastAccessTime
;
855 if (lpLastWriteTime
) *lpLastWriteTime
= info
.ftLastWriteTime
;
860 /***********************************************************************
861 * GetTempFileNameA (KERNEL32.@)
863 UINT WINAPI
GetTempFileNameA( LPCSTR path
, LPCSTR prefix
, UINT unique
,
866 UNICODE_STRING pathW
, prefixW
;
867 WCHAR bufferW
[MAX_PATH
];
870 if ( !path
|| !prefix
|| !buffer
)
872 SetLastError( ERROR_INVALID_PARAMETER
);
876 RtlCreateUnicodeStringFromAsciiz(&pathW
, path
);
877 RtlCreateUnicodeStringFromAsciiz(&prefixW
, prefix
);
879 ret
= GetTempFileNameW(pathW
.Buffer
, prefixW
.Buffer
, unique
, bufferW
);
881 WideCharToMultiByte(CP_ACP
, 0, bufferW
, -1, buffer
, MAX_PATH
, NULL
, NULL
);
883 RtlFreeUnicodeString(&pathW
);
884 RtlFreeUnicodeString(&prefixW
);
888 /***********************************************************************
889 * GetTempFileNameW (KERNEL32.@)
891 UINT WINAPI
GetTempFileNameW( LPCWSTR path
, LPCWSTR prefix
, UINT unique
,
894 static const WCHAR formatW
[] = {'%','x','.','t','m','p',0};
896 DOS_FULL_NAME full_name
;
900 if ( !path
|| !prefix
|| !buffer
)
902 SetLastError( ERROR_INVALID_PARAMETER
);
906 strcpyW( buffer
, path
);
907 p
= buffer
+ strlenW(buffer
);
909 /* add a \, if there isn't one */
910 if ((p
== buffer
) || (p
[-1] != '\\')) *p
++ = '\\';
912 for (i
= 3; (i
> 0) && (*prefix
); i
--) *p
++ = *prefix
++;
916 if (unique
) sprintfW( p
, formatW
, unique
);
919 /* get a "random" unique number and try to create the file */
921 UINT num
= GetTickCount() & 0xffff;
927 sprintfW( p
, formatW
, unique
);
928 handle
= CreateFileW( buffer
, GENERIC_WRITE
, 0, NULL
,
929 CREATE_NEW
, FILE_ATTRIBUTE_NORMAL
, 0 );
930 if (handle
!= INVALID_HANDLE_VALUE
)
931 { /* We created it */
932 TRACE("created %s\n", debugstr_w(buffer
) );
933 CloseHandle( handle
);
936 if (GetLastError() != ERROR_FILE_EXISTS
&&
937 GetLastError() != ERROR_SHARING_VIOLATION
)
938 break; /* No need to go on */
939 if (!(++unique
& 0xffff)) unique
= 1;
940 } while (unique
!= num
);
943 /* Get the full path name */
945 if (DOSFS_GetFullName( buffer
, FALSE
, &full_name
))
948 /* Check if we have write access in the directory */
949 if ((slash
= strrchr( full_name
.long_name
, '/' ))) *slash
= '\0';
950 if (access( full_name
.long_name
, W_OK
) == -1)
951 WARN("returns %s, which doesn't seem to be writeable.\n",
952 debugstr_w(buffer
) );
954 TRACE("returning %s\n", debugstr_w(buffer
) );
959 /******************************************************************
960 * FILE_ReadWriteApc (internal)
964 static void WINAPI
FILE_ReadWriteApc(void* apc_user
, PIO_STATUS_BLOCK io_status
, ULONG len
)
966 LPOVERLAPPED_COMPLETION_ROUTINE cr
= (LPOVERLAPPED_COMPLETION_ROUTINE
)apc_user
;
968 cr(RtlNtStatusToDosError(io_status
->u
.Status
), len
, (LPOVERLAPPED
)io_status
);
971 /***********************************************************************
972 * ReadFileEx (KERNEL32.@)
974 BOOL WINAPI
ReadFileEx(HANDLE hFile
, LPVOID buffer
, DWORD bytesToRead
,
975 LPOVERLAPPED overlapped
,
976 LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine
)
978 LARGE_INTEGER offset
;
980 PIO_STATUS_BLOCK io_status
;
984 SetLastError(ERROR_INVALID_PARAMETER
);
988 offset
.u
.LowPart
= overlapped
->Offset
;
989 offset
.u
.HighPart
= overlapped
->OffsetHigh
;
990 io_status
= (PIO_STATUS_BLOCK
)overlapped
;
991 io_status
->u
.Status
= STATUS_PENDING
;
993 status
= NtReadFile(hFile
, NULL
, FILE_ReadWriteApc
, lpCompletionRoutine
,
994 io_status
, buffer
, bytesToRead
, &offset
, NULL
);
998 SetLastError( RtlNtStatusToDosError(status
) );
1004 /***********************************************************************
1005 * ReadFile (KERNEL32.@)
1007 BOOL WINAPI
ReadFile( HANDLE hFile
, LPVOID buffer
, DWORD bytesToRead
,
1008 LPDWORD bytesRead
, LPOVERLAPPED overlapped
)
1010 LARGE_INTEGER offset
;
1011 PLARGE_INTEGER poffset
= NULL
;
1012 IO_STATUS_BLOCK iosb
;
1013 PIO_STATUS_BLOCK io_status
= &iosb
;
1017 TRACE("%p %p %ld %p %p\n", hFile
, buffer
, bytesToRead
,
1018 bytesRead
, overlapped
);
1020 if (bytesRead
) *bytesRead
= 0; /* Do this before anything else */
1021 if (!bytesToRead
) return TRUE
;
1023 if (IsBadReadPtr(buffer
, bytesToRead
))
1025 SetLastError(ERROR_WRITE_FAULT
); /* FIXME */
1028 if (is_console_handle(hFile
))
1029 return ReadConsoleA(hFile
, buffer
, bytesToRead
, bytesRead
, NULL
);
1031 if (overlapped
!= NULL
)
1033 offset
.u
.LowPart
= overlapped
->Offset
;
1034 offset
.u
.HighPart
= overlapped
->OffsetHigh
;
1036 hEvent
= overlapped
->hEvent
;
1037 io_status
= (PIO_STATUS_BLOCK
)overlapped
;
1039 io_status
->u
.Status
= STATUS_PENDING
;
1040 io_status
->Information
= 0;
1042 status
= NtReadFile(hFile
, hEvent
, NULL
, NULL
, io_status
, buffer
, bytesToRead
, poffset
, NULL
);
1044 if (status
!= STATUS_PENDING
&& bytesRead
)
1045 *bytesRead
= io_status
->Information
;
1047 if (status
&& status
!= STATUS_END_OF_FILE
)
1049 SetLastError( RtlNtStatusToDosError(status
) );
1056 /***********************************************************************
1057 * WriteFileEx (KERNEL32.@)
1059 BOOL WINAPI
WriteFileEx(HANDLE hFile
, LPCVOID buffer
, DWORD bytesToWrite
,
1060 LPOVERLAPPED overlapped
,
1061 LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine
)
1063 LARGE_INTEGER offset
;
1065 PIO_STATUS_BLOCK io_status
;
1067 TRACE("%p %p %ld %p %p\n",
1068 hFile
, buffer
, bytesToWrite
, overlapped
, lpCompletionRoutine
);
1070 if (overlapped
== NULL
)
1072 SetLastError(ERROR_INVALID_PARAMETER
);
1075 offset
.u
.LowPart
= overlapped
->Offset
;
1076 offset
.u
.HighPart
= overlapped
->OffsetHigh
;
1078 io_status
= (PIO_STATUS_BLOCK
)overlapped
;
1079 io_status
->u
.Status
= STATUS_PENDING
;
1081 status
= NtWriteFile(hFile
, NULL
, FILE_ReadWriteApc
, lpCompletionRoutine
,
1082 io_status
, buffer
, bytesToWrite
, &offset
, NULL
);
1084 if (status
) SetLastError( RtlNtStatusToDosError(status
) );
1088 /***********************************************************************
1089 * WriteFile (KERNEL32.@)
1091 BOOL WINAPI
WriteFile( HANDLE hFile
, LPCVOID buffer
, DWORD bytesToWrite
,
1092 LPDWORD bytesWritten
, LPOVERLAPPED overlapped
)
1094 HANDLE hEvent
= NULL
;
1095 LARGE_INTEGER offset
;
1096 PLARGE_INTEGER poffset
= NULL
;
1098 IO_STATUS_BLOCK iosb
;
1099 PIO_STATUS_BLOCK piosb
= &iosb
;
1101 TRACE("%p %p %ld %p %p\n",
1102 hFile
, buffer
, bytesToWrite
, bytesWritten
, overlapped
);
1104 if (is_console_handle(hFile
))
1105 return WriteConsoleA(hFile
, buffer
, bytesToWrite
, bytesWritten
, NULL
);
1107 if (IsBadReadPtr(buffer
, bytesToWrite
))
1109 SetLastError(ERROR_READ_FAULT
); /* FIXME */
1115 offset
.u
.LowPart
= overlapped
->Offset
;
1116 offset
.u
.HighPart
= overlapped
->OffsetHigh
;
1118 hEvent
= overlapped
->hEvent
;
1119 piosb
= (PIO_STATUS_BLOCK
)overlapped
;
1121 piosb
->u
.Status
= STATUS_PENDING
;
1122 piosb
->Information
= 0;
1124 status
= NtWriteFile(hFile
, hEvent
, NULL
, NULL
, piosb
,
1125 buffer
, bytesToWrite
, poffset
, NULL
);
1128 SetLastError( RtlNtStatusToDosError(status
) );
1131 if (bytesWritten
) *bytesWritten
= piosb
->Information
;
1137 /***********************************************************************
1138 * SetFilePointer (KERNEL32.@)
1140 DWORD WINAPI
SetFilePointer( HANDLE hFile
, LONG distance
, LONG
*highword
,
1143 static const int whence
[3] = { SEEK_SET
, SEEK_CUR
, SEEK_END
};
1144 DWORD ret
= INVALID_SET_FILE_POINTER
;
1148 TRACE("handle %p offset %ld high %ld origin %ld\n",
1149 hFile
, distance
, highword
?*highword
:0, method
);
1151 if (method
> FILE_END
)
1153 SetLastError( ERROR_INVALID_PARAMETER
);
1157 if (!(status
= wine_server_handle_to_fd( hFile
, 0, &fd
, NULL
, NULL
)))
1161 if (highword
) pos
= ((off_t
)*highword
<< 32) | (ULONG
)distance
;
1162 else pos
= (off_t
)distance
;
1163 if ((res
= lseek( fd
, pos
, whence
[method
] )) == (off_t
)-1)
1165 /* also check EPERM due to SuSE7 2.2.16 lseek() EPERM kernel bug */
1166 if (((errno
== EINVAL
) || (errno
== EPERM
)) && (method
!= FILE_BEGIN
) && (pos
< 0))
1167 SetLastError( ERROR_NEGATIVE_SEEK
);
1174 if (highword
) *highword
= (res
>> 32);
1175 if (ret
== INVALID_SET_FILE_POINTER
) SetLastError( 0 );
1177 wine_server_release_fd( hFile
, fd
);
1179 else SetLastError( RtlNtStatusToDosError(status
) );
1185 /*************************************************************************
1186 * SetHandleCount (KERNEL32.@)
1188 UINT WINAPI
SetHandleCount( UINT count
)
1190 return min( 256, count
);
1194 /**************************************************************************
1195 * SetEndOfFile (KERNEL32.@)
1197 BOOL WINAPI
SetEndOfFile( HANDLE hFile
)
1200 SERVER_START_REQ( truncate_file
)
1202 req
->handle
= hFile
;
1203 ret
= !wine_server_call_err( req
);
1210 /***********************************************************************
1211 * GetFileType (KERNEL32.@)
1213 DWORD WINAPI
GetFileType( HANDLE hFile
)
1217 DWORD ret
= FILE_TYPE_UNKNOWN
;
1219 if (is_console_handle( hFile
))
1220 return FILE_TYPE_CHAR
;
1222 if (!(status
= wine_server_handle_to_fd( hFile
, 0, &fd
, NULL
, NULL
)))
1226 if (fstat( fd
, &st
) == -1)
1228 else if (S_ISFIFO(st
.st_mode
) || S_ISSOCK(st
.st_mode
))
1229 ret
= FILE_TYPE_PIPE
;
1230 else if (S_ISCHR(st
.st_mode
))
1231 ret
= FILE_TYPE_CHAR
;
1233 ret
= FILE_TYPE_DISK
;
1234 wine_server_release_fd( hFile
, fd
);
1236 else SetLastError( RtlNtStatusToDosError(status
) );
1242 /* check if a file name is for an executable file (.exe or .com) */
1243 inline static BOOL
is_executable( const char *name
)
1245 int len
= strlen(name
);
1247 if (len
< 4) return FALSE
;
1248 return (!strcasecmp( name
+ len
- 4, ".exe" ) ||
1249 !strcasecmp( name
+ len
- 4, ".com" ));
1253 /***********************************************************************
1254 * FILE_AddBootRenameEntry
1256 * Adds an entry to the registry that is loaded when windows boots and
1257 * checks if there are some files to be removed or renamed/moved.
1258 * <fn1> has to be valid and <fn2> may be NULL. If both pointers are
1259 * non-NULL then the file is moved, otherwise it is deleted. The
1260 * entry of the registrykey is always appended with two zero
1261 * terminated strings. If <fn2> is NULL then the second entry is
1262 * simply a single 0-byte. Otherwise the second filename goes
1263 * there. The entries are prepended with \??\ before the path and the
1264 * second filename gets also a '!' as the first character if
1265 * MOVEFILE_REPLACE_EXISTING is set. After the final string another
1266 * 0-byte follows to indicate the end of the strings.
1268 * \??\D:\test\file1[0]
1269 * !\??\D:\test\file1_renamed[0]
1270 * \??\D:\Test|delete[0]
1271 * [0] <- file is to be deleted, second string empty
1272 * \??\D:\test\file2[0]
1273 * !\??\D:\test\file2_renamed[0]
1274 * [0] <- indicates end of strings
1277 * \??\D:\test\file1[0]
1278 * !\??\D:\test\file1_renamed[0]
1279 * \??\D:\Test|delete[0]
1280 * [0] <- file is to be deleted, second string empty
1281 * [0] <- indicates end of strings
1284 static BOOL
FILE_AddBootRenameEntry( LPCWSTR fn1
, LPCWSTR fn2
, DWORD flags
)
1286 static const WCHAR PreString
[] = {'\\','?','?','\\',0};
1287 static const WCHAR ValueName
[] = {'P','e','n','d','i','n','g',
1288 'F','i','l','e','R','e','n','a','m','e',
1289 'O','p','e','r','a','t','i','o','n','s',0};
1290 static const WCHAR SessionW
[] = {'M','a','c','h','i','n','e','\\',
1291 'S','y','s','t','e','m','\\',
1292 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
1293 'C','o','n','t','r','o','l','\\',
1294 'S','e','s','s','i','o','n',' ','M','a','n','a','g','e','r',0};
1295 static const int info_size
= FIELD_OFFSET( KEY_VALUE_PARTIAL_INFORMATION
, Data
);
1297 OBJECT_ATTRIBUTES attr
;
1298 UNICODE_STRING nameW
;
1299 KEY_VALUE_PARTIAL_INFORMATION
*info
;
1302 DWORD len0
, len1
, len2
;
1304 BYTE
*Buffer
= NULL
;
1307 attr
.Length
= sizeof(attr
);
1308 attr
.RootDirectory
= 0;
1309 attr
.ObjectName
= &nameW
;
1310 attr
.Attributes
= 0;
1311 attr
.SecurityDescriptor
= NULL
;
1312 attr
.SecurityQualityOfService
= NULL
;
1313 RtlInitUnicodeString( &nameW
, SessionW
);
1315 if (NtCreateKey( &Reboot
, KEY_ALL_ACCESS
, &attr
, 0, NULL
, 0, NULL
) != STATUS_SUCCESS
)
1317 WARN("Error creating key for reboot managment [%s]\n",
1318 "SYSTEM\\CurrentControlSet\\Control\\Session Manager");
1322 len0
= strlenW(PreString
);
1323 len1
= strlenW(fn1
) + len0
+ 1;
1326 len2
= strlenW(fn2
) + len0
+ 1;
1327 if (flags
& MOVEFILE_REPLACE_EXISTING
) len2
++; /* Plus 1 because of the leading '!' */
1329 else len2
= 1; /* minimum is the 0 characters for the empty second string */
1331 /* convert characters to bytes */
1332 len0
*= sizeof(WCHAR
);
1333 len1
*= sizeof(WCHAR
);
1334 len2
*= sizeof(WCHAR
);
1336 RtlInitUnicodeString( &nameW
, ValueName
);
1338 /* First we check if the key exists and if so how many bytes it already contains. */
1339 if (NtQueryValueKey( Reboot
, &nameW
, KeyValuePartialInformation
,
1340 NULL
, 0, &DataSize
) == STATUS_BUFFER_OVERFLOW
)
1342 if (!(Buffer
= HeapAlloc( GetProcessHeap(), 0, DataSize
+ len1
+ len2
+ sizeof(WCHAR
) )))
1344 if (NtQueryValueKey( Reboot
, &nameW
, KeyValuePartialInformation
,
1345 Buffer
, DataSize
, &DataSize
)) goto Quit
;
1346 info
= (KEY_VALUE_PARTIAL_INFORMATION
*)Buffer
;
1347 if (info
->Type
!= REG_MULTI_SZ
) goto Quit
;
1348 if (DataSize
> sizeof(info
)) DataSize
-= sizeof(WCHAR
); /* remove terminating null (will be added back later) */
1352 DataSize
= info_size
;
1353 if (!(Buffer
= HeapAlloc( GetProcessHeap(), 0, DataSize
+ len1
+ len2
+ sizeof(WCHAR
) )))
1357 p
= (WCHAR
*)(Buffer
+ DataSize
);
1358 strcpyW( p
, PreString
);
1363 p
= (WCHAR
*)(Buffer
+ DataSize
);
1364 if (flags
& MOVEFILE_REPLACE_EXISTING
)
1366 strcpyW( p
, PreString
);
1372 p
= (WCHAR
*)(Buffer
+ DataSize
);
1374 DataSize
+= sizeof(WCHAR
);
1377 /* add final null */
1378 p
= (WCHAR
*)(Buffer
+ DataSize
);
1380 DataSize
+= sizeof(WCHAR
);
1382 rc
= !NtSetValueKey(Reboot
, &nameW
, 0, REG_MULTI_SZ
, Buffer
+ info_size
, DataSize
- info_size
);
1385 if (Reboot
) NtClose(Reboot
);
1386 if (Buffer
) HeapFree( GetProcessHeap(), 0, Buffer
);
1391 /**************************************************************************
1392 * MoveFileExW (KERNEL32.@)
1394 BOOL WINAPI
MoveFileExW( LPCWSTR fn1
, LPCWSTR fn2
, DWORD flag
)
1396 DOS_FULL_NAME full_name1
, full_name2
;
1398 DWORD attr
= INVALID_FILE_ATTRIBUTES
;
1400 TRACE("(%s,%s,%04lx)\n", debugstr_w(fn1
), debugstr_w(fn2
), flag
);
1402 /* FIXME: <Gerhard W. Gruber>sparhawk@gmx.at
1403 In case of W9x and lesser this function should return 120 (ERROR_CALL_NOT_IMPLEMENTED)
1404 to be really compatible. Most programs won't have any problems though. In case
1405 you encounter one, this is what you should return here. I don't know what's up
1406 with NT 3.5. Is this function available there or not?
1407 Does anybody really care about 3.5? :)
1410 /* Filename1 has to be always set to a valid path. Filename2 may be NULL
1411 if the source file has to be deleted.
1414 SetLastError(ERROR_INVALID_PARAMETER
);
1418 /* This function has to be run through in order to process the name properly.
1419 If the BOOTDELAY flag is set, the file doesn't need to exist though. At least
1420 that is the behaviour on NT 4.0. The operation accepts the filenames as
1421 they are given but it can't reply with a reasonable returncode. Success
1422 means in that case success for entering the values into the registry.
1424 if(!DOSFS_GetFullName( fn1
, TRUE
, &full_name1
))
1426 if(!(flag
& MOVEFILE_DELAY_UNTIL_REBOOT
))
1430 if (fn2
) /* !fn2 means delete fn1 */
1432 if (DOSFS_GetFullName( fn2
, TRUE
, &full_name2
))
1434 if(!(flag
& MOVEFILE_DELAY_UNTIL_REBOOT
))
1436 /* target exists, check if we may overwrite */
1437 if (!(flag
& MOVEFILE_REPLACE_EXISTING
))
1439 SetLastError( ERROR_ALREADY_EXISTS
);
1446 if (!DOSFS_GetFullName( fn2
, FALSE
, &full_name2
))
1448 if(!(flag
& MOVEFILE_DELAY_UNTIL_REBOOT
))
1453 /* Source name and target path are valid */
1455 if (flag
& MOVEFILE_DELAY_UNTIL_REBOOT
)
1457 return FILE_AddBootRenameEntry( fn1
, fn2
, flag
);
1460 attr
= GetFileAttributesW( fn1
);
1461 if ( attr
== INVALID_FILE_ATTRIBUTES
) return FALSE
;
1463 /* check if we are allowed to rename the source */
1464 hFile
= FILE_CreateFile( full_name1
.long_name
, 0, 0,
1465 NULL
, OPEN_EXISTING
, 0, 0 );
1468 if (GetLastError() != ERROR_ACCESS_DENIED
) return FALSE
;
1469 if ( !(attr
& FILE_ATTRIBUTE_DIRECTORY
) ) return FALSE
;
1470 /* if it's a directory we can continue */
1472 else CloseHandle(hFile
);
1474 /* check, if we are allowed to delete the destination,
1475 ** (but the file not being there is fine) */
1476 hFile
= FILE_CreateFile( full_name2
.long_name
, GENERIC_READ
|GENERIC_WRITE
, 0,
1477 NULL
, OPEN_EXISTING
, 0, 0 );
1478 if(!hFile
&& GetLastError() != ERROR_FILE_NOT_FOUND
) return FALSE
;
1481 if (full_name1
.drive
!= full_name2
.drive
)
1483 if (!(flag
& MOVEFILE_COPY_ALLOWED
))
1485 SetLastError( ERROR_NOT_SAME_DEVICE
);
1488 else if ( attr
& FILE_ATTRIBUTE_DIRECTORY
)
1490 /* Strange, but that's what Windows returns */
1491 SetLastError ( ERROR_ACCESS_DENIED
);
1495 if (rename( full_name1
.long_name
, full_name2
.long_name
) == -1)
1496 /* Try copy/delete unless it's a directory. */
1497 /* FIXME: This does not handle the (unlikely) case that the two locations
1498 are on the same Wine drive, but on different Unix file systems. */
1500 if ( attr
& FILE_ATTRIBUTE_DIRECTORY
)
1507 if ( ! CopyFileW( fn1
, fn2
, !(flag
& MOVEFILE_REPLACE_EXISTING
) ))
1509 if ( ! DeleteFileW ( fn1
) )
1513 if (is_executable( full_name1
.long_name
) != is_executable( full_name2
.long_name
))
1516 if (stat( full_name2
.long_name
, &fstat
) != -1)
1518 if (is_executable( full_name2
.long_name
))
1519 /* set executable bit where read bit is set */
1520 fstat
.st_mode
|= (fstat
.st_mode
& 0444) >> 2;
1522 fstat
.st_mode
&= ~0111;
1523 chmod( full_name2
.long_name
, fstat
.st_mode
);
1528 else /* fn2 == NULL means delete source */
1530 if (flag
& MOVEFILE_DELAY_UNTIL_REBOOT
)
1532 if (flag
& MOVEFILE_COPY_ALLOWED
) {
1533 WARN("Illegal flag\n");
1534 SetLastError( ERROR_GEN_FAILURE
);
1538 return FILE_AddBootRenameEntry( fn1
, NULL
, flag
);
1541 if (unlink( full_name1
.long_name
) == -1)
1546 return TRUE
; /* successfully deleted */
1550 /**************************************************************************
1551 * MoveFileExA (KERNEL32.@)
1553 BOOL WINAPI
MoveFileExA( LPCSTR fn1
, LPCSTR fn2
, DWORD flag
)
1555 UNICODE_STRING fn1W
, fn2W
;
1560 SetLastError(ERROR_INVALID_PARAMETER
);
1564 RtlCreateUnicodeStringFromAsciiz(&fn1W
, fn1
);
1565 if (fn2
) RtlCreateUnicodeStringFromAsciiz(&fn2W
, fn2
);
1566 else fn2W
.Buffer
= NULL
;
1568 ret
= MoveFileExW( fn1W
.Buffer
, fn2W
.Buffer
, flag
);
1570 RtlFreeUnicodeString(&fn1W
);
1571 RtlFreeUnicodeString(&fn2W
);
1576 /**************************************************************************
1577 * MoveFileW (KERNEL32.@)
1579 * Move file or directory
1581 BOOL WINAPI
MoveFileW( LPCWSTR fn1
, LPCWSTR fn2
)
1583 return MoveFileExW( fn1
, fn2
, MOVEFILE_COPY_ALLOWED
);
1587 /**************************************************************************
1588 * MoveFileA (KERNEL32.@)
1590 BOOL WINAPI
MoveFileA( LPCSTR fn1
, LPCSTR fn2
)
1592 return MoveFileExA( fn1
, fn2
, MOVEFILE_COPY_ALLOWED
);
1596 /**************************************************************************
1597 * CopyFileW (KERNEL32.@)
1599 BOOL WINAPI
CopyFileW( LPCWSTR source
, LPCWSTR dest
, BOOL fail_if_exists
)
1602 BY_HANDLE_FILE_INFORMATION info
;
1607 if (!source
|| !dest
)
1609 SetLastError(ERROR_INVALID_PARAMETER
);
1613 TRACE("%s -> %s\n", debugstr_w(source
), debugstr_w(dest
));
1615 if ((h1
= CreateFileW(source
, GENERIC_READ
, FILE_SHARE_READ
| FILE_SHARE_WRITE
,
1616 NULL
, OPEN_EXISTING
, 0, 0)) == INVALID_HANDLE_VALUE
)
1618 WARN("Unable to open source %s\n", debugstr_w(source
));
1622 if (!GetFileInformationByHandle( h1
, &info
))
1624 WARN("GetFileInformationByHandle returned error for %s\n", debugstr_w(source
));
1629 if ((h2
= CreateFileW( dest
, GENERIC_WRITE
, FILE_SHARE_READ
| FILE_SHARE_WRITE
, NULL
,
1630 fail_if_exists
? CREATE_NEW
: CREATE_ALWAYS
,
1631 info
.dwFileAttributes
, h1
)) == INVALID_HANDLE_VALUE
)
1633 WARN("Unable to open dest %s\n", debugstr_w(dest
));
1638 while (ReadFile( h1
, buffer
, sizeof(buffer
), &count
, NULL
) && count
)
1644 if (!WriteFile( h2
, p
, count
, &res
, NULL
) || !res
) goto done
;
1657 /**************************************************************************
1658 * CopyFileA (KERNEL32.@)
1660 BOOL WINAPI
CopyFileA( LPCSTR source
, LPCSTR dest
, BOOL fail_if_exists
)
1662 UNICODE_STRING sourceW
, destW
;
1665 if (!source
|| !dest
)
1667 SetLastError(ERROR_INVALID_PARAMETER
);
1671 RtlCreateUnicodeStringFromAsciiz(&sourceW
, source
);
1672 RtlCreateUnicodeStringFromAsciiz(&destW
, dest
);
1674 ret
= CopyFileW(sourceW
.Buffer
, destW
.Buffer
, fail_if_exists
);
1676 RtlFreeUnicodeString(&sourceW
);
1677 RtlFreeUnicodeString(&destW
);
1682 /**************************************************************************
1683 * CopyFileExW (KERNEL32.@)
1685 * This implementation ignores most of the extra parameters passed-in into
1686 * the "ex" version of the method and calls the CopyFile method.
1687 * It will have to be fixed eventually.
1689 BOOL WINAPI
CopyFileExW(LPCWSTR sourceFilename
, LPCWSTR destFilename
,
1690 LPPROGRESS_ROUTINE progressRoutine
, LPVOID appData
,
1691 LPBOOL cancelFlagPointer
, DWORD copyFlags
)
1694 * Interpret the only flag that CopyFile can interpret.
1696 return CopyFileW(sourceFilename
, destFilename
, (copyFlags
& COPY_FILE_FAIL_IF_EXISTS
) != 0);
1700 /**************************************************************************
1701 * CopyFileExA (KERNEL32.@)
1703 BOOL WINAPI
CopyFileExA(LPCSTR sourceFilename
, LPCSTR destFilename
,
1704 LPPROGRESS_ROUTINE progressRoutine
, LPVOID appData
,
1705 LPBOOL cancelFlagPointer
, DWORD copyFlags
)
1707 UNICODE_STRING sourceW
, destW
;
1710 if (!sourceFilename
|| !destFilename
)
1712 SetLastError(ERROR_INVALID_PARAMETER
);
1716 RtlCreateUnicodeStringFromAsciiz(&sourceW
, sourceFilename
);
1717 RtlCreateUnicodeStringFromAsciiz(&destW
, destFilename
);
1719 ret
= CopyFileExW(sourceW
.Buffer
, destW
.Buffer
, progressRoutine
, appData
,
1720 cancelFlagPointer
, copyFlags
);
1722 RtlFreeUnicodeString(&sourceW
);
1723 RtlFreeUnicodeString(&destW
);
1728 /***********************************************************************
1729 * SetFileTime (KERNEL32.@)
1731 BOOL WINAPI
SetFileTime( HANDLE hFile
,
1732 const FILETIME
*ctime
,
1733 const FILETIME
*atime
,
1734 const FILETIME
*mtime
)
1740 if (!(status
= wine_server_handle_to_fd( hFile
, GENERIC_WRITE
, &fd
, NULL
, NULL
)))
1743 ULONGLONG sec
, nsec
;
1744 struct timeval tv
[2];
1746 if (!atime
|| !mtime
)
1750 tv
[0].tv_sec
= tv
[0].tv_usec
= 0;
1751 tv
[1].tv_sec
= tv
[1].tv_usec
= 0;
1752 if (!fstat( fd
, &st
))
1754 tv
[0].tv_sec
= st
.st_atime
;
1755 tv
[1].tv_sec
= st
.st_mtime
;
1760 sec
= ((ULONGLONG
)atime
->dwHighDateTime
<< 32) | atime
->dwLowDateTime
;
1761 sec
= RtlLargeIntegerDivide( sec
, 10000000, &nsec
);
1762 tv
[0].tv_sec
= sec
- SECS_1601_TO_1970
;
1763 tv
[0].tv_usec
= (UINT
)nsec
/ 10;
1767 sec
= ((ULONGLONG
)mtime
->dwHighDateTime
<< 32) | mtime
->dwLowDateTime
;
1768 sec
= RtlLargeIntegerDivide( sec
, 10000000, &nsec
);
1769 tv
[1].tv_sec
= sec
- SECS_1601_TO_1970
;
1770 tv
[1].tv_usec
= (UINT
)nsec
/ 10;
1773 if (!futimes( fd
, tv
)) ret
= TRUE
;
1774 else FILE_SetDosError();
1776 ret
= TRUE
; /* pretend it succeeded */
1778 wine_server_release_fd( hFile
, fd
);
1780 else SetLastError( RtlNtStatusToDosError(status
) );
1785 /**************************************************************************
1786 * GetFileAttributesExW (KERNEL32.@)
1788 BOOL WINAPI
GetFileAttributesExW(
1789 LPCWSTR lpFileName
, GET_FILEEX_INFO_LEVELS fInfoLevelId
,
1790 LPVOID lpFileInformation
)
1792 DOS_FULL_NAME full_name
;
1793 BY_HANDLE_FILE_INFORMATION info
;
1795 if (!lpFileName
|| !lpFileInformation
)
1797 SetLastError(ERROR_INVALID_PARAMETER
);
1801 if (fInfoLevelId
== GetFileExInfoStandard
) {
1802 LPWIN32_FILE_ATTRIBUTE_DATA lpFad
=
1803 (LPWIN32_FILE_ATTRIBUTE_DATA
) lpFileInformation
;
1804 if (!DOSFS_GetFullName( lpFileName
, TRUE
, &full_name
)) return FALSE
;
1805 if (!FILE_Stat( full_name
.long_name
, &info
, NULL
)) return FALSE
;
1807 lpFad
->dwFileAttributes
= info
.dwFileAttributes
;
1808 lpFad
->ftCreationTime
= info
.ftCreationTime
;
1809 lpFad
->ftLastAccessTime
= info
.ftLastAccessTime
;
1810 lpFad
->ftLastWriteTime
= info
.ftLastWriteTime
;
1811 lpFad
->nFileSizeHigh
= info
.nFileSizeHigh
;
1812 lpFad
->nFileSizeLow
= info
.nFileSizeLow
;
1815 FIXME("invalid info level %d!\n", fInfoLevelId
);
1823 /**************************************************************************
1824 * GetFileAttributesExA (KERNEL32.@)
1826 BOOL WINAPI
GetFileAttributesExA(
1827 LPCSTR filename
, GET_FILEEX_INFO_LEVELS fInfoLevelId
,
1828 LPVOID lpFileInformation
)
1830 UNICODE_STRING filenameW
;
1833 if (!filename
|| !lpFileInformation
)
1835 SetLastError(ERROR_INVALID_PARAMETER
);
1839 if (RtlCreateUnicodeStringFromAsciiz(&filenameW
, filename
))
1841 ret
= GetFileAttributesExW(filenameW
.Buffer
, fInfoLevelId
, lpFileInformation
);
1842 RtlFreeUnicodeString(&filenameW
);
1845 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);