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, UINT drive_type
)
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 req
->removable
= (drive_type
== DRIVE_REMOVABLE
|| drive_type
== DRIVE_CDROM
);
224 wine_server_add_data( req
, filename
, strlen(filename
) );
226 err
= wine_server_call( req
);
233 /* In the case file creation was rejected due to CREATE_NEW flag
234 * was specified and file with that name already exists, correct
235 * last error is ERROR_FILE_EXISTS and not ERROR_ALREADY_EXISTS.
236 * Note: RtlNtStatusToDosError is not the subject to blame here.
238 if (err
== STATUS_OBJECT_NAME_COLLISION
)
239 SetLastError( ERROR_FILE_EXISTS
);
241 SetLastError( RtlNtStatusToDosError(err
) );
244 if (!ret
) WARN("Unable to create file '%s' (GLE %ld)\n", filename
, GetLastError());
249 static HANDLE
FILE_OpenPipe(LPCWSTR name
, DWORD access
, LPSECURITY_ATTRIBUTES sa
)
254 if (name
&& (len
= strlenW(name
)) > MAX_PATH
)
256 SetLastError( ERROR_FILENAME_EXCED_RANGE
);
259 SERVER_START_REQ( open_named_pipe
)
261 req
->access
= access
;
262 req
->inherit
= (sa
&& (sa
->nLength
>=sizeof(*sa
)) && sa
->bInheritHandle
);
264 wine_server_add_data( req
, name
, len
* sizeof(WCHAR
) );
265 wine_server_call_err( req
);
269 TRACE("Returned %p\n",ret
);
273 /*************************************************************************
274 * CreateFileW [KERNEL32.@] Creates or opens a file or other object
276 * Creates or opens an object, and returns a handle that can be used to
277 * access that object.
281 * filename [in] pointer to filename to be accessed
282 * access [in] access mode requested
283 * sharing [in] share mode
284 * sa [in] pointer to security attributes
285 * creation [in] how to create the file
286 * attributes [in] attributes for newly created file
287 * template [in] handle to file with extended attributes to copy
290 * Success: Open handle to specified file
291 * Failure: INVALID_HANDLE_VALUE
294 * Should call SetLastError() on failure.
298 * Doesn't support character devices, template files, or a
299 * lot of the 'attributes' flags yet.
301 HANDLE WINAPI
CreateFileW( LPCWSTR filename
, DWORD access
, DWORD sharing
,
302 LPSECURITY_ATTRIBUTES sa
, DWORD creation
,
303 DWORD attributes
, HANDLE
template )
305 DOS_FULL_NAME full_name
;
308 static const WCHAR bkslashes_with_question_markW
[] = {'\\','\\','?','\\',0};
309 static const WCHAR bkslashes_with_dotW
[] = {'\\','\\','.','\\',0};
310 static const WCHAR bkslashesW
[] = {'\\','\\',0};
311 static const WCHAR coninW
[] = {'C','O','N','I','N','$',0};
312 static const WCHAR conoutW
[] = {'C','O','N','O','U','T','$',0};
314 if (!filename
|| !filename
[0])
316 SetLastError( ERROR_PATH_NOT_FOUND
);
317 return INVALID_HANDLE_VALUE
;
320 TRACE("%s %s%s%s%s%s%s%s attributes 0x%lx\n", debugstr_w(filename
),
321 ((access
& GENERIC_READ
)==GENERIC_READ
)?"GENERIC_READ ":"",
322 ((access
& GENERIC_WRITE
)==GENERIC_WRITE
)?"GENERIC_WRITE ":"",
323 (!access
)?"QUERY_ACCESS ":"",
324 ((sharing
& FILE_SHARE_READ
)==FILE_SHARE_READ
)?"FILE_SHARE_READ ":"",
325 ((sharing
& FILE_SHARE_WRITE
)==FILE_SHARE_WRITE
)?"FILE_SHARE_WRITE ":"",
326 ((sharing
& FILE_SHARE_DELETE
)==FILE_SHARE_DELETE
)?"FILE_SHARE_DELETE ":"",
327 (creation
==CREATE_NEW
)?"CREATE_NEW":
328 (creation
==CREATE_ALWAYS
)?"CREATE_ALWAYS ":
329 (creation
==OPEN_EXISTING
)?"OPEN_EXISTING ":
330 (creation
==OPEN_ALWAYS
)?"OPEN_ALWAYS ":
331 (creation
==TRUNCATE_EXISTING
)?"TRUNCATE_EXISTING ":"", attributes
);
333 /* Open a console for CONIN$ or CONOUT$ */
334 if (!strcmpiW(filename
, coninW
) || !strcmpiW(filename
, conoutW
))
336 ret
= OpenConsoleW(filename
, access
, (sa
&& sa
->bInheritHandle
), creation
);
340 /* If the name starts with '\\?\', ignore the first 4 chars. */
341 if (!strncmpW(filename
, bkslashes_with_question_markW
, 4))
343 static const WCHAR uncW
[] = {'U','N','C','\\',0};
345 if (!strncmpiW(filename
, uncW
, 4))
347 FIXME("UNC name (%s) not supported.\n", debugstr_w(filename
) );
348 SetLastError( ERROR_PATH_NOT_FOUND
);
349 return INVALID_HANDLE_VALUE
;
353 if (!strncmpW(filename
, bkslashes_with_dotW
, 4))
355 static const WCHAR pipeW
[] = {'P','I','P','E','\\',0};
356 if(!strncmpiW(filename
+ 4, pipeW
, 5))
358 TRACE("Opening a pipe: %s\n", debugstr_w(filename
));
359 ret
= FILE_OpenPipe( filename
, access
, sa
);
362 else if (isalphaW(filename
[4]) && filename
[5] == ':' && filename
[6] == '\0')
364 const char *device
= DRIVE_GetDevice( toupperW(filename
[4]) - 'A' );
367 ret
= FILE_CreateFile( device
, access
, sharing
, sa
, creation
,
368 attributes
, template, DRIVE_FIXED
);
372 SetLastError( ERROR_ACCESS_DENIED
);
373 ret
= INVALID_HANDLE_VALUE
;
377 else if ((dosdev
= RtlIsDosDeviceName_U( filename
+ 4 )))
379 dosdev
+= MAKELONG( 0, 4*sizeof(WCHAR
) ); /* adjust position to start of filename */
383 ret
= VXD_Open( filename
+4, access
, sa
);
387 else dosdev
= RtlIsDosDeviceName_U( filename
);
391 static const WCHAR conW
[] = {'C','O','N',0};
394 memcpy( dev
, filename
+ HIWORD(dosdev
)/sizeof(WCHAR
), LOWORD(dosdev
) );
395 dev
[LOWORD(dosdev
)/sizeof(WCHAR
)] = 0;
397 TRACE("opening device %s\n", debugstr_w(dev
) );
399 if (!strcmpiW( dev
, conW
))
401 switch (access
& (GENERIC_READ
|GENERIC_WRITE
))
404 ret
= OpenConsoleW(coninW
, access
, (sa
&& sa
->bInheritHandle
), creation
);
407 ret
= OpenConsoleW(conoutW
, access
, (sa
&& sa
->bInheritHandle
), creation
);
410 FIXME("can't open CON read/write\n");
411 SetLastError( ERROR_FILE_NOT_FOUND
);
412 return INVALID_HANDLE_VALUE
;
416 ret
= VOLUME_OpenDevice( dev
, access
, sharing
, sa
, attributes
);
420 /* If the name still starts with '\\', it's a UNC name. */
421 if (!strncmpW(filename
, bkslashesW
, 2))
423 ret
= SMB_CreateFileW(filename
, access
, sharing
, sa
, creation
, attributes
, template );
427 /* If the name contains a DOS wild card (* or ?), do no create a file */
428 if(strchrW(filename
, '*') || strchrW(filename
, '?'))
430 SetLastError(ERROR_BAD_PATHNAME
);
431 return INVALID_HANDLE_VALUE
;
434 /* check for filename, don't check for last entry if creating */
435 if (!DOSFS_GetFullName( filename
,
436 (creation
== OPEN_EXISTING
) ||
437 (creation
== TRUNCATE_EXISTING
),
439 WARN("Unable to get full filename from %s (GLE %ld)\n",
440 debugstr_w(filename
), GetLastError());
441 return INVALID_HANDLE_VALUE
;
444 ret
= FILE_CreateFile( full_name
.long_name
, access
, sharing
,
445 sa
, creation
, attributes
, template,
446 GetDriveTypeW( full_name
.short_name
) );
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 info
->nFileSizeHigh
= 0;
503 info
->nFileSizeLow
= 0;
504 if (!S_ISDIR(st
->st_mode
)) {
505 info
->nFileSizeHigh
= st
->st_size
>> 32;
506 info
->nFileSizeLow
= st
->st_size
& 0xffffffff;
508 info
->nNumberOfLinks
= st
->st_nlink
;
509 info
->nFileIndexHigh
= 0;
510 info
->nFileIndexLow
= st
->st_ino
;
514 /***********************************************************************
515 * get_show_dot_files_option
517 static BOOL
get_show_dot_files_option(void)
519 static const WCHAR WineW
[] = {'M','a','c','h','i','n','e','\\',
520 'S','o','f','t','w','a','r','e','\\',
521 'W','i','n','e','\\','W','i','n','e','\\',
522 'C','o','n','f','i','g','\\','W','i','n','e',0};
523 static const WCHAR ShowDotFilesW
[] = {'S','h','o','w','D','o','t','F','i','l','e','s',0};
528 OBJECT_ATTRIBUTES attr
;
529 UNICODE_STRING nameW
;
532 attr
.Length
= sizeof(attr
);
533 attr
.RootDirectory
= 0;
534 attr
.ObjectName
= &nameW
;
536 attr
.SecurityDescriptor
= NULL
;
537 attr
.SecurityQualityOfService
= NULL
;
538 RtlInitUnicodeString( &nameW
, WineW
);
540 if (!NtOpenKey( &hkey
, KEY_ALL_ACCESS
, &attr
))
542 RtlInitUnicodeString( &nameW
, ShowDotFilesW
);
543 if (!NtQueryValueKey( hkey
, &nameW
, KeyValuePartialInformation
, tmp
, sizeof(tmp
), &dummy
))
545 WCHAR
*str
= (WCHAR
*)((KEY_VALUE_PARTIAL_INFORMATION
*)tmp
)->Data
;
546 ret
= IS_OPTION_TRUE( str
[0] );
554 /***********************************************************************
557 * Stat a Unix path name. Return TRUE if OK.
559 BOOL
FILE_Stat( LPCSTR unixName
, BY_HANDLE_FILE_INFORMATION
*info
, BOOL
*is_symlink_ptr
)
565 if (lstat( unixName
, &st
) == -1)
570 is_symlink
= S_ISLNK(st
.st_mode
);
573 /* do a "real" stat to find out
574 about the type of the symlink destination */
575 if (stat( unixName
, &st
) == -1)
582 /* fill in the information we gathered so far */
583 FILE_FillInfo( &st
, info
);
585 /* and now see if this is a hidden file, based on the name */
586 p
= strrchr( unixName
, '/');
587 p
= p
? p
+ 1 : unixName
;
588 if (*p
== '.' && *(p
+1) && (*(p
+1) != '.' || *(p
+2)))
590 static int show_dot_files
= -1;
591 if (show_dot_files
== -1)
592 show_dot_files
= get_show_dot_files_option();
594 info
->dwFileAttributes
|= FILE_ATTRIBUTE_HIDDEN
;
596 if (is_symlink_ptr
) *is_symlink_ptr
= is_symlink
;
601 /***********************************************************************
602 * GetFileInformationByHandle (KERNEL32.@)
604 DWORD WINAPI
GetFileInformationByHandle( HANDLE hFile
,
605 BY_HANDLE_FILE_INFORMATION
*info
)
610 TRACE("%p\n", hFile
);
612 SERVER_START_REQ( get_file_info
)
615 if ((ret
= !wine_server_call_err( req
)))
617 /* FIXME: which file types are supported ?
618 * Serial ports (FILE_TYPE_CHAR) are not,
619 * and MSDN also says that pipes are not supported.
620 * FILE_TYPE_REMOTE seems to be supported according to
621 * MSDN q234741.txt */
622 if ((reply
->type
== FILE_TYPE_DISK
) || (reply
->type
== FILE_TYPE_REMOTE
))
624 RtlSecondsSince1970ToTime( reply
->write_time
, (LARGE_INTEGER
*)&info
->ftCreationTime
);
625 RtlSecondsSince1970ToTime( reply
->write_time
, (LARGE_INTEGER
*)&info
->ftLastWriteTime
);
626 RtlSecondsSince1970ToTime( reply
->access_time
, (LARGE_INTEGER
*)&info
->ftLastAccessTime
);
627 info
->dwFileAttributes
= reply
->attr
;
628 info
->dwVolumeSerialNumber
= reply
->serial
;
629 info
->nFileSizeHigh
= reply
->size_high
;
630 info
->nFileSizeLow
= reply
->size_low
;
631 info
->nNumberOfLinks
= reply
->links
;
632 info
->nFileIndexHigh
= reply
->index_high
;
633 info
->nFileIndexLow
= reply
->index_low
;
637 SetLastError(ERROR_NOT_SUPPORTED
);
647 /**************************************************************************
648 * GetFileAttributesW (KERNEL32.@)
650 DWORD WINAPI
GetFileAttributesW( LPCWSTR name
)
652 DOS_FULL_NAME full_name
;
653 BY_HANDLE_FILE_INFORMATION info
;
657 SetLastError( ERROR_INVALID_PARAMETER
);
658 return INVALID_FILE_ATTRIBUTES
;
660 if (!DOSFS_GetFullName( name
, TRUE
, &full_name
) )
661 return INVALID_FILE_ATTRIBUTES
;
662 if (!FILE_Stat( full_name
.long_name
, &info
, NULL
))
663 return INVALID_FILE_ATTRIBUTES
;
664 return info
.dwFileAttributes
;
668 /**************************************************************************
669 * GetFileAttributesA (KERNEL32.@)
671 DWORD WINAPI
GetFileAttributesA( LPCSTR name
)
673 UNICODE_STRING nameW
;
674 DWORD ret
= INVALID_FILE_ATTRIBUTES
;
678 SetLastError( ERROR_INVALID_PARAMETER
);
679 return INVALID_FILE_ATTRIBUTES
;
682 if (RtlCreateUnicodeStringFromAsciiz(&nameW
, name
))
684 ret
= GetFileAttributesW(nameW
.Buffer
);
685 RtlFreeUnicodeString(&nameW
);
688 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
693 /**************************************************************************
694 * SetFileAttributesW (KERNEL32.@)
696 BOOL WINAPI
SetFileAttributesW(LPCWSTR lpFileName
, DWORD attributes
)
699 DOS_FULL_NAME full_name
;
703 SetLastError( ERROR_INVALID_PARAMETER
);
707 TRACE("(%s,%lx)\n", debugstr_w(lpFileName
), attributes
);
709 if (!DOSFS_GetFullName( lpFileName
, TRUE
, &full_name
))
712 if(stat(full_name
.long_name
,&buf
)==-1)
717 if (attributes
& FILE_ATTRIBUTE_READONLY
)
719 if(S_ISDIR(buf
.st_mode
))
721 WARN("FILE_ATTRIBUTE_READONLY ignored for directory.\n");
723 buf
.st_mode
&= ~0222; /* octal!, clear write permission bits */
724 attributes
&= ~FILE_ATTRIBUTE_READONLY
;
728 /* add write permission */
729 buf
.st_mode
|= (0600 | ((buf
.st_mode
& 044) >> 1)) & (~FILE_umask
);
731 if (attributes
& FILE_ATTRIBUTE_DIRECTORY
)
733 if (!S_ISDIR(buf
.st_mode
))
734 FIXME("SetFileAttributes expected the file %s to be a directory\n",
735 debugstr_w(lpFileName
));
736 attributes
&= ~FILE_ATTRIBUTE_DIRECTORY
;
738 attributes
&= ~(FILE_ATTRIBUTE_NORMAL
|FILE_ATTRIBUTE_ARCHIVE
|FILE_ATTRIBUTE_HIDDEN
|
739 FILE_ATTRIBUTE_SYSTEM
|FILE_ATTRIBUTE_TEMPORARY
);
741 FIXME("(%s):%lx attribute(s) not implemented.\n", debugstr_w(lpFileName
), attributes
);
742 if (-1==chmod(full_name
.long_name
,buf
.st_mode
))
744 if (GetDriveTypeW(lpFileName
) == DRIVE_CDROM
)
746 SetLastError( ERROR_ACCESS_DENIED
);
751 * FIXME: We don't return FALSE here because of differences between
752 * Linux and Windows privileges. Under Linux only the owner of
753 * the file is allowed to change file attributes. Under Windows,
754 * applications expect that if you can write to a file, you can also
755 * change its attributes (see GENERIC_WRITE). We could try to be
756 * clever here but that would break multi-user installations where
757 * users share read-only DLLs. This is because some installers like
758 * to change attributes of already installed DLLs.
760 FIXME("Couldn't set file attributes for existing file \"%s\".\n"
761 "Check permissions or set VFAT \"quiet\" mount flag\n", full_name
.long_name
);
767 /**************************************************************************
768 * SetFileAttributesA (KERNEL32.@)
770 BOOL WINAPI
SetFileAttributesA(LPCSTR lpFileName
, DWORD attributes
)
772 UNICODE_STRING filenameW
;
777 SetLastError( ERROR_INVALID_PARAMETER
);
781 if (RtlCreateUnicodeStringFromAsciiz(&filenameW
, lpFileName
))
783 ret
= SetFileAttributesW(filenameW
.Buffer
, attributes
);
784 RtlFreeUnicodeString(&filenameW
);
787 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
792 /******************************************************************************
793 * GetCompressedFileSizeA [KERNEL32.@]
795 DWORD WINAPI
GetCompressedFileSizeA(
797 LPDWORD lpFileSizeHigh
)
799 UNICODE_STRING filenameW
;
802 if (RtlCreateUnicodeStringFromAsciiz(&filenameW
, lpFileName
))
804 ret
= GetCompressedFileSizeW(filenameW
.Buffer
, lpFileSizeHigh
);
805 RtlFreeUnicodeString(&filenameW
);
809 ret
= INVALID_FILE_SIZE
;
810 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
816 /******************************************************************************
817 * GetCompressedFileSizeW [KERNEL32.@]
820 * Success: Low-order doubleword of number of bytes
821 * Failure: INVALID_FILE_SIZE
823 DWORD WINAPI
GetCompressedFileSizeW(
824 LPCWSTR lpFileName
, /* [in] Pointer to name of file */
825 LPDWORD lpFileSizeHigh
) /* [out] Receives high-order doubleword of size */
827 DOS_FULL_NAME full_name
;
831 TRACE("(%s,%p)\n",debugstr_w(lpFileName
),lpFileSizeHigh
);
833 if (!DOSFS_GetFullName( lpFileName
, TRUE
, &full_name
)) return INVALID_FILE_SIZE
;
834 if (stat(full_name
.long_name
, &st
) != 0)
837 return INVALID_FILE_SIZE
;
839 #if HAVE_STRUCT_STAT_ST_BLOCKS
840 /* blocks are 512 bytes long */
841 if (lpFileSizeHigh
) *lpFileSizeHigh
= (st
.st_blocks
>> 23);
842 low
= (DWORD
)(st
.st_blocks
<< 9);
844 if (lpFileSizeHigh
) *lpFileSizeHigh
= (st
.st_size
>> 32);
845 low
= (DWORD
)st
.st_size
;
851 /***********************************************************************
852 * GetFileTime (KERNEL32.@)
854 BOOL WINAPI
GetFileTime( HANDLE hFile
, FILETIME
*lpCreationTime
,
855 FILETIME
*lpLastAccessTime
,
856 FILETIME
*lpLastWriteTime
)
858 BY_HANDLE_FILE_INFORMATION info
;
859 if (!GetFileInformationByHandle( hFile
, &info
)) return FALSE
;
860 if (lpCreationTime
) *lpCreationTime
= info
.ftCreationTime
;
861 if (lpLastAccessTime
) *lpLastAccessTime
= info
.ftLastAccessTime
;
862 if (lpLastWriteTime
) *lpLastWriteTime
= info
.ftLastWriteTime
;
867 /***********************************************************************
868 * GetTempFileNameA (KERNEL32.@)
870 UINT WINAPI
GetTempFileNameA( LPCSTR path
, LPCSTR prefix
, UINT unique
,
873 UNICODE_STRING pathW
, prefixW
;
874 WCHAR bufferW
[MAX_PATH
];
877 if ( !path
|| !prefix
|| !buffer
)
879 SetLastError( ERROR_INVALID_PARAMETER
);
883 RtlCreateUnicodeStringFromAsciiz(&pathW
, path
);
884 RtlCreateUnicodeStringFromAsciiz(&prefixW
, prefix
);
886 ret
= GetTempFileNameW(pathW
.Buffer
, prefixW
.Buffer
, unique
, bufferW
);
888 WideCharToMultiByte(CP_ACP
, 0, bufferW
, -1, buffer
, MAX_PATH
, NULL
, NULL
);
890 RtlFreeUnicodeString(&pathW
);
891 RtlFreeUnicodeString(&prefixW
);
895 /***********************************************************************
896 * GetTempFileNameW (KERNEL32.@)
898 UINT WINAPI
GetTempFileNameW( LPCWSTR path
, LPCWSTR prefix
, UINT unique
,
901 static const WCHAR formatW
[] = {'%','x','.','t','m','p',0};
903 DOS_FULL_NAME full_name
;
907 if ( !path
|| !prefix
|| !buffer
)
909 SetLastError( ERROR_INVALID_PARAMETER
);
913 strcpyW( buffer
, path
);
914 p
= buffer
+ strlenW(buffer
);
916 /* add a \, if there isn't one */
917 if ((p
== buffer
) || (p
[-1] != '\\')) *p
++ = '\\';
919 for (i
= 3; (i
> 0) && (*prefix
); i
--) *p
++ = *prefix
++;
923 if (unique
) sprintfW( p
, formatW
, unique
);
926 /* get a "random" unique number and try to create the file */
928 UINT num
= GetTickCount() & 0xffff;
934 sprintfW( p
, formatW
, unique
);
935 handle
= CreateFileW( buffer
, GENERIC_WRITE
, 0, NULL
,
936 CREATE_NEW
, FILE_ATTRIBUTE_NORMAL
, 0 );
937 if (handle
!= INVALID_HANDLE_VALUE
)
938 { /* We created it */
939 TRACE("created %s\n", debugstr_w(buffer
) );
940 CloseHandle( handle
);
943 if (GetLastError() != ERROR_FILE_EXISTS
&&
944 GetLastError() != ERROR_SHARING_VIOLATION
)
945 break; /* No need to go on */
946 if (!(++unique
& 0xffff)) unique
= 1;
947 } while (unique
!= num
);
950 /* Get the full path name */
952 if (DOSFS_GetFullName( buffer
, FALSE
, &full_name
))
955 /* Check if we have write access in the directory */
956 if ((slash
= strrchr( full_name
.long_name
, '/' ))) *slash
= '\0';
957 if (access( full_name
.long_name
, W_OK
) == -1)
958 WARN("returns %s, which doesn't seem to be writeable.\n",
959 debugstr_w(buffer
) );
961 TRACE("returning %s\n", debugstr_w(buffer
) );
966 /******************************************************************
967 * FILE_ReadWriteApc (internal)
971 static void WINAPI
FILE_ReadWriteApc(void* apc_user
, PIO_STATUS_BLOCK io_status
, ULONG len
)
973 LPOVERLAPPED_COMPLETION_ROUTINE cr
= (LPOVERLAPPED_COMPLETION_ROUTINE
)apc_user
;
975 cr(RtlNtStatusToDosError(io_status
->u
.Status
), len
, (LPOVERLAPPED
)io_status
);
978 /***********************************************************************
979 * ReadFileEx (KERNEL32.@)
981 BOOL WINAPI
ReadFileEx(HANDLE hFile
, LPVOID buffer
, DWORD bytesToRead
,
982 LPOVERLAPPED overlapped
,
983 LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine
)
985 LARGE_INTEGER offset
;
987 PIO_STATUS_BLOCK io_status
;
991 SetLastError(ERROR_INVALID_PARAMETER
);
995 offset
.u
.LowPart
= overlapped
->Offset
;
996 offset
.u
.HighPart
= overlapped
->OffsetHigh
;
997 io_status
= (PIO_STATUS_BLOCK
)overlapped
;
998 io_status
->u
.Status
= STATUS_PENDING
;
1000 status
= NtReadFile(hFile
, NULL
, FILE_ReadWriteApc
, lpCompletionRoutine
,
1001 io_status
, buffer
, bytesToRead
, &offset
, NULL
);
1005 SetLastError( RtlNtStatusToDosError(status
) );
1011 /***********************************************************************
1012 * ReadFile (KERNEL32.@)
1014 BOOL WINAPI
ReadFile( HANDLE hFile
, LPVOID buffer
, DWORD bytesToRead
,
1015 LPDWORD bytesRead
, LPOVERLAPPED overlapped
)
1017 LARGE_INTEGER offset
;
1018 PLARGE_INTEGER poffset
= NULL
;
1019 IO_STATUS_BLOCK iosb
;
1020 PIO_STATUS_BLOCK io_status
= &iosb
;
1024 TRACE("%p %p %ld %p %p\n", hFile
, buffer
, bytesToRead
,
1025 bytesRead
, overlapped
);
1027 if (bytesRead
) *bytesRead
= 0; /* Do this before anything else */
1028 if (!bytesToRead
) return TRUE
;
1030 if (IsBadReadPtr(buffer
, bytesToRead
))
1032 SetLastError(ERROR_WRITE_FAULT
); /* FIXME */
1035 if (is_console_handle(hFile
))
1036 return ReadConsoleA(hFile
, buffer
, bytesToRead
, bytesRead
, NULL
);
1038 if (overlapped
!= NULL
)
1040 offset
.u
.LowPart
= overlapped
->Offset
;
1041 offset
.u
.HighPart
= overlapped
->OffsetHigh
;
1043 hEvent
= overlapped
->hEvent
;
1044 io_status
= (PIO_STATUS_BLOCK
)overlapped
;
1046 io_status
->u
.Status
= STATUS_PENDING
;
1047 io_status
->Information
= 0;
1049 status
= NtReadFile(hFile
, hEvent
, NULL
, NULL
, io_status
, buffer
, bytesToRead
, poffset
, NULL
);
1051 if (status
!= STATUS_PENDING
&& bytesRead
)
1052 *bytesRead
= io_status
->Information
;
1054 if (status
&& status
!= STATUS_END_OF_FILE
)
1056 SetLastError( RtlNtStatusToDosError(status
) );
1063 /***********************************************************************
1064 * WriteFileEx (KERNEL32.@)
1066 BOOL WINAPI
WriteFileEx(HANDLE hFile
, LPCVOID buffer
, DWORD bytesToWrite
,
1067 LPOVERLAPPED overlapped
,
1068 LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine
)
1070 LARGE_INTEGER offset
;
1072 PIO_STATUS_BLOCK io_status
;
1074 TRACE("%p %p %ld %p %p\n",
1075 hFile
, buffer
, bytesToWrite
, overlapped
, lpCompletionRoutine
);
1077 if (overlapped
== NULL
)
1079 SetLastError(ERROR_INVALID_PARAMETER
);
1082 offset
.u
.LowPart
= overlapped
->Offset
;
1083 offset
.u
.HighPart
= overlapped
->OffsetHigh
;
1085 io_status
= (PIO_STATUS_BLOCK
)overlapped
;
1086 io_status
->u
.Status
= STATUS_PENDING
;
1088 status
= NtWriteFile(hFile
, NULL
, FILE_ReadWriteApc
, lpCompletionRoutine
,
1089 io_status
, buffer
, bytesToWrite
, &offset
, NULL
);
1091 if (status
) SetLastError( RtlNtStatusToDosError(status
) );
1095 /***********************************************************************
1096 * WriteFile (KERNEL32.@)
1098 BOOL WINAPI
WriteFile( HANDLE hFile
, LPCVOID buffer
, DWORD bytesToWrite
,
1099 LPDWORD bytesWritten
, LPOVERLAPPED overlapped
)
1101 HANDLE hEvent
= NULL
;
1102 LARGE_INTEGER offset
;
1103 PLARGE_INTEGER poffset
= NULL
;
1105 IO_STATUS_BLOCK iosb
;
1106 PIO_STATUS_BLOCK piosb
= &iosb
;
1108 TRACE("%p %p %ld %p %p\n",
1109 hFile
, buffer
, bytesToWrite
, bytesWritten
, overlapped
);
1111 if (is_console_handle(hFile
))
1112 return WriteConsoleA(hFile
, buffer
, bytesToWrite
, bytesWritten
, NULL
);
1114 if (IsBadReadPtr(buffer
, bytesToWrite
))
1116 SetLastError(ERROR_READ_FAULT
); /* FIXME */
1122 offset
.u
.LowPart
= overlapped
->Offset
;
1123 offset
.u
.HighPart
= overlapped
->OffsetHigh
;
1125 hEvent
= overlapped
->hEvent
;
1126 piosb
= (PIO_STATUS_BLOCK
)overlapped
;
1128 piosb
->u
.Status
= STATUS_PENDING
;
1129 piosb
->Information
= 0;
1131 status
= NtWriteFile(hFile
, hEvent
, NULL
, NULL
, piosb
,
1132 buffer
, bytesToWrite
, poffset
, NULL
);
1135 SetLastError( RtlNtStatusToDosError(status
) );
1138 if (bytesWritten
) *bytesWritten
= piosb
->Information
;
1144 /***********************************************************************
1145 * SetFilePointer (KERNEL32.@)
1147 DWORD WINAPI
SetFilePointer( HANDLE hFile
, LONG distance
, LONG
*highword
,
1150 DWORD ret
= INVALID_SET_FILE_POINTER
;
1152 TRACE("handle %p offset %ld high %ld origin %ld\n",
1153 hFile
, distance
, highword
?*highword
:0, method
);
1155 SERVER_START_REQ( set_file_pointer
)
1157 req
->handle
= hFile
;
1158 req
->low
= distance
;
1159 req
->high
= highword
? *highword
: (distance
>= 0) ? 0 : -1;
1160 /* FIXME: assumes 1:1 mapping between Windows and Unix seek constants */
1161 req
->whence
= method
;
1163 if (!wine_server_call_err( req
))
1165 ret
= reply
->new_low
;
1166 if (highword
) *highword
= reply
->new_high
;
1174 /*************************************************************************
1175 * SetHandleCount (KERNEL32.@)
1177 UINT WINAPI
SetHandleCount( UINT count
)
1179 return min( 256, count
);
1183 /**************************************************************************
1184 * SetEndOfFile (KERNEL32.@)
1186 BOOL WINAPI
SetEndOfFile( HANDLE hFile
)
1189 SERVER_START_REQ( truncate_file
)
1191 req
->handle
= hFile
;
1192 ret
= !wine_server_call_err( req
);
1199 /***********************************************************************
1200 * GetFileType (KERNEL32.@)
1202 DWORD WINAPI
GetFileType( HANDLE hFile
)
1204 DWORD ret
= FILE_TYPE_UNKNOWN
;
1206 if (is_console_handle( hFile
))
1207 return FILE_TYPE_CHAR
;
1209 SERVER_START_REQ( get_file_info
)
1211 req
->handle
= hFile
;
1212 if (!wine_server_call_err( req
)) ret
= reply
->type
;
1219 /* check if a file name is for an executable file (.exe or .com) */
1220 inline static BOOL
is_executable( const char *name
)
1222 int len
= strlen(name
);
1224 if (len
< 4) return FALSE
;
1225 return (!strcasecmp( name
+ len
- 4, ".exe" ) ||
1226 !strcasecmp( name
+ len
- 4, ".com" ));
1230 /***********************************************************************
1231 * FILE_AddBootRenameEntry
1233 * Adds an entry to the registry that is loaded when windows boots and
1234 * checks if there are some files to be removed or renamed/moved.
1235 * <fn1> has to be valid and <fn2> may be NULL. If both pointers are
1236 * non-NULL then the file is moved, otherwise it is deleted. The
1237 * entry of the registrykey is always appended with two zero
1238 * terminated strings. If <fn2> is NULL then the second entry is
1239 * simply a single 0-byte. Otherwise the second filename goes
1240 * there. The entries are prepended with \??\ before the path and the
1241 * second filename gets also a '!' as the first character if
1242 * MOVEFILE_REPLACE_EXISTING is set. After the final string another
1243 * 0-byte follows to indicate the end of the strings.
1245 * \??\D:\test\file1[0]
1246 * !\??\D:\test\file1_renamed[0]
1247 * \??\D:\Test|delete[0]
1248 * [0] <- file is to be deleted, second string empty
1249 * \??\D:\test\file2[0]
1250 * !\??\D:\test\file2_renamed[0]
1251 * [0] <- indicates end of strings
1254 * \??\D:\test\file1[0]
1255 * !\??\D:\test\file1_renamed[0]
1256 * \??\D:\Test|delete[0]
1257 * [0] <- file is to be deleted, second string empty
1258 * [0] <- indicates end of strings
1261 static BOOL
FILE_AddBootRenameEntry( LPCWSTR fn1
, LPCWSTR fn2
, DWORD flags
)
1263 static const WCHAR PreString
[] = {'\\','?','?','\\',0};
1264 static const WCHAR ValueName
[] = {'P','e','n','d','i','n','g',
1265 'F','i','l','e','R','e','n','a','m','e',
1266 'O','p','e','r','a','t','i','o','n','s',0};
1267 static const WCHAR SessionW
[] = {'M','a','c','h','i','n','e','\\',
1268 'S','y','s','t','e','m','\\',
1269 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
1270 'C','o','n','t','r','o','l','\\',
1271 'S','e','s','s','i','o','n',' ','M','a','n','a','g','e','r',0};
1272 static const int info_size
= FIELD_OFFSET( KEY_VALUE_PARTIAL_INFORMATION
, Data
);
1274 OBJECT_ATTRIBUTES attr
;
1275 UNICODE_STRING nameW
;
1276 KEY_VALUE_PARTIAL_INFORMATION
*info
;
1279 DWORD len0
, len1
, len2
;
1281 BYTE
*Buffer
= NULL
;
1284 attr
.Length
= sizeof(attr
);
1285 attr
.RootDirectory
= 0;
1286 attr
.ObjectName
= &nameW
;
1287 attr
.Attributes
= 0;
1288 attr
.SecurityDescriptor
= NULL
;
1289 attr
.SecurityQualityOfService
= NULL
;
1290 RtlInitUnicodeString( &nameW
, SessionW
);
1292 if (NtCreateKey( &Reboot
, KEY_ALL_ACCESS
, &attr
, 0, NULL
, 0, NULL
) != STATUS_SUCCESS
)
1294 WARN("Error creating key for reboot managment [%s]\n",
1295 "SYSTEM\\CurrentControlSet\\Control\\Session Manager");
1299 len0
= strlenW(PreString
);
1300 len1
= strlenW(fn1
) + len0
+ 1;
1303 len2
= strlenW(fn2
) + len0
+ 1;
1304 if (flags
& MOVEFILE_REPLACE_EXISTING
) len2
++; /* Plus 1 because of the leading '!' */
1306 else len2
= 1; /* minimum is the 0 characters for the empty second string */
1308 /* convert characters to bytes */
1309 len0
*= sizeof(WCHAR
);
1310 len1
*= sizeof(WCHAR
);
1311 len2
*= sizeof(WCHAR
);
1313 RtlInitUnicodeString( &nameW
, ValueName
);
1315 /* First we check if the key exists and if so how many bytes it already contains. */
1316 if (NtQueryValueKey( Reboot
, &nameW
, KeyValuePartialInformation
,
1317 NULL
, 0, &DataSize
) == STATUS_BUFFER_OVERFLOW
)
1319 if (!(Buffer
= HeapAlloc( GetProcessHeap(), 0, DataSize
+ len1
+ len2
+ sizeof(WCHAR
) )))
1321 if (NtQueryValueKey( Reboot
, &nameW
, KeyValuePartialInformation
,
1322 Buffer
, DataSize
, &DataSize
)) goto Quit
;
1323 info
= (KEY_VALUE_PARTIAL_INFORMATION
*)Buffer
;
1324 if (info
->Type
!= REG_MULTI_SZ
) goto Quit
;
1325 if (DataSize
> sizeof(info
)) DataSize
-= sizeof(WCHAR
); /* remove terminating null (will be added back later) */
1329 DataSize
= info_size
;
1330 if (!(Buffer
= HeapAlloc( GetProcessHeap(), 0, DataSize
+ len1
+ len2
+ sizeof(WCHAR
) )))
1334 p
= (WCHAR
*)(Buffer
+ DataSize
);
1335 strcpyW( p
, PreString
);
1340 p
= (WCHAR
*)(Buffer
+ DataSize
);
1341 if (flags
& MOVEFILE_REPLACE_EXISTING
)
1343 strcpyW( p
, PreString
);
1349 p
= (WCHAR
*)(Buffer
+ DataSize
);
1351 DataSize
+= sizeof(WCHAR
);
1354 /* add final null */
1355 p
= (WCHAR
*)(Buffer
+ DataSize
);
1357 DataSize
+= sizeof(WCHAR
);
1359 rc
= !NtSetValueKey(Reboot
, &nameW
, 0, REG_MULTI_SZ
, Buffer
+ info_size
, DataSize
- info_size
);
1362 if (Reboot
) NtClose(Reboot
);
1363 if (Buffer
) HeapFree( GetProcessHeap(), 0, Buffer
);
1368 /**************************************************************************
1369 * MoveFileExW (KERNEL32.@)
1371 BOOL WINAPI
MoveFileExW( LPCWSTR fn1
, LPCWSTR fn2
, DWORD flag
)
1373 DOS_FULL_NAME full_name1
, full_name2
;
1375 DWORD attr
= INVALID_FILE_ATTRIBUTES
;
1377 TRACE("(%s,%s,%04lx)\n", debugstr_w(fn1
), debugstr_w(fn2
), flag
);
1379 /* FIXME: <Gerhard W. Gruber>sparhawk@gmx.at
1380 In case of W9x and lesser this function should return 120 (ERROR_CALL_NOT_IMPLEMENTED)
1381 to be really compatible. Most programs won't have any problems though. In case
1382 you encounter one, this is what you should return here. I don't know what's up
1383 with NT 3.5. Is this function available there or not?
1384 Does anybody really care about 3.5? :)
1387 /* Filename1 has to be always set to a valid path. Filename2 may be NULL
1388 if the source file has to be deleted.
1391 SetLastError(ERROR_INVALID_PARAMETER
);
1395 /* This function has to be run through in order to process the name properly.
1396 If the BOOTDELAY flag is set, the file doesn't need to exist though. At least
1397 that is the behaviour on NT 4.0. The operation accepts the filenames as
1398 they are given but it can't reply with a reasonable returncode. Success
1399 means in that case success for entering the values into the registry.
1401 if(!DOSFS_GetFullName( fn1
, TRUE
, &full_name1
))
1403 if(!(flag
& MOVEFILE_DELAY_UNTIL_REBOOT
))
1407 if (fn2
) /* !fn2 means delete fn1 */
1409 if (DOSFS_GetFullName( fn2
, TRUE
, &full_name2
))
1411 if(!(flag
& MOVEFILE_DELAY_UNTIL_REBOOT
))
1413 /* target exists, check if we may overwrite */
1414 if (!(flag
& MOVEFILE_REPLACE_EXISTING
))
1416 SetLastError( ERROR_ALREADY_EXISTS
);
1423 if (!DOSFS_GetFullName( fn2
, FALSE
, &full_name2
))
1425 if(!(flag
& MOVEFILE_DELAY_UNTIL_REBOOT
))
1430 /* Source name and target path are valid */
1432 if (flag
& MOVEFILE_DELAY_UNTIL_REBOOT
)
1434 return FILE_AddBootRenameEntry( fn1
, fn2
, flag
);
1437 attr
= GetFileAttributesW( fn1
);
1438 if ( attr
== INVALID_FILE_ATTRIBUTES
) return FALSE
;
1440 /* check if we are allowed to rename the source */
1441 hFile
= FILE_CreateFile( full_name1
.long_name
, 0, 0,
1442 NULL
, OPEN_EXISTING
, 0, 0,
1443 GetDriveTypeW( full_name1
.short_name
) );
1446 if (GetLastError() != ERROR_ACCESS_DENIED
) return FALSE
;
1447 if ( !(attr
& FILE_ATTRIBUTE_DIRECTORY
) ) return FALSE
;
1448 /* if it's a directory we can continue */
1450 else CloseHandle(hFile
);
1452 /* check, if we are allowed to delete the destination,
1453 ** (but the file not being there is fine) */
1454 hFile
= FILE_CreateFile( full_name2
.long_name
, GENERIC_READ
|GENERIC_WRITE
, 0,
1455 NULL
, OPEN_EXISTING
, 0, 0,
1456 GetDriveTypeW( full_name2
.short_name
) );
1457 if(!hFile
&& GetLastError() != ERROR_FILE_NOT_FOUND
) return FALSE
;
1460 if (full_name1
.drive
!= full_name2
.drive
)
1462 if (!(flag
& MOVEFILE_COPY_ALLOWED
))
1464 SetLastError( ERROR_NOT_SAME_DEVICE
);
1467 else if ( attr
& FILE_ATTRIBUTE_DIRECTORY
)
1469 /* Strange, but that's what Windows returns */
1470 SetLastError ( ERROR_ACCESS_DENIED
);
1474 if (rename( full_name1
.long_name
, full_name2
.long_name
) == -1)
1475 /* Try copy/delete unless it's a directory. */
1476 /* FIXME: This does not handle the (unlikely) case that the two locations
1477 are on the same Wine drive, but on different Unix file systems. */
1479 if ( attr
& FILE_ATTRIBUTE_DIRECTORY
)
1486 if ( ! CopyFileW( fn1
, fn2
, !(flag
& MOVEFILE_REPLACE_EXISTING
) ))
1488 if ( ! DeleteFileW ( fn1
) )
1492 if (is_executable( full_name1
.long_name
) != is_executable( full_name2
.long_name
))
1495 if (stat( full_name2
.long_name
, &fstat
) != -1)
1497 if (is_executable( full_name2
.long_name
))
1498 /* set executable bit where read bit is set */
1499 fstat
.st_mode
|= (fstat
.st_mode
& 0444) >> 2;
1501 fstat
.st_mode
&= ~0111;
1502 chmod( full_name2
.long_name
, fstat
.st_mode
);
1507 else /* fn2 == NULL means delete source */
1509 if (flag
& MOVEFILE_DELAY_UNTIL_REBOOT
)
1511 if (flag
& MOVEFILE_COPY_ALLOWED
) {
1512 WARN("Illegal flag\n");
1513 SetLastError( ERROR_GEN_FAILURE
);
1517 return FILE_AddBootRenameEntry( fn1
, NULL
, flag
);
1520 if (unlink( full_name1
.long_name
) == -1)
1525 return TRUE
; /* successfully deleted */
1529 /**************************************************************************
1530 * MoveFileExA (KERNEL32.@)
1532 BOOL WINAPI
MoveFileExA( LPCSTR fn1
, LPCSTR fn2
, DWORD flag
)
1534 UNICODE_STRING fn1W
, fn2W
;
1539 SetLastError(ERROR_INVALID_PARAMETER
);
1543 RtlCreateUnicodeStringFromAsciiz(&fn1W
, fn1
);
1544 if (fn2
) RtlCreateUnicodeStringFromAsciiz(&fn2W
, fn2
);
1545 else fn2W
.Buffer
= NULL
;
1547 ret
= MoveFileExW( fn1W
.Buffer
, fn2W
.Buffer
, flag
);
1549 RtlFreeUnicodeString(&fn1W
);
1550 RtlFreeUnicodeString(&fn2W
);
1555 /**************************************************************************
1556 * MoveFileW (KERNEL32.@)
1558 * Move file or directory
1560 BOOL WINAPI
MoveFileW( LPCWSTR fn1
, LPCWSTR fn2
)
1562 return MoveFileExW( fn1
, fn2
, MOVEFILE_COPY_ALLOWED
);
1566 /**************************************************************************
1567 * MoveFileA (KERNEL32.@)
1569 BOOL WINAPI
MoveFileA( LPCSTR fn1
, LPCSTR fn2
)
1571 return MoveFileExA( fn1
, fn2
, MOVEFILE_COPY_ALLOWED
);
1575 /**************************************************************************
1576 * CopyFileW (KERNEL32.@)
1578 BOOL WINAPI
CopyFileW( LPCWSTR source
, LPCWSTR dest
, BOOL fail_if_exists
)
1581 BY_HANDLE_FILE_INFORMATION info
;
1586 if (!source
|| !dest
)
1588 SetLastError(ERROR_INVALID_PARAMETER
);
1592 TRACE("%s -> %s\n", debugstr_w(source
), debugstr_w(dest
));
1594 if ((h1
= CreateFileW(source
, GENERIC_READ
, FILE_SHARE_READ
| FILE_SHARE_WRITE
,
1595 NULL
, OPEN_EXISTING
, 0, 0)) == INVALID_HANDLE_VALUE
)
1597 WARN("Unable to open source %s\n", debugstr_w(source
));
1601 if (!GetFileInformationByHandle( h1
, &info
))
1603 WARN("GetFileInformationByHandle returned error for %s\n", debugstr_w(source
));
1608 if ((h2
= CreateFileW( dest
, GENERIC_WRITE
, FILE_SHARE_READ
| FILE_SHARE_WRITE
, NULL
,
1609 fail_if_exists
? CREATE_NEW
: CREATE_ALWAYS
,
1610 info
.dwFileAttributes
, h1
)) == INVALID_HANDLE_VALUE
)
1612 WARN("Unable to open dest %s\n", debugstr_w(dest
));
1617 while (ReadFile( h1
, buffer
, sizeof(buffer
), &count
, NULL
) && count
)
1623 if (!WriteFile( h2
, p
, count
, &res
, NULL
) || !res
) goto done
;
1636 /**************************************************************************
1637 * CopyFileA (KERNEL32.@)
1639 BOOL WINAPI
CopyFileA( LPCSTR source
, LPCSTR dest
, BOOL fail_if_exists
)
1641 UNICODE_STRING sourceW
, destW
;
1644 if (!source
|| !dest
)
1646 SetLastError(ERROR_INVALID_PARAMETER
);
1650 RtlCreateUnicodeStringFromAsciiz(&sourceW
, source
);
1651 RtlCreateUnicodeStringFromAsciiz(&destW
, dest
);
1653 ret
= CopyFileW(sourceW
.Buffer
, destW
.Buffer
, fail_if_exists
);
1655 RtlFreeUnicodeString(&sourceW
);
1656 RtlFreeUnicodeString(&destW
);
1661 /**************************************************************************
1662 * CopyFileExW (KERNEL32.@)
1664 * This implementation ignores most of the extra parameters passed-in into
1665 * the "ex" version of the method and calls the CopyFile method.
1666 * It will have to be fixed eventually.
1668 BOOL WINAPI
CopyFileExW(LPCWSTR sourceFilename
, LPCWSTR destFilename
,
1669 LPPROGRESS_ROUTINE progressRoutine
, LPVOID appData
,
1670 LPBOOL cancelFlagPointer
, DWORD copyFlags
)
1673 * Interpret the only flag that CopyFile can interpret.
1675 return CopyFileW(sourceFilename
, destFilename
, (copyFlags
& COPY_FILE_FAIL_IF_EXISTS
) != 0);
1679 /**************************************************************************
1680 * CopyFileExA (KERNEL32.@)
1682 BOOL WINAPI
CopyFileExA(LPCSTR sourceFilename
, LPCSTR destFilename
,
1683 LPPROGRESS_ROUTINE progressRoutine
, LPVOID appData
,
1684 LPBOOL cancelFlagPointer
, DWORD copyFlags
)
1686 UNICODE_STRING sourceW
, destW
;
1689 if (!sourceFilename
|| !destFilename
)
1691 SetLastError(ERROR_INVALID_PARAMETER
);
1695 RtlCreateUnicodeStringFromAsciiz(&sourceW
, sourceFilename
);
1696 RtlCreateUnicodeStringFromAsciiz(&destW
, destFilename
);
1698 ret
= CopyFileExW(sourceW
.Buffer
, destW
.Buffer
, progressRoutine
, appData
,
1699 cancelFlagPointer
, copyFlags
);
1701 RtlFreeUnicodeString(&sourceW
);
1702 RtlFreeUnicodeString(&destW
);
1707 /***********************************************************************
1708 * SetFileTime (KERNEL32.@)
1710 BOOL WINAPI
SetFileTime( HANDLE hFile
,
1711 const FILETIME
*ctime
,
1712 const FILETIME
*atime
,
1713 const FILETIME
*mtime
)
1719 ULONGLONG sec
, nsec
;
1721 if (!(status
= wine_server_handle_to_fd( hFile
, GENERIC_WRITE
, &fd
, NULL
, NULL
)))
1723 struct timeval tv
[2];
1725 if (!atime
|| !mtime
)
1729 tv
[0].tv_sec
= tv
[0].tv_usec
= 0;
1730 tv
[1].tv_sec
= tv
[1].tv_usec
= 0;
1731 if (!fstat( fd
, &st
))
1733 tv
[0].tv_sec
= st
.st_atime
;
1734 tv
[1].tv_sec
= st
.st_mtime
;
1739 sec
= ((ULONGLONG
)atime
->dwHighDateTime
<< 32) | atime
->dwLowDateTime
;
1740 sec
= RtlLargeIntegerDivide( sec
, 10000000, &nsec
);
1741 tv
[0].tv_sec
= sec
- SECS_1601_TO_1970
;
1742 tv
[0].tv_usec
= (UINT
)nsec
/ 10;
1746 sec
= ((ULONGLONG
)mtime
->dwHighDateTime
<< 32) | mtime
->dwLowDateTime
;
1747 sec
= RtlLargeIntegerDivide( sec
, 10000000, &nsec
);
1748 tv
[1].tv_sec
= sec
- SECS_1601_TO_1970
;
1749 tv
[1].tv_usec
= (UINT
)nsec
/ 10;
1752 if (!futimes( fd
, tv
)) ret
= TRUE
;
1753 else FILE_SetDosError();
1754 wine_server_release_fd( hFile
, fd
);
1756 else SetLastError( RtlNtStatusToDosError(status
) );
1759 SetLastError( ERROR_CALL_NOT_IMPLEMENTED
);
1761 #endif /* HAVE_FUTIMES */
1765 /**************************************************************************
1766 * GetFileAttributesExW (KERNEL32.@)
1768 BOOL WINAPI
GetFileAttributesExW(
1769 LPCWSTR lpFileName
, GET_FILEEX_INFO_LEVELS fInfoLevelId
,
1770 LPVOID lpFileInformation
)
1772 DOS_FULL_NAME full_name
;
1773 BY_HANDLE_FILE_INFORMATION info
;
1775 if (!lpFileName
|| !lpFileInformation
)
1777 SetLastError(ERROR_INVALID_PARAMETER
);
1781 if (fInfoLevelId
== GetFileExInfoStandard
) {
1782 LPWIN32_FILE_ATTRIBUTE_DATA lpFad
=
1783 (LPWIN32_FILE_ATTRIBUTE_DATA
) lpFileInformation
;
1784 if (!DOSFS_GetFullName( lpFileName
, TRUE
, &full_name
)) return FALSE
;
1785 if (!FILE_Stat( full_name
.long_name
, &info
, NULL
)) return FALSE
;
1787 lpFad
->dwFileAttributes
= info
.dwFileAttributes
;
1788 lpFad
->ftCreationTime
= info
.ftCreationTime
;
1789 lpFad
->ftLastAccessTime
= info
.ftLastAccessTime
;
1790 lpFad
->ftLastWriteTime
= info
.ftLastWriteTime
;
1791 lpFad
->nFileSizeHigh
= info
.nFileSizeHigh
;
1792 lpFad
->nFileSizeLow
= info
.nFileSizeLow
;
1795 FIXME("invalid info level %d!\n", fInfoLevelId
);
1803 /**************************************************************************
1804 * GetFileAttributesExA (KERNEL32.@)
1806 BOOL WINAPI
GetFileAttributesExA(
1807 LPCSTR filename
, GET_FILEEX_INFO_LEVELS fInfoLevelId
,
1808 LPVOID lpFileInformation
)
1810 UNICODE_STRING filenameW
;
1813 if (!filename
|| !lpFileInformation
)
1815 SetLastError(ERROR_INVALID_PARAMETER
);
1819 if (RtlCreateUnicodeStringFromAsciiz(&filenameW
, filename
))
1821 ret
= GetFileAttributesExW(filenameW
.Buffer
, fInfoLevelId
, lpFileInformation
);
1822 RtlFreeUnicodeString(&filenameW
);
1825 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);