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, BOOL fail_read_only
,
195 case CREATE_ALWAYS
: disp
= FILE_OVERWRITE_IF
; break;
196 case CREATE_NEW
: disp
= FILE_CREATE
; break;
197 case OPEN_ALWAYS
: disp
= FILE_OPEN_IF
; break;
198 case OPEN_EXISTING
: disp
= FILE_OPEN
; break;
199 case TRUNCATE_EXISTING
: disp
= FILE_OVERWRITE
; break;
201 SetLastError( ERROR_INVALID_PARAMETER
);
206 if (attributes
& FILE_FLAG_BACKUP_SEMANTICS
)
207 options
|= FILE_OPEN_FOR_BACKUP_INTENT
;
208 if (attributes
& FILE_FLAG_DELETE_ON_CLOSE
)
209 options
|= FILE_DELETE_ON_CLOSE
;
210 if (!(attributes
& FILE_FLAG_OVERLAPPED
))
211 options
|= FILE_SYNCHRONOUS_IO_ALERT
;
212 if (attributes
& FILE_FLAG_RANDOM_ACCESS
)
213 options
|= FILE_RANDOM_ACCESS
;
214 attributes
&= FILE_ATTRIBUTE_VALID_FLAGS
;
218 SERVER_START_REQ( create_file
)
220 req
->access
= access
;
221 req
->inherit
= (sa
&& (sa
->nLength
>=sizeof(*sa
)) && sa
->bInheritHandle
);
222 req
->sharing
= sharing
;
224 req
->options
= options
;
225 req
->attrs
= attributes
;
226 req
->removable
= (drive_type
== DRIVE_REMOVABLE
|| drive_type
== DRIVE_CDROM
);
227 wine_server_add_data( req
, filename
, strlen(filename
) );
229 err
= wine_server_call( req
);
234 /* If write access failed, retry without GENERIC_WRITE */
236 if (!ret
&& !fail_read_only
&& (access
& GENERIC_WRITE
))
238 if ((err
== STATUS_MEDIA_WRITE_PROTECTED
) || (err
== STATUS_ACCESS_DENIED
))
240 TRACE("Write access failed for file '%s', trying without "
241 "write access\n", filename
);
242 access
&= ~GENERIC_WRITE
;
249 /* In the case file creation was rejected due to CREATE_NEW flag
250 * was specified and file with that name already exists, correct
251 * last error is ERROR_FILE_EXISTS and not ERROR_ALREADY_EXISTS.
252 * Note: RtlNtStatusToDosError is not the subject to blame here.
254 if (err
== STATUS_OBJECT_NAME_COLLISION
)
255 SetLastError( ERROR_FILE_EXISTS
);
257 SetLastError( RtlNtStatusToDosError(err
) );
260 if (!ret
) WARN("Unable to create file '%s' (GLE %ld)\n", filename
, GetLastError());
266 static HANDLE
FILE_OpenPipe(LPCWSTR name
, DWORD access
, LPSECURITY_ATTRIBUTES sa
)
271 if (name
&& (len
= strlenW(name
)) > MAX_PATH
)
273 SetLastError( ERROR_FILENAME_EXCED_RANGE
);
276 SERVER_START_REQ( open_named_pipe
)
278 req
->access
= access
;
279 req
->inherit
= (sa
&& (sa
->nLength
>=sizeof(*sa
)) && sa
->bInheritHandle
);
281 wine_server_add_data( req
, name
, len
* sizeof(WCHAR
) );
282 wine_server_call_err( req
);
286 TRACE("Returned %p\n",ret
);
290 /*************************************************************************
291 * CreateFileW [KERNEL32.@] Creates or opens a file or other object
293 * Creates or opens an object, and returns a handle that can be used to
294 * access that object.
298 * filename [in] pointer to filename to be accessed
299 * access [in] access mode requested
300 * sharing [in] share mode
301 * sa [in] pointer to security attributes
302 * creation [in] how to create the file
303 * attributes [in] attributes for newly created file
304 * template [in] handle to file with extended attributes to copy
307 * Success: Open handle to specified file
308 * Failure: INVALID_HANDLE_VALUE
311 * Should call SetLastError() on failure.
315 * Doesn't support character devices, template files, or a
316 * lot of the 'attributes' flags yet.
318 HANDLE WINAPI
CreateFileW( LPCWSTR filename
, DWORD access
, DWORD sharing
,
319 LPSECURITY_ATTRIBUTES sa
, DWORD creation
,
320 DWORD attributes
, HANDLE
template )
322 DOS_FULL_NAME full_name
;
325 static const WCHAR bkslashes_with_question_markW
[] = {'\\','\\','?','\\',0};
326 static const WCHAR bkslashes_with_dotW
[] = {'\\','\\','.','\\',0};
327 static const WCHAR bkslashesW
[] = {'\\','\\',0};
328 static const WCHAR coninW
[] = {'C','O','N','I','N','$',0};
329 static const WCHAR conoutW
[] = {'C','O','N','O','U','T','$',0};
333 SetLastError( ERROR_INVALID_PARAMETER
);
334 return INVALID_HANDLE_VALUE
;
336 TRACE("%s %s%s%s%s%s%s%s attributes 0x%lx\n", debugstr_w(filename
),
337 ((access
& GENERIC_READ
)==GENERIC_READ
)?"GENERIC_READ ":"",
338 ((access
& GENERIC_WRITE
)==GENERIC_WRITE
)?"GENERIC_WRITE ":"",
339 (!access
)?"QUERY_ACCESS ":"",
340 ((sharing
& FILE_SHARE_READ
)==FILE_SHARE_READ
)?"FILE_SHARE_READ ":"",
341 ((sharing
& FILE_SHARE_WRITE
)==FILE_SHARE_WRITE
)?"FILE_SHARE_WRITE ":"",
342 ((sharing
& FILE_SHARE_DELETE
)==FILE_SHARE_DELETE
)?"FILE_SHARE_DELETE ":"",
343 (creation
==CREATE_NEW
)?"CREATE_NEW":
344 (creation
==CREATE_ALWAYS
)?"CREATE_ALWAYS ":
345 (creation
==OPEN_EXISTING
)?"OPEN_EXISTING ":
346 (creation
==OPEN_ALWAYS
)?"OPEN_ALWAYS ":
347 (creation
==TRUNCATE_EXISTING
)?"TRUNCATE_EXISTING ":"", attributes
);
349 /* Open a console for CONIN$ or CONOUT$ */
350 if (!strcmpiW(filename
, coninW
) || !strcmpiW(filename
, conoutW
))
352 ret
= OpenConsoleW(filename
, access
, (sa
&& sa
->bInheritHandle
), creation
);
356 /* If the name starts with '\\?\', ignore the first 4 chars. */
357 if (!strncmpW(filename
, bkslashes_with_question_markW
, 4))
359 static const WCHAR uncW
[] = {'U','N','C','\\',0};
361 if (!strncmpiW(filename
, uncW
, 4))
363 FIXME("UNC name (%s) not supported.\n", debugstr_w(filename
) );
364 SetLastError( ERROR_PATH_NOT_FOUND
);
365 return INVALID_HANDLE_VALUE
;
369 if (!strncmpW(filename
, bkslashes_with_dotW
, 4))
371 static const WCHAR pipeW
[] = {'P','I','P','E','\\',0};
372 if(!strncmpiW(filename
+ 4, pipeW
, 5))
374 TRACE("Opening a pipe: %s\n", debugstr_w(filename
));
375 ret
= FILE_OpenPipe( filename
, access
, sa
);
378 else if (isalphaW(filename
[4]) && filename
[5] == ':' && filename
[6] == '\0')
380 const char *device
= DRIVE_GetDevice( toupperW(filename
[4]) - 'A' );
383 ret
= FILE_CreateFile( device
, access
, sharing
, sa
, creation
,
384 attributes
, template, TRUE
, DRIVE_FIXED
);
388 SetLastError( ERROR_ACCESS_DENIED
);
389 ret
= INVALID_HANDLE_VALUE
;
393 else if ((dosdev
= RtlIsDosDeviceName_U( filename
+ 4 )))
395 dosdev
+= MAKELONG( 0, 4*sizeof(WCHAR
) ); /* adjust position to start of filename */
399 ret
= VXD_Open( filename
+4, access
, sa
);
403 else dosdev
= RtlIsDosDeviceName_U( filename
);
407 static const WCHAR conW
[] = {'C','O','N',0};
410 memcpy( dev
, filename
+ HIWORD(dosdev
)/sizeof(WCHAR
), LOWORD(dosdev
) );
411 dev
[LOWORD(dosdev
)/sizeof(WCHAR
)] = 0;
413 TRACE("opening device %s\n", debugstr_w(dev
) );
415 if (!strcmpiW( dev
, conW
))
417 switch (access
& (GENERIC_READ
|GENERIC_WRITE
))
420 ret
= OpenConsoleW(coninW
, access
, (sa
&& sa
->bInheritHandle
), creation
);
423 ret
= OpenConsoleW(conoutW
, access
, (sa
&& sa
->bInheritHandle
), creation
);
426 FIXME("can't open CON read/write\n");
427 SetLastError( ERROR_FILE_NOT_FOUND
);
428 return INVALID_HANDLE_VALUE
;
432 ret
= VOLUME_OpenDevice( dev
, access
, sharing
, sa
, attributes
);
436 /* If the name still starts with '\\', it's a UNC name. */
437 if (!strncmpW(filename
, bkslashesW
, 2))
439 ret
= SMB_CreateFileW(filename
, access
, sharing
, sa
, creation
, attributes
, template );
443 /* If the name contains a DOS wild card (* or ?), do no create a file */
444 if(strchrW(filename
, '*') || strchrW(filename
, '?'))
446 SetLastError(ERROR_BAD_PATHNAME
);
447 return INVALID_HANDLE_VALUE
;
450 /* check for filename, don't check for last entry if creating */
451 if (!DOSFS_GetFullName( filename
,
452 (creation
== OPEN_EXISTING
) ||
453 (creation
== TRUNCATE_EXISTING
),
455 WARN("Unable to get full filename from %s (GLE %ld)\n",
456 debugstr_w(filename
), GetLastError());
457 return INVALID_HANDLE_VALUE
;
460 ret
= FILE_CreateFile( full_name
.long_name
, access
, sharing
,
461 sa
, creation
, attributes
, template,
462 DRIVE_GetFlags(full_name
.drive
) & DRIVE_FAIL_READ_ONLY
,
463 GetDriveTypeW( full_name
.short_name
) );
465 if (!ret
) ret
= INVALID_HANDLE_VALUE
;
466 TRACE("returning %p\n", ret
);
472 /*************************************************************************
473 * CreateFileA (KERNEL32.@)
475 HANDLE WINAPI
CreateFileA( LPCSTR filename
, DWORD access
, DWORD sharing
,
476 LPSECURITY_ATTRIBUTES sa
, DWORD creation
,
477 DWORD attributes
, HANDLE
template)
479 UNICODE_STRING filenameW
;
480 HANDLE ret
= INVALID_HANDLE_VALUE
;
484 SetLastError( ERROR_INVALID_PARAMETER
);
485 return INVALID_HANDLE_VALUE
;
488 if (RtlCreateUnicodeStringFromAsciiz(&filenameW
, filename
))
490 ret
= CreateFileW(filenameW
.Buffer
, access
, sharing
, sa
, creation
,
491 attributes
, template);
492 RtlFreeUnicodeString(&filenameW
);
495 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
500 /***********************************************************************
503 * Fill a file information from a struct stat.
505 static void FILE_FillInfo( struct stat
*st
, BY_HANDLE_FILE_INFORMATION
*info
)
507 if (S_ISDIR(st
->st_mode
))
508 info
->dwFileAttributes
= FILE_ATTRIBUTE_DIRECTORY
;
510 info
->dwFileAttributes
= FILE_ATTRIBUTE_ARCHIVE
;
511 if (!(st
->st_mode
& S_IWUSR
))
512 info
->dwFileAttributes
|= FILE_ATTRIBUTE_READONLY
;
514 RtlSecondsSince1970ToTime( st
->st_mtime
, (LARGE_INTEGER
*)&info
->ftCreationTime
);
515 RtlSecondsSince1970ToTime( st
->st_mtime
, (LARGE_INTEGER
*)&info
->ftLastWriteTime
);
516 RtlSecondsSince1970ToTime( st
->st_atime
, (LARGE_INTEGER
*)&info
->ftLastAccessTime
);
518 info
->dwVolumeSerialNumber
= 0; /* FIXME */
519 info
->nFileSizeHigh
= 0;
520 info
->nFileSizeLow
= 0;
521 if (!S_ISDIR(st
->st_mode
)) {
522 info
->nFileSizeHigh
= st
->st_size
>> 32;
523 info
->nFileSizeLow
= st
->st_size
& 0xffffffff;
525 info
->nNumberOfLinks
= st
->st_nlink
;
526 info
->nFileIndexHigh
= 0;
527 info
->nFileIndexLow
= st
->st_ino
;
531 /***********************************************************************
532 * get_show_dot_files_option
534 static BOOL
get_show_dot_files_option(void)
536 static const WCHAR WineW
[] = {'M','a','c','h','i','n','e','\\',
537 'S','o','f','t','w','a','r','e','\\',
538 'W','i','n','e','\\','W','i','n','e','\\',
539 'C','o','n','f','i','g','\\','W','i','n','e',0};
540 static const WCHAR ShowDotFilesW
[] = {'S','h','o','w','D','o','t','F','i','l','e','s',0};
545 OBJECT_ATTRIBUTES attr
;
546 UNICODE_STRING nameW
;
549 attr
.Length
= sizeof(attr
);
550 attr
.RootDirectory
= 0;
551 attr
.ObjectName
= &nameW
;
553 attr
.SecurityDescriptor
= NULL
;
554 attr
.SecurityQualityOfService
= NULL
;
555 RtlInitUnicodeString( &nameW
, WineW
);
557 if (!NtOpenKey( &hkey
, KEY_ALL_ACCESS
, &attr
))
559 RtlInitUnicodeString( &nameW
, ShowDotFilesW
);
560 if (!NtQueryValueKey( hkey
, &nameW
, KeyValuePartialInformation
, tmp
, sizeof(tmp
), &dummy
))
562 WCHAR
*str
= (WCHAR
*)((KEY_VALUE_PARTIAL_INFORMATION
*)tmp
)->Data
;
563 ret
= IS_OPTION_TRUE( str
[0] );
571 /***********************************************************************
574 * Stat a Unix path name. Return TRUE if OK.
576 BOOL
FILE_Stat( LPCSTR unixName
, BY_HANDLE_FILE_INFORMATION
*info
, BOOL
*is_symlink_ptr
)
582 if (lstat( unixName
, &st
) == -1)
587 is_symlink
= S_ISLNK(st
.st_mode
);
590 /* do a "real" stat to find out
591 about the type of the symlink destination */
592 if (stat( unixName
, &st
) == -1)
599 /* fill in the information we gathered so far */
600 FILE_FillInfo( &st
, info
);
602 /* and now see if this is a hidden file, based on the name */
603 p
= strrchr( unixName
, '/');
604 p
= p
? p
+ 1 : unixName
;
605 if (*p
== '.' && *(p
+1) && (*(p
+1) != '.' || *(p
+2)))
607 static int show_dot_files
= -1;
608 if (show_dot_files
== -1)
609 show_dot_files
= get_show_dot_files_option();
611 info
->dwFileAttributes
|= FILE_ATTRIBUTE_HIDDEN
;
613 if (is_symlink_ptr
) *is_symlink_ptr
= is_symlink
;
618 /***********************************************************************
619 * GetFileInformationByHandle (KERNEL32.@)
621 DWORD WINAPI
GetFileInformationByHandle( HANDLE hFile
,
622 BY_HANDLE_FILE_INFORMATION
*info
)
627 TRACE("%p\n", hFile
);
629 SERVER_START_REQ( get_file_info
)
632 if ((ret
= !wine_server_call_err( req
)))
634 /* FIXME: which file types are supported ?
635 * Serial ports (FILE_TYPE_CHAR) are not,
636 * and MSDN also says that pipes are not supported.
637 * FILE_TYPE_REMOTE seems to be supported according to
638 * MSDN q234741.txt */
639 if ((reply
->type
== FILE_TYPE_DISK
) || (reply
->type
== FILE_TYPE_REMOTE
))
641 RtlSecondsSince1970ToTime( reply
->write_time
, (LARGE_INTEGER
*)&info
->ftCreationTime
);
642 RtlSecondsSince1970ToTime( reply
->write_time
, (LARGE_INTEGER
*)&info
->ftLastWriteTime
);
643 RtlSecondsSince1970ToTime( reply
->access_time
, (LARGE_INTEGER
*)&info
->ftLastAccessTime
);
644 info
->dwFileAttributes
= reply
->attr
;
645 info
->dwVolumeSerialNumber
= reply
->serial
;
646 info
->nFileSizeHigh
= reply
->size_high
;
647 info
->nFileSizeLow
= reply
->size_low
;
648 info
->nNumberOfLinks
= reply
->links
;
649 info
->nFileIndexHigh
= reply
->index_high
;
650 info
->nFileIndexLow
= reply
->index_low
;
654 SetLastError(ERROR_NOT_SUPPORTED
);
664 /**************************************************************************
665 * GetFileAttributesW (KERNEL32.@)
667 DWORD WINAPI
GetFileAttributesW( LPCWSTR name
)
669 DOS_FULL_NAME full_name
;
670 BY_HANDLE_FILE_INFORMATION info
;
674 SetLastError( ERROR_INVALID_PARAMETER
);
675 return INVALID_FILE_ATTRIBUTES
;
677 if (!DOSFS_GetFullName( name
, TRUE
, &full_name
) )
678 return INVALID_FILE_ATTRIBUTES
;
679 if (!FILE_Stat( full_name
.long_name
, &info
, NULL
))
680 return INVALID_FILE_ATTRIBUTES
;
681 return info
.dwFileAttributes
;
685 /**************************************************************************
686 * GetFileAttributesA (KERNEL32.@)
688 DWORD WINAPI
GetFileAttributesA( LPCSTR name
)
690 UNICODE_STRING nameW
;
691 DWORD ret
= INVALID_FILE_ATTRIBUTES
;
695 SetLastError( ERROR_INVALID_PARAMETER
);
696 return INVALID_FILE_ATTRIBUTES
;
699 if (RtlCreateUnicodeStringFromAsciiz(&nameW
, name
))
701 ret
= GetFileAttributesW(nameW
.Buffer
);
702 RtlFreeUnicodeString(&nameW
);
705 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
710 /**************************************************************************
711 * SetFileAttributesW (KERNEL32.@)
713 BOOL WINAPI
SetFileAttributesW(LPCWSTR lpFileName
, DWORD attributes
)
716 DOS_FULL_NAME full_name
;
720 SetLastError( ERROR_INVALID_PARAMETER
);
724 TRACE("(%s,%lx)\n", debugstr_w(lpFileName
), attributes
);
726 if (!DOSFS_GetFullName( lpFileName
, TRUE
, &full_name
))
729 if(stat(full_name
.long_name
,&buf
)==-1)
734 if (attributes
& FILE_ATTRIBUTE_READONLY
)
736 if(S_ISDIR(buf
.st_mode
))
738 WARN("FILE_ATTRIBUTE_READONLY ignored for directory.\n");
740 buf
.st_mode
&= ~0222; /* octal!, clear write permission bits */
741 attributes
&= ~FILE_ATTRIBUTE_READONLY
;
745 /* add write permission */
746 buf
.st_mode
|= (0600 | ((buf
.st_mode
& 044) >> 1)) & (~FILE_umask
);
748 if (attributes
& FILE_ATTRIBUTE_DIRECTORY
)
750 if (!S_ISDIR(buf
.st_mode
))
751 FIXME("SetFileAttributes expected the file %s to be a directory\n",
752 debugstr_w(lpFileName
));
753 attributes
&= ~FILE_ATTRIBUTE_DIRECTORY
;
755 attributes
&= ~(FILE_ATTRIBUTE_NORMAL
|FILE_ATTRIBUTE_ARCHIVE
|FILE_ATTRIBUTE_HIDDEN
|
756 FILE_ATTRIBUTE_SYSTEM
|FILE_ATTRIBUTE_TEMPORARY
);
758 FIXME("(%s):%lx attribute(s) not implemented.\n", debugstr_w(lpFileName
), attributes
);
759 if (-1==chmod(full_name
.long_name
,buf
.st_mode
))
761 if (GetDriveTypeW(lpFileName
) == DRIVE_CDROM
)
763 SetLastError( ERROR_ACCESS_DENIED
);
768 * FIXME: We don't return FALSE here because of differences between
769 * Linux and Windows privileges. Under Linux only the owner of
770 * the file is allowed to change file attributes. Under Windows,
771 * applications expect that if you can write to a file, you can also
772 * change its attributes (see GENERIC_WRITE). We could try to be
773 * clever here but that would break multi-user installations where
774 * users share read-only DLLs. This is because some installers like
775 * to change attributes of already installed DLLs.
777 FIXME("Couldn't set file attributes for existing file \"%s\".\n"
778 "Check permissions or set VFAT \"quiet\" mount flag\n", full_name
.long_name
);
784 /**************************************************************************
785 * SetFileAttributesA (KERNEL32.@)
787 BOOL WINAPI
SetFileAttributesA(LPCSTR lpFileName
, DWORD attributes
)
789 UNICODE_STRING filenameW
;
794 SetLastError( ERROR_INVALID_PARAMETER
);
798 if (RtlCreateUnicodeStringFromAsciiz(&filenameW
, lpFileName
))
800 ret
= SetFileAttributesW(filenameW
.Buffer
, attributes
);
801 RtlFreeUnicodeString(&filenameW
);
804 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
809 /******************************************************************************
810 * GetCompressedFileSizeA [KERNEL32.@]
812 DWORD WINAPI
GetCompressedFileSizeA(
814 LPDWORD lpFileSizeHigh
)
816 UNICODE_STRING filenameW
;
819 if (RtlCreateUnicodeStringFromAsciiz(&filenameW
, lpFileName
))
821 ret
= GetCompressedFileSizeW(filenameW
.Buffer
, lpFileSizeHigh
);
822 RtlFreeUnicodeString(&filenameW
);
826 ret
= INVALID_FILE_SIZE
;
827 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
833 /******************************************************************************
834 * GetCompressedFileSizeW [KERNEL32.@]
837 * Success: Low-order doubleword of number of bytes
838 * Failure: INVALID_FILE_SIZE
840 DWORD WINAPI
GetCompressedFileSizeW(
841 LPCWSTR lpFileName
, /* [in] Pointer to name of file */
842 LPDWORD lpFileSizeHigh
) /* [out] Receives high-order doubleword of size */
844 DOS_FULL_NAME full_name
;
848 TRACE("(%s,%p)\n",debugstr_w(lpFileName
),lpFileSizeHigh
);
850 if (!DOSFS_GetFullName( lpFileName
, TRUE
, &full_name
)) return INVALID_FILE_SIZE
;
851 if (stat(full_name
.long_name
, &st
) != 0)
854 return INVALID_FILE_SIZE
;
856 #if HAVE_STRUCT_STAT_ST_BLOCKS
857 /* blocks are 512 bytes long */
858 if (lpFileSizeHigh
) *lpFileSizeHigh
= (st
.st_blocks
>> 23);
859 low
= (DWORD
)(st
.st_blocks
<< 9);
861 if (lpFileSizeHigh
) *lpFileSizeHigh
= (st
.st_size
>> 32);
862 low
= (DWORD
)st
.st_size
;
868 /***********************************************************************
869 * GetFileTime (KERNEL32.@)
871 BOOL WINAPI
GetFileTime( HANDLE hFile
, FILETIME
*lpCreationTime
,
872 FILETIME
*lpLastAccessTime
,
873 FILETIME
*lpLastWriteTime
)
875 BY_HANDLE_FILE_INFORMATION info
;
876 if (!GetFileInformationByHandle( hFile
, &info
)) return FALSE
;
877 if (lpCreationTime
) *lpCreationTime
= info
.ftCreationTime
;
878 if (lpLastAccessTime
) *lpLastAccessTime
= info
.ftLastAccessTime
;
879 if (lpLastWriteTime
) *lpLastWriteTime
= info
.ftLastWriteTime
;
884 /***********************************************************************
885 * GetTempFileNameA (KERNEL32.@)
887 UINT WINAPI
GetTempFileNameA( LPCSTR path
, LPCSTR prefix
, UINT unique
,
890 UNICODE_STRING pathW
, prefixW
;
891 WCHAR bufferW
[MAX_PATH
];
894 if ( !path
|| !prefix
|| !buffer
)
896 SetLastError( ERROR_INVALID_PARAMETER
);
900 RtlCreateUnicodeStringFromAsciiz(&pathW
, path
);
901 RtlCreateUnicodeStringFromAsciiz(&prefixW
, prefix
);
903 ret
= GetTempFileNameW(pathW
.Buffer
, prefixW
.Buffer
, unique
, bufferW
);
905 WideCharToMultiByte(CP_ACP
, 0, bufferW
, -1, buffer
, MAX_PATH
, NULL
, NULL
);
907 RtlFreeUnicodeString(&pathW
);
908 RtlFreeUnicodeString(&prefixW
);
912 /***********************************************************************
913 * GetTempFileNameW (KERNEL32.@)
915 UINT WINAPI
GetTempFileNameW( LPCWSTR path
, LPCWSTR prefix
, UINT unique
,
918 static const WCHAR formatW
[] = {'%','x','.','t','m','p',0};
920 DOS_FULL_NAME full_name
;
924 if ( !path
|| !prefix
|| !buffer
)
926 SetLastError( ERROR_INVALID_PARAMETER
);
930 strcpyW( buffer
, path
);
931 p
= buffer
+ strlenW(buffer
);
933 /* add a \, if there isn't one */
934 if ((p
== buffer
) || (p
[-1] != '\\')) *p
++ = '\\';
936 for (i
= 3; (i
> 0) && (*prefix
); i
--) *p
++ = *prefix
++;
940 if (unique
) sprintfW( p
, formatW
, unique
);
943 /* get a "random" unique number and try to create the file */
945 UINT num
= GetTickCount() & 0xffff;
951 sprintfW( p
, formatW
, unique
);
952 handle
= CreateFileW( buffer
, GENERIC_WRITE
, 0, NULL
,
953 CREATE_NEW
, FILE_ATTRIBUTE_NORMAL
, 0 );
954 if (handle
!= INVALID_HANDLE_VALUE
)
955 { /* We created it */
956 TRACE("created %s\n", debugstr_w(buffer
) );
957 CloseHandle( handle
);
960 if (GetLastError() != ERROR_FILE_EXISTS
&&
961 GetLastError() != ERROR_SHARING_VIOLATION
)
962 break; /* No need to go on */
963 if (!(++unique
& 0xffff)) unique
= 1;
964 } while (unique
!= num
);
967 /* Get the full path name */
969 if (DOSFS_GetFullName( buffer
, FALSE
, &full_name
))
972 /* Check if we have write access in the directory */
973 if ((slash
= strrchr( full_name
.long_name
, '/' ))) *slash
= '\0';
974 if (access( full_name
.long_name
, W_OK
) == -1)
975 WARN("returns %s, which doesn't seem to be writeable.\n",
976 debugstr_w(buffer
) );
978 TRACE("returning %s\n", debugstr_w(buffer
) );
983 /******************************************************************
984 * FILE_ReadWriteApc (internal)
988 static void WINAPI
FILE_ReadWriteApc(void* apc_user
, PIO_STATUS_BLOCK io_status
, ULONG len
)
990 LPOVERLAPPED_COMPLETION_ROUTINE cr
= (LPOVERLAPPED_COMPLETION_ROUTINE
)apc_user
;
992 cr(RtlNtStatusToDosError(io_status
->u
.Status
), len
, (LPOVERLAPPED
)io_status
);
995 /***********************************************************************
996 * ReadFileEx (KERNEL32.@)
998 BOOL WINAPI
ReadFileEx(HANDLE hFile
, LPVOID buffer
, DWORD bytesToRead
,
999 LPOVERLAPPED overlapped
,
1000 LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine
)
1002 LARGE_INTEGER offset
;
1004 PIO_STATUS_BLOCK io_status
;
1008 SetLastError(ERROR_INVALID_PARAMETER
);
1012 offset
.u
.LowPart
= overlapped
->Offset
;
1013 offset
.u
.HighPart
= overlapped
->OffsetHigh
;
1014 io_status
= (PIO_STATUS_BLOCK
)overlapped
;
1015 io_status
->u
.Status
= STATUS_PENDING
;
1017 status
= NtReadFile(hFile
, NULL
, FILE_ReadWriteApc
, lpCompletionRoutine
,
1018 io_status
, buffer
, bytesToRead
, &offset
, NULL
);
1022 SetLastError( RtlNtStatusToDosError(status
) );
1028 /***********************************************************************
1029 * ReadFile (KERNEL32.@)
1031 BOOL WINAPI
ReadFile( HANDLE hFile
, LPVOID buffer
, DWORD bytesToRead
,
1032 LPDWORD bytesRead
, LPOVERLAPPED overlapped
)
1034 LARGE_INTEGER offset
;
1035 PLARGE_INTEGER poffset
= NULL
;
1036 IO_STATUS_BLOCK iosb
;
1037 PIO_STATUS_BLOCK io_status
= &iosb
;
1041 TRACE("%p %p %ld %p %p\n", hFile
, buffer
, bytesToRead
,
1042 bytesRead
, overlapped
);
1044 if (bytesRead
) *bytesRead
= 0; /* Do this before anything else */
1045 if (!bytesToRead
) return TRUE
;
1047 if (IsBadReadPtr(buffer
, bytesToRead
))
1049 SetLastError(ERROR_WRITE_FAULT
); /* FIXME */
1052 if (is_console_handle(hFile
))
1053 return ReadConsoleA(hFile
, buffer
, bytesToRead
, bytesRead
, NULL
);
1055 if (overlapped
!= NULL
)
1057 offset
.u
.LowPart
= overlapped
->Offset
;
1058 offset
.u
.HighPart
= overlapped
->OffsetHigh
;
1060 hEvent
= overlapped
->hEvent
;
1061 io_status
= (PIO_STATUS_BLOCK
)overlapped
;
1063 io_status
->u
.Status
= STATUS_PENDING
;
1064 io_status
->Information
= 0;
1066 status
= NtReadFile(hFile
, hEvent
, NULL
, NULL
, io_status
, buffer
, bytesToRead
, poffset
, NULL
);
1068 if (status
!= STATUS_PENDING
&& bytesRead
)
1069 *bytesRead
= io_status
->Information
;
1071 if (status
&& status
!= STATUS_END_OF_FILE
)
1073 SetLastError( RtlNtStatusToDosError(status
) );
1080 /***********************************************************************
1081 * WriteFileEx (KERNEL32.@)
1083 BOOL WINAPI
WriteFileEx(HANDLE hFile
, LPCVOID buffer
, DWORD bytesToWrite
,
1084 LPOVERLAPPED overlapped
,
1085 LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine
)
1087 LARGE_INTEGER offset
;
1089 PIO_STATUS_BLOCK io_status
;
1091 TRACE("%p %p %ld %p %p\n",
1092 hFile
, buffer
, bytesToWrite
, overlapped
, lpCompletionRoutine
);
1094 if (overlapped
== NULL
)
1096 SetLastError(ERROR_INVALID_PARAMETER
);
1099 offset
.u
.LowPart
= overlapped
->Offset
;
1100 offset
.u
.HighPart
= overlapped
->OffsetHigh
;
1102 io_status
= (PIO_STATUS_BLOCK
)overlapped
;
1103 io_status
->u
.Status
= STATUS_PENDING
;
1105 status
= NtWriteFile(hFile
, NULL
, FILE_ReadWriteApc
, lpCompletionRoutine
,
1106 io_status
, buffer
, bytesToWrite
, &offset
, NULL
);
1108 if (status
) SetLastError( RtlNtStatusToDosError(status
) );
1112 /***********************************************************************
1113 * WriteFile (KERNEL32.@)
1115 BOOL WINAPI
WriteFile( HANDLE hFile
, LPCVOID buffer
, DWORD bytesToWrite
,
1116 LPDWORD bytesWritten
, LPOVERLAPPED overlapped
)
1118 HANDLE hEvent
= NULL
;
1119 LARGE_INTEGER offset
;
1120 PLARGE_INTEGER poffset
= NULL
;
1122 IO_STATUS_BLOCK iosb
;
1123 PIO_STATUS_BLOCK piosb
= &iosb
;
1125 TRACE("%p %p %ld %p %p\n",
1126 hFile
, buffer
, bytesToWrite
, bytesWritten
, overlapped
);
1128 if (is_console_handle(hFile
))
1129 return WriteConsoleA(hFile
, buffer
, bytesToWrite
, bytesWritten
, NULL
);
1131 if (IsBadReadPtr(buffer
, bytesToWrite
))
1133 SetLastError(ERROR_READ_FAULT
); /* FIXME */
1139 offset
.u
.LowPart
= overlapped
->Offset
;
1140 offset
.u
.HighPart
= overlapped
->OffsetHigh
;
1142 hEvent
= overlapped
->hEvent
;
1143 piosb
= (PIO_STATUS_BLOCK
)overlapped
;
1145 piosb
->u
.Status
= STATUS_PENDING
;
1146 piosb
->Information
= 0;
1148 status
= NtWriteFile(hFile
, hEvent
, NULL
, NULL
, piosb
,
1149 buffer
, bytesToWrite
, poffset
, NULL
);
1152 SetLastError( RtlNtStatusToDosError(status
) );
1155 if (bytesWritten
) *bytesWritten
= piosb
->Information
;
1161 /***********************************************************************
1162 * SetFilePointer (KERNEL32.@)
1164 DWORD WINAPI
SetFilePointer( HANDLE hFile
, LONG distance
, LONG
*highword
,
1167 DWORD ret
= INVALID_SET_FILE_POINTER
;
1169 TRACE("handle %p offset %ld high %ld origin %ld\n",
1170 hFile
, distance
, highword
?*highword
:0, method
);
1172 SERVER_START_REQ( set_file_pointer
)
1174 req
->handle
= hFile
;
1175 req
->low
= distance
;
1176 req
->high
= highword
? *highword
: (distance
>= 0) ? 0 : -1;
1177 /* FIXME: assumes 1:1 mapping between Windows and Unix seek constants */
1178 req
->whence
= method
;
1180 if (!wine_server_call_err( req
))
1182 ret
= reply
->new_low
;
1183 if (highword
) *highword
= reply
->new_high
;
1191 /*************************************************************************
1192 * SetHandleCount (KERNEL32.@)
1194 UINT WINAPI
SetHandleCount( UINT count
)
1196 return min( 256, count
);
1200 /**************************************************************************
1201 * SetEndOfFile (KERNEL32.@)
1203 BOOL WINAPI
SetEndOfFile( HANDLE hFile
)
1206 SERVER_START_REQ( truncate_file
)
1208 req
->handle
= hFile
;
1209 ret
= !wine_server_call_err( req
);
1216 /***********************************************************************
1217 * DeleteFileW (KERNEL32.@)
1219 BOOL WINAPI
DeleteFileW( LPCWSTR path
)
1221 DOS_FULL_NAME full_name
;
1224 TRACE("%s\n", debugstr_w(path
) );
1225 if (!path
|| !*path
)
1227 SetLastError(ERROR_PATH_NOT_FOUND
);
1230 if (RtlIsDosDeviceName_U( path
))
1232 WARN("cannot remove DOS device %s!\n", debugstr_w(path
));
1233 SetLastError( ERROR_FILE_NOT_FOUND
);
1237 if (!DOSFS_GetFullName( path
, TRUE
, &full_name
)) return FALSE
;
1239 /* check if we are allowed to delete the source */
1240 hFile
= FILE_CreateFile( full_name
.long_name
, GENERIC_READ
|GENERIC_WRITE
, 0,
1241 NULL
, OPEN_EXISTING
, 0, 0, TRUE
,
1242 GetDriveTypeW( full_name
.short_name
) );
1243 if (!hFile
) return FALSE
;
1245 if (unlink( full_name
.long_name
) == -1)
1256 /***********************************************************************
1257 * DeleteFileA (KERNEL32.@)
1259 BOOL WINAPI
DeleteFileA( LPCSTR path
)
1261 UNICODE_STRING pathW
;
1266 SetLastError(ERROR_INVALID_PARAMETER
);
1270 if (RtlCreateUnicodeStringFromAsciiz(&pathW
, path
))
1272 ret
= DeleteFileW(pathW
.Buffer
);
1273 RtlFreeUnicodeString(&pathW
);
1276 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
1281 /***********************************************************************
1282 * GetFileType (KERNEL32.@)
1284 DWORD WINAPI
GetFileType( HANDLE hFile
)
1286 DWORD ret
= FILE_TYPE_UNKNOWN
;
1288 if (is_console_handle( hFile
))
1289 return FILE_TYPE_CHAR
;
1291 SERVER_START_REQ( get_file_info
)
1293 req
->handle
= hFile
;
1294 if (!wine_server_call_err( req
)) ret
= reply
->type
;
1301 /* check if a file name is for an executable file (.exe or .com) */
1302 inline static BOOL
is_executable( const char *name
)
1304 int len
= strlen(name
);
1306 if (len
< 4) return FALSE
;
1307 return (!strcasecmp( name
+ len
- 4, ".exe" ) ||
1308 !strcasecmp( name
+ len
- 4, ".com" ));
1312 /***********************************************************************
1313 * FILE_AddBootRenameEntry
1315 * Adds an entry to the registry that is loaded when windows boots and
1316 * checks if there are some files to be removed or renamed/moved.
1317 * <fn1> has to be valid and <fn2> may be NULL. If both pointers are
1318 * non-NULL then the file is moved, otherwise it is deleted. The
1319 * entry of the registrykey is always appended with two zero
1320 * terminated strings. If <fn2> is NULL then the second entry is
1321 * simply a single 0-byte. Otherwise the second filename goes
1322 * there. The entries are prepended with \??\ before the path and the
1323 * second filename gets also a '!' as the first character if
1324 * MOVEFILE_REPLACE_EXISTING is set. After the final string another
1325 * 0-byte follows to indicate the end of the strings.
1327 * \??\D:\test\file1[0]
1328 * !\??\D:\test\file1_renamed[0]
1329 * \??\D:\Test|delete[0]
1330 * [0] <- file is to be deleted, second string empty
1331 * \??\D:\test\file2[0]
1332 * !\??\D:\test\file2_renamed[0]
1333 * [0] <- indicates end of strings
1336 * \??\D:\test\file1[0]
1337 * !\??\D:\test\file1_renamed[0]
1338 * \??\D:\Test|delete[0]
1339 * [0] <- file is to be deleted, second string empty
1340 * [0] <- indicates end of strings
1343 static BOOL
FILE_AddBootRenameEntry( LPCWSTR fn1
, LPCWSTR fn2
, DWORD flags
)
1345 static const WCHAR PreString
[] = {'\\','?','?','\\',0};
1346 static const WCHAR ValueName
[] = {'P','e','n','d','i','n','g',
1347 'F','i','l','e','R','e','n','a','m','e',
1348 'O','p','e','r','a','t','i','o','n','s',0};
1349 static const WCHAR SessionW
[] = {'M','a','c','h','i','n','e','\\',
1350 'S','y','s','t','e','m','\\',
1351 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
1352 'C','o','n','t','r','o','l','\\',
1353 'S','e','s','s','i','o','n',' ','M','a','n','a','g','e','r',0};
1354 static const int info_size
= FIELD_OFFSET( KEY_VALUE_PARTIAL_INFORMATION
, Data
);
1356 OBJECT_ATTRIBUTES attr
;
1357 UNICODE_STRING nameW
;
1358 KEY_VALUE_PARTIAL_INFORMATION
*info
;
1361 DWORD len0
, len1
, len2
;
1363 BYTE
*Buffer
= NULL
;
1366 attr
.Length
= sizeof(attr
);
1367 attr
.RootDirectory
= 0;
1368 attr
.ObjectName
= &nameW
;
1369 attr
.Attributes
= 0;
1370 attr
.SecurityDescriptor
= NULL
;
1371 attr
.SecurityQualityOfService
= NULL
;
1372 RtlInitUnicodeString( &nameW
, SessionW
);
1374 if (NtCreateKey( &Reboot
, KEY_ALL_ACCESS
, &attr
, 0, NULL
, 0, NULL
) != STATUS_SUCCESS
)
1376 WARN("Error creating key for reboot managment [%s]\n",
1377 "SYSTEM\\CurrentControlSet\\Control\\Session Manager");
1381 len0
= strlenW(PreString
);
1382 len1
= strlenW(fn1
) + len0
+ 1;
1385 len2
= strlenW(fn2
) + len0
+ 1;
1386 if (flags
& MOVEFILE_REPLACE_EXISTING
) len2
++; /* Plus 1 because of the leading '!' */
1388 else len2
= 1; /* minimum is the 0 characters for the empty second string */
1390 /* convert characters to bytes */
1391 len0
*= sizeof(WCHAR
);
1392 len1
*= sizeof(WCHAR
);
1393 len2
*= sizeof(WCHAR
);
1395 RtlInitUnicodeString( &nameW
, ValueName
);
1397 /* First we check if the key exists and if so how many bytes it already contains. */
1398 if (NtQueryValueKey( Reboot
, &nameW
, KeyValuePartialInformation
,
1399 NULL
, 0, &DataSize
) == STATUS_BUFFER_OVERFLOW
)
1401 if (!(Buffer
= HeapAlloc( GetProcessHeap(), 0, DataSize
+ len1
+ len2
+ sizeof(WCHAR
) )))
1403 if (NtQueryValueKey( Reboot
, &nameW
, KeyValuePartialInformation
,
1404 Buffer
, DataSize
, &DataSize
)) goto Quit
;
1405 info
= (KEY_VALUE_PARTIAL_INFORMATION
*)Buffer
;
1406 if (info
->Type
!= REG_MULTI_SZ
) goto Quit
;
1407 if (DataSize
> sizeof(info
)) DataSize
-= sizeof(WCHAR
); /* remove terminating null (will be added back later) */
1411 DataSize
= info_size
;
1412 if (!(Buffer
= HeapAlloc( GetProcessHeap(), 0, DataSize
+ len1
+ len2
+ sizeof(WCHAR
) )))
1416 p
= (WCHAR
*)(Buffer
+ DataSize
);
1417 strcpyW( p
, PreString
);
1422 p
= (WCHAR
*)(Buffer
+ DataSize
);
1423 if (flags
& MOVEFILE_REPLACE_EXISTING
)
1425 strcpyW( p
, PreString
);
1431 p
= (WCHAR
*)(Buffer
+ DataSize
);
1433 DataSize
+= sizeof(WCHAR
);
1436 /* add final null */
1437 p
= (WCHAR
*)(Buffer
+ DataSize
);
1439 DataSize
+= sizeof(WCHAR
);
1441 rc
= !NtSetValueKey(Reboot
, &nameW
, 0, REG_MULTI_SZ
, Buffer
+ info_size
, DataSize
- info_size
);
1444 if (Reboot
) NtClose(Reboot
);
1445 if (Buffer
) HeapFree( GetProcessHeap(), 0, Buffer
);
1450 /**************************************************************************
1451 * MoveFileExW (KERNEL32.@)
1453 BOOL WINAPI
MoveFileExW( LPCWSTR fn1
, LPCWSTR fn2
, DWORD flag
)
1455 DOS_FULL_NAME full_name1
, full_name2
;
1457 DWORD attr
= INVALID_FILE_ATTRIBUTES
;
1459 TRACE("(%s,%s,%04lx)\n", debugstr_w(fn1
), debugstr_w(fn2
), flag
);
1461 /* FIXME: <Gerhard W. Gruber>sparhawk@gmx.at
1462 In case of W9x and lesser this function should return 120 (ERROR_CALL_NOT_IMPLEMENTED)
1463 to be really compatible. Most programs won't have any problems though. In case
1464 you encounter one, this is what you should return here. I don't know what's up
1465 with NT 3.5. Is this function available there or not?
1466 Does anybody really care about 3.5? :)
1469 /* Filename1 has to be always set to a valid path. Filename2 may be NULL
1470 if the source file has to be deleted.
1473 SetLastError(ERROR_INVALID_PARAMETER
);
1477 /* This function has to be run through in order to process the name properly.
1478 If the BOOTDELAY flag is set, the file doesn't need to exist though. At least
1479 that is the behaviour on NT 4.0. The operation accepts the filenames as
1480 they are given but it can't reply with a reasonable returncode. Success
1481 means in that case success for entering the values into the registry.
1483 if(!DOSFS_GetFullName( fn1
, TRUE
, &full_name1
))
1485 if(!(flag
& MOVEFILE_DELAY_UNTIL_REBOOT
))
1489 if (fn2
) /* !fn2 means delete fn1 */
1491 if (DOSFS_GetFullName( fn2
, TRUE
, &full_name2
))
1493 if(!(flag
& MOVEFILE_DELAY_UNTIL_REBOOT
))
1495 /* target exists, check if we may overwrite */
1496 if (!(flag
& MOVEFILE_REPLACE_EXISTING
))
1498 SetLastError( ERROR_ALREADY_EXISTS
);
1505 if (!DOSFS_GetFullName( fn2
, FALSE
, &full_name2
))
1507 if(!(flag
& MOVEFILE_DELAY_UNTIL_REBOOT
))
1512 /* Source name and target path are valid */
1514 if (flag
& MOVEFILE_DELAY_UNTIL_REBOOT
)
1516 return FILE_AddBootRenameEntry( fn1
, fn2
, flag
);
1519 attr
= GetFileAttributesW( fn1
);
1520 if ( attr
== INVALID_FILE_ATTRIBUTES
) return FALSE
;
1522 /* check if we are allowed to rename the source */
1523 hFile
= FILE_CreateFile( full_name1
.long_name
, 0, 0,
1524 NULL
, OPEN_EXISTING
, 0, 0, TRUE
,
1525 GetDriveTypeW( full_name1
.short_name
) );
1528 if (GetLastError() != ERROR_ACCESS_DENIED
) return FALSE
;
1529 if ( !(attr
& FILE_ATTRIBUTE_DIRECTORY
) ) return FALSE
;
1530 /* if it's a directory we can continue */
1532 else CloseHandle(hFile
);
1534 /* check, if we are allowed to delete the destination,
1535 ** (but the file not being there is fine) */
1536 hFile
= FILE_CreateFile( full_name2
.long_name
, GENERIC_READ
|GENERIC_WRITE
, 0,
1537 NULL
, OPEN_EXISTING
, 0, 0, TRUE
,
1538 GetDriveTypeW( full_name2
.short_name
) );
1539 if(!hFile
&& GetLastError() != ERROR_FILE_NOT_FOUND
) return FALSE
;
1542 if (full_name1
.drive
!= full_name2
.drive
)
1544 if (!(flag
& MOVEFILE_COPY_ALLOWED
))
1546 SetLastError( ERROR_NOT_SAME_DEVICE
);
1549 else if ( attr
& FILE_ATTRIBUTE_DIRECTORY
)
1551 /* Strange, but that's what Windows returns */
1552 SetLastError ( ERROR_ACCESS_DENIED
);
1556 if (rename( full_name1
.long_name
, full_name2
.long_name
) == -1)
1557 /* Try copy/delete unless it's a directory. */
1558 /* FIXME: This does not handle the (unlikely) case that the two locations
1559 are on the same Wine drive, but on different Unix file systems. */
1561 if ( attr
& FILE_ATTRIBUTE_DIRECTORY
)
1568 if ( ! CopyFileW( fn1
, fn2
, !(flag
& MOVEFILE_REPLACE_EXISTING
) ))
1570 if ( ! DeleteFileW ( fn1
) )
1574 if (is_executable( full_name1
.long_name
) != is_executable( full_name2
.long_name
))
1577 if (stat( full_name2
.long_name
, &fstat
) != -1)
1579 if (is_executable( full_name2
.long_name
))
1580 /* set executable bit where read bit is set */
1581 fstat
.st_mode
|= (fstat
.st_mode
& 0444) >> 2;
1583 fstat
.st_mode
&= ~0111;
1584 chmod( full_name2
.long_name
, fstat
.st_mode
);
1589 else /* fn2 == NULL means delete source */
1591 if (flag
& MOVEFILE_DELAY_UNTIL_REBOOT
)
1593 if (flag
& MOVEFILE_COPY_ALLOWED
) {
1594 WARN("Illegal flag\n");
1595 SetLastError( ERROR_GEN_FAILURE
);
1599 return FILE_AddBootRenameEntry( fn1
, NULL
, flag
);
1602 if (unlink( full_name1
.long_name
) == -1)
1607 return TRUE
; /* successfully deleted */
1611 /**************************************************************************
1612 * MoveFileExA (KERNEL32.@)
1614 BOOL WINAPI
MoveFileExA( LPCSTR fn1
, LPCSTR fn2
, DWORD flag
)
1616 UNICODE_STRING fn1W
, fn2W
;
1621 SetLastError(ERROR_INVALID_PARAMETER
);
1625 RtlCreateUnicodeStringFromAsciiz(&fn1W
, fn1
);
1626 if (fn2
) RtlCreateUnicodeStringFromAsciiz(&fn2W
, fn2
);
1627 else fn2W
.Buffer
= NULL
;
1629 ret
= MoveFileExW( fn1W
.Buffer
, fn2W
.Buffer
, flag
);
1631 RtlFreeUnicodeString(&fn1W
);
1632 RtlFreeUnicodeString(&fn2W
);
1637 /**************************************************************************
1638 * MoveFileW (KERNEL32.@)
1640 * Move file or directory
1642 BOOL WINAPI
MoveFileW( LPCWSTR fn1
, LPCWSTR fn2
)
1644 return MoveFileExW( fn1
, fn2
, MOVEFILE_COPY_ALLOWED
);
1648 /**************************************************************************
1649 * MoveFileA (KERNEL32.@)
1651 BOOL WINAPI
MoveFileA( LPCSTR fn1
, LPCSTR fn2
)
1653 return MoveFileExA( fn1
, fn2
, MOVEFILE_COPY_ALLOWED
);
1657 /**************************************************************************
1658 * CopyFileW (KERNEL32.@)
1660 BOOL WINAPI
CopyFileW( LPCWSTR source
, LPCWSTR dest
, BOOL fail_if_exists
)
1663 BY_HANDLE_FILE_INFORMATION info
;
1668 if (!source
|| !dest
)
1670 SetLastError(ERROR_INVALID_PARAMETER
);
1674 TRACE("%s -> %s\n", debugstr_w(source
), debugstr_w(dest
));
1676 if ((h1
= CreateFileW(source
, GENERIC_READ
, FILE_SHARE_READ
| FILE_SHARE_WRITE
,
1677 NULL
, OPEN_EXISTING
, 0, 0)) == INVALID_HANDLE_VALUE
)
1679 WARN("Unable to open source %s\n", debugstr_w(source
));
1683 if (!GetFileInformationByHandle( h1
, &info
))
1685 WARN("GetFileInformationByHandle returned error for %s\n", debugstr_w(source
));
1690 if ((h2
= CreateFileW( dest
, GENERIC_WRITE
, FILE_SHARE_READ
| FILE_SHARE_WRITE
, NULL
,
1691 fail_if_exists
? CREATE_NEW
: CREATE_ALWAYS
,
1692 info
.dwFileAttributes
, h1
)) == INVALID_HANDLE_VALUE
)
1694 WARN("Unable to open dest %s\n", debugstr_w(dest
));
1699 while (ReadFile( h1
, buffer
, sizeof(buffer
), &count
, NULL
) && count
)
1705 if (!WriteFile( h2
, p
, count
, &res
, NULL
) || !res
) goto done
;
1718 /**************************************************************************
1719 * CopyFileA (KERNEL32.@)
1721 BOOL WINAPI
CopyFileA( LPCSTR source
, LPCSTR dest
, BOOL fail_if_exists
)
1723 UNICODE_STRING sourceW
, destW
;
1726 if (!source
|| !dest
)
1728 SetLastError(ERROR_INVALID_PARAMETER
);
1732 RtlCreateUnicodeStringFromAsciiz(&sourceW
, source
);
1733 RtlCreateUnicodeStringFromAsciiz(&destW
, dest
);
1735 ret
= CopyFileW(sourceW
.Buffer
, destW
.Buffer
, fail_if_exists
);
1737 RtlFreeUnicodeString(&sourceW
);
1738 RtlFreeUnicodeString(&destW
);
1743 /**************************************************************************
1744 * CopyFileExW (KERNEL32.@)
1746 * This implementation ignores most of the extra parameters passed-in into
1747 * the "ex" version of the method and calls the CopyFile method.
1748 * It will have to be fixed eventually.
1750 BOOL WINAPI
CopyFileExW(LPCWSTR sourceFilename
, LPCWSTR destFilename
,
1751 LPPROGRESS_ROUTINE progressRoutine
, LPVOID appData
,
1752 LPBOOL cancelFlagPointer
, DWORD copyFlags
)
1755 * Interpret the only flag that CopyFile can interpret.
1757 return CopyFileW(sourceFilename
, destFilename
, (copyFlags
& COPY_FILE_FAIL_IF_EXISTS
) != 0);
1761 /**************************************************************************
1762 * CopyFileExA (KERNEL32.@)
1764 BOOL WINAPI
CopyFileExA(LPCSTR sourceFilename
, LPCSTR destFilename
,
1765 LPPROGRESS_ROUTINE progressRoutine
, LPVOID appData
,
1766 LPBOOL cancelFlagPointer
, DWORD copyFlags
)
1768 UNICODE_STRING sourceW
, destW
;
1771 if (!sourceFilename
|| !destFilename
)
1773 SetLastError(ERROR_INVALID_PARAMETER
);
1777 RtlCreateUnicodeStringFromAsciiz(&sourceW
, sourceFilename
);
1778 RtlCreateUnicodeStringFromAsciiz(&destW
, destFilename
);
1780 ret
= CopyFileExW(sourceW
.Buffer
, destW
.Buffer
, progressRoutine
, appData
,
1781 cancelFlagPointer
, copyFlags
);
1783 RtlFreeUnicodeString(&sourceW
);
1784 RtlFreeUnicodeString(&destW
);
1789 /***********************************************************************
1790 * SetFileTime (KERNEL32.@)
1792 BOOL WINAPI
SetFileTime( HANDLE hFile
,
1793 const FILETIME
*ctime
,
1794 const FILETIME
*atime
,
1795 const FILETIME
*mtime
)
1801 ULONGLONG sec
, nsec
;
1803 if (!(status
= wine_server_handle_to_fd( hFile
, GENERIC_WRITE
, &fd
, NULL
, NULL
)))
1805 struct timeval tv
[2];
1807 if (!atime
|| !mtime
)
1811 tv
[0].tv_sec
= tv
[0].tv_usec
= 0;
1812 tv
[1].tv_sec
= tv
[1].tv_usec
= 0;
1813 if (!fstat( fd
, &st
))
1815 tv
[0].tv_sec
= st
.st_atime
;
1816 tv
[1].tv_sec
= st
.st_mtime
;
1821 sec
= ((ULONGLONG
)atime
->dwHighDateTime
<< 32) | atime
->dwLowDateTime
;
1822 sec
= RtlLargeIntegerDivide( sec
, 10000000, &nsec
);
1823 tv
[0].tv_sec
= sec
- SECS_1601_TO_1970
;
1824 tv
[0].tv_usec
= (UINT
)nsec
/ 10;
1828 sec
= ((ULONGLONG
)mtime
->dwHighDateTime
<< 32) | mtime
->dwLowDateTime
;
1829 sec
= RtlLargeIntegerDivide( sec
, 10000000, &nsec
);
1830 tv
[1].tv_sec
= sec
- SECS_1601_TO_1970
;
1831 tv
[1].tv_usec
= (UINT
)nsec
/ 10;
1834 if (!futimes( fd
, tv
)) ret
= TRUE
;
1835 else FILE_SetDosError();
1836 wine_server_release_fd( hFile
, fd
);
1838 else SetLastError( RtlNtStatusToDosError(status
) );
1841 SetLastError( ERROR_CALL_NOT_IMPLEMENTED
);
1843 #endif /* HAVE_FUTIMES */
1847 /**************************************************************************
1848 * GetFileAttributesExW (KERNEL32.@)
1850 BOOL WINAPI
GetFileAttributesExW(
1851 LPCWSTR lpFileName
, GET_FILEEX_INFO_LEVELS fInfoLevelId
,
1852 LPVOID lpFileInformation
)
1854 DOS_FULL_NAME full_name
;
1855 BY_HANDLE_FILE_INFORMATION info
;
1857 if (!lpFileName
|| !lpFileInformation
)
1859 SetLastError(ERROR_INVALID_PARAMETER
);
1863 if (fInfoLevelId
== GetFileExInfoStandard
) {
1864 LPWIN32_FILE_ATTRIBUTE_DATA lpFad
=
1865 (LPWIN32_FILE_ATTRIBUTE_DATA
) lpFileInformation
;
1866 if (!DOSFS_GetFullName( lpFileName
, TRUE
, &full_name
)) return FALSE
;
1867 if (!FILE_Stat( full_name
.long_name
, &info
, NULL
)) return FALSE
;
1869 lpFad
->dwFileAttributes
= info
.dwFileAttributes
;
1870 lpFad
->ftCreationTime
= info
.ftCreationTime
;
1871 lpFad
->ftLastAccessTime
= info
.ftLastAccessTime
;
1872 lpFad
->ftLastWriteTime
= info
.ftLastWriteTime
;
1873 lpFad
->nFileSizeHigh
= info
.nFileSizeHigh
;
1874 lpFad
->nFileSizeLow
= info
.nFileSizeLow
;
1877 FIXME("invalid info level %d!\n", fInfoLevelId
);
1885 /**************************************************************************
1886 * GetFileAttributesExA (KERNEL32.@)
1888 BOOL WINAPI
GetFileAttributesExA(
1889 LPCSTR filename
, GET_FILEEX_INFO_LEVELS fInfoLevelId
,
1890 LPVOID lpFileInformation
)
1892 UNICODE_STRING filenameW
;
1895 if (!filename
|| !lpFileInformation
)
1897 SetLastError(ERROR_INVALID_PARAMETER
);
1901 if (RtlCreateUnicodeStringFromAsciiz(&filenameW
, filename
))
1903 ret
= GetFileAttributesExW(filenameW
.Buffer
, fInfoLevelId
, lpFileInformation
);
1904 RtlFreeUnicodeString(&filenameW
);
1907 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);