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"
73 #include "kernel_private.h"
76 #include "wine/unicode.h"
77 #include "wine/debug.h"
79 WINE_DEFAULT_DEBUG_CHANNEL(file
);
81 #if defined(MAP_ANONYMOUS) && !defined(MAP_ANON)
82 #define MAP_ANON MAP_ANONYMOUS
85 #define IS_OPTION_TRUE(ch) ((ch) == 'y' || (ch) == 'Y' || (ch) == 't' || (ch) == 'T' || (ch) == '1')
89 /***********************************************************************
92 * Convert OF_* mode into flags for CreateFile.
94 void FILE_ConvertOFMode( INT mode
, DWORD
*access
, DWORD
*sharing
)
98 case OF_READ
: *access
= GENERIC_READ
; break;
99 case OF_WRITE
: *access
= GENERIC_WRITE
; break;
100 case OF_READWRITE
: *access
= GENERIC_READ
| GENERIC_WRITE
; break;
101 default: *access
= 0; break;
105 case OF_SHARE_EXCLUSIVE
: *sharing
= 0; break;
106 case OF_SHARE_DENY_WRITE
: *sharing
= FILE_SHARE_READ
; break;
107 case OF_SHARE_DENY_READ
: *sharing
= FILE_SHARE_WRITE
; break;
108 case OF_SHARE_DENY_NONE
:
109 case OF_SHARE_COMPAT
:
110 default: *sharing
= FILE_SHARE_READ
| FILE_SHARE_WRITE
; break;
115 /***********************************************************************
118 * locale-independent case conversion for file I/O
120 int FILE_strcasecmp( const char *str1
, const char *str2
)
123 for ( ; ; str1
++, str2
++)
124 if ((ret
= FILE_toupper(*str1
) - FILE_toupper(*str2
)) || !*str1
) break;
129 /***********************************************************************
132 * locale-independent case conversion for file I/O
134 int FILE_strncasecmp( const char *str1
, const char *str2
, int len
)
137 for ( ; len
> 0; len
--, str1
++, str2
++)
138 if ((ret
= FILE_toupper(*str1
) - FILE_toupper(*str2
)) || !*str1
) break;
143 /***********************************************************************
146 * Set the DOS error code from errno.
148 void FILE_SetDosError(void)
150 int save_errno
= errno
; /* errno gets overwritten by printf */
152 TRACE("errno = %d %s\n", errno
, strerror(errno
));
156 SetLastError( ERROR_SHARING_VIOLATION
);
159 SetLastError( ERROR_INVALID_HANDLE
);
162 SetLastError( ERROR_HANDLE_DISK_FULL
);
167 SetLastError( ERROR_ACCESS_DENIED
);
170 SetLastError( ERROR_LOCK_VIOLATION
);
173 SetLastError( ERROR_FILE_NOT_FOUND
);
176 SetLastError( ERROR_CANNOT_MAKE
);
180 SetLastError( ERROR_NO_MORE_FILES
);
183 SetLastError( ERROR_FILE_EXISTS
);
187 SetLastError( ERROR_SEEK
);
190 SetLastError( ERROR_DIR_NOT_EMPTY
);
193 SetLastError( ERROR_BAD_FORMAT
);
196 WARN("unknown file error: %s\n", strerror(save_errno
) );
197 SetLastError( ERROR_GEN_FAILURE
);
204 /***********************************************************************
207 * Implementation of CreateFile. Takes a Unix path name.
208 * Returns 0 on failure.
210 HANDLE
FILE_CreateFile( LPCSTR filename
, DWORD access
, DWORD sharing
,
211 LPSECURITY_ATTRIBUTES sa
, DWORD creation
,
212 DWORD attributes
, HANDLE
template, BOOL fail_read_only
,
220 SERVER_START_REQ( create_file
)
222 req
->access
= access
;
223 req
->inherit
= (sa
&& (sa
->nLength
>=sizeof(*sa
)) && sa
->bInheritHandle
);
224 req
->sharing
= sharing
;
225 req
->create
= creation
;
226 req
->attrs
= attributes
;
227 req
->removable
= (drive_type
== DRIVE_REMOVABLE
|| drive_type
== DRIVE_CDROM
);
228 wine_server_add_data( req
, filename
, strlen(filename
) );
230 err
= wine_server_call( req
);
235 /* If write access failed, retry without GENERIC_WRITE */
237 if (!ret
&& !fail_read_only
&& (access
& GENERIC_WRITE
))
239 if ((err
== STATUS_MEDIA_WRITE_PROTECTED
) || (err
== STATUS_ACCESS_DENIED
))
241 TRACE("Write access failed for file '%s', trying without "
242 "write access\n", filename
);
243 access
&= ~GENERIC_WRITE
;
250 /* In the case file creation was rejected due to CREATE_NEW flag
251 * was specified and file with that name already exists, correct
252 * last error is ERROR_FILE_EXISTS and not ERROR_ALREADY_EXISTS.
253 * Note: RtlNtStatusToDosError is not the subject to blame here.
255 if (err
== STATUS_OBJECT_NAME_COLLISION
)
256 SetLastError( ERROR_FILE_EXISTS
);
258 SetLastError( RtlNtStatusToDosError(err
) );
261 if (!ret
) WARN("Unable to create file '%s' (GLE %ld)\n", filename
, GetLastError());
267 static HANDLE
FILE_OpenPipe(LPCWSTR name
, DWORD access
, LPSECURITY_ATTRIBUTES sa
)
272 if (name
&& (len
= strlenW(name
)) > MAX_PATH
)
274 SetLastError( ERROR_FILENAME_EXCED_RANGE
);
277 SERVER_START_REQ( open_named_pipe
)
279 req
->access
= access
;
280 req
->inherit
= (sa
&& (sa
->nLength
>=sizeof(*sa
)) && sa
->bInheritHandle
);
282 wine_server_add_data( req
, name
, len
* sizeof(WCHAR
) );
283 wine_server_call_err( req
);
287 TRACE("Returned %p\n",ret
);
291 /*************************************************************************
292 * CreateFileW [KERNEL32.@] Creates or opens a file or other object
294 * Creates or opens an object, and returns a handle that can be used to
295 * access that object.
299 * filename [in] pointer to filename to be accessed
300 * access [in] access mode requested
301 * sharing [in] share mode
302 * sa [in] pointer to security attributes
303 * creation [in] how to create the file
304 * attributes [in] attributes for newly created file
305 * template [in] handle to file with extended attributes to copy
308 * Success: Open handle to specified file
309 * Failure: INVALID_HANDLE_VALUE
312 * Should call SetLastError() on failure.
316 * Doesn't support character devices, template files, or a
317 * lot of the 'attributes' flags yet.
319 HANDLE WINAPI
CreateFileW( LPCWSTR filename
, DWORD access
, DWORD sharing
,
320 LPSECURITY_ATTRIBUTES sa
, DWORD creation
,
321 DWORD attributes
, HANDLE
template )
323 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 /* If the name starts with '\\?\', ignore the first 4 chars. */
350 if (!strncmpW(filename
, bkslashes_with_question_markW
, 4))
352 static const WCHAR uncW
[] = {'U','N','C','\\',0};
354 if (!strncmpiW(filename
, uncW
, 4))
356 FIXME("UNC name (%s) not supported.\n", debugstr_w(filename
) );
357 SetLastError( ERROR_PATH_NOT_FOUND
);
358 return INVALID_HANDLE_VALUE
;
362 if (!strncmpW(filename
, bkslashes_with_dotW
, 4))
364 static const WCHAR pipeW
[] = {'P','I','P','E','\\',0};
365 if(!strncmpiW(filename
+ 4, pipeW
, 5))
367 TRACE("Opening a pipe: %s\n", debugstr_w(filename
));
368 ret
= FILE_OpenPipe( filename
, access
, sa
);
371 else if (isalphaW(filename
[4]) && filename
[5] == ':' && filename
[6] == '\0')
373 const char *device
= DRIVE_GetDevice( toupperW(filename
[4]) - 'A' );
376 ret
= FILE_CreateFile( device
, access
, sharing
, sa
, creation
,
377 attributes
, template, TRUE
, DRIVE_FIXED
);
381 SetLastError( ERROR_ACCESS_DENIED
);
382 ret
= INVALID_HANDLE_VALUE
;
386 else if (!RtlIsDosDeviceName_U( filename
))
388 ret
= VXD_Open( filename
+4, access
, sa
);
392 filename
+=4; /* fall into DOSFS_Device case below */
395 /* If the name still starts with '\\', it's a UNC name. */
396 if (!strncmpW(filename
, bkslashesW
, 2))
398 ret
= SMB_CreateFileW(filename
, access
, sharing
, sa
, creation
, attributes
, template );
402 /* If the name contains a DOS wild card (* or ?), do no create a file */
403 if(strchrW(filename
, '*') || strchrW(filename
, '?'))
405 SetLastError(ERROR_BAD_PATHNAME
);
406 return INVALID_HANDLE_VALUE
;
409 /* Open a console for CONIN$ or CONOUT$ */
410 if (!strcmpiW(filename
, coninW
) || !strcmpiW(filename
, conoutW
))
412 ret
= OpenConsoleW(filename
, access
, sa
, creation
);
416 if (RtlIsDosDeviceName_U( filename
))
418 TRACE("opening device %s\n", debugstr_w(filename
) );
420 if (!(ret
= DOSFS_OpenDevice( filename
, access
, attributes
, sa
)))
422 /* Do not silence this please. It is a critical error. -MM */
423 ERR("Couldn't open device %s!\n", debugstr_w(filename
));
424 SetLastError( ERROR_FILE_NOT_FOUND
);
429 /* check for filename, don't check for last entry if creating */
430 if (!DOSFS_GetFullName( filename
,
431 (creation
== OPEN_EXISTING
) ||
432 (creation
== TRUNCATE_EXISTING
),
434 WARN("Unable to get full filename from %s (GLE %ld)\n",
435 debugstr_w(filename
), GetLastError());
436 return INVALID_HANDLE_VALUE
;
439 ret
= FILE_CreateFile( full_name
.long_name
, access
, sharing
,
440 sa
, creation
, attributes
, template,
441 DRIVE_GetFlags(full_name
.drive
) & DRIVE_FAIL_READ_ONLY
,
442 GetDriveTypeW( full_name
.short_name
) );
444 if (!ret
) ret
= INVALID_HANDLE_VALUE
;
445 TRACE("returning %p\n", ret
);
451 /*************************************************************************
452 * CreateFileA (KERNEL32.@)
454 HANDLE WINAPI
CreateFileA( LPCSTR filename
, DWORD access
, DWORD sharing
,
455 LPSECURITY_ATTRIBUTES sa
, DWORD creation
,
456 DWORD attributes
, HANDLE
template)
458 UNICODE_STRING filenameW
;
459 HANDLE ret
= INVALID_HANDLE_VALUE
;
463 SetLastError( ERROR_INVALID_PARAMETER
);
464 return INVALID_HANDLE_VALUE
;
467 if (RtlCreateUnicodeStringFromAsciiz(&filenameW
, filename
))
469 ret
= CreateFileW(filenameW
.Buffer
, access
, sharing
, sa
, creation
,
470 attributes
, template);
471 RtlFreeUnicodeString(&filenameW
);
474 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
479 /***********************************************************************
482 * Fill a file information from a struct stat.
484 static void FILE_FillInfo( struct stat
*st
, BY_HANDLE_FILE_INFORMATION
*info
)
486 if (S_ISDIR(st
->st_mode
))
487 info
->dwFileAttributes
= FILE_ATTRIBUTE_DIRECTORY
;
489 info
->dwFileAttributes
= FILE_ATTRIBUTE_ARCHIVE
;
490 if (!(st
->st_mode
& S_IWUSR
))
491 info
->dwFileAttributes
|= FILE_ATTRIBUTE_READONLY
;
493 RtlSecondsSince1970ToTime( st
->st_mtime
, (LARGE_INTEGER
*)&info
->ftCreationTime
);
494 RtlSecondsSince1970ToTime( st
->st_mtime
, (LARGE_INTEGER
*)&info
->ftLastWriteTime
);
495 RtlSecondsSince1970ToTime( st
->st_atime
, (LARGE_INTEGER
*)&info
->ftLastAccessTime
);
497 info
->dwVolumeSerialNumber
= 0; /* FIXME */
498 info
->nFileSizeHigh
= 0;
499 info
->nFileSizeLow
= 0;
500 if (!S_ISDIR(st
->st_mode
)) {
501 info
->nFileSizeHigh
= st
->st_size
>> 32;
502 info
->nFileSizeLow
= st
->st_size
& 0xffffffff;
504 info
->nNumberOfLinks
= st
->st_nlink
;
505 info
->nFileIndexHigh
= 0;
506 info
->nFileIndexLow
= st
->st_ino
;
510 /***********************************************************************
511 * get_show_dot_files_option
513 static BOOL
get_show_dot_files_option(void)
515 static const WCHAR WineW
[] = {'M','a','c','h','i','n','e','\\',
516 'S','o','f','t','w','a','r','e','\\',
517 'W','i','n','e','\\','W','i','n','e','\\',
518 'C','o','n','f','i','g','\\','W','i','n','e',0};
519 static const WCHAR ShowDotFilesW
[] = {'S','h','o','w','D','o','t','F','i','l','e','s',0};
524 OBJECT_ATTRIBUTES attr
;
525 UNICODE_STRING nameW
;
528 attr
.Length
= sizeof(attr
);
529 attr
.RootDirectory
= 0;
530 attr
.ObjectName
= &nameW
;
532 attr
.SecurityDescriptor
= NULL
;
533 attr
.SecurityQualityOfService
= NULL
;
534 RtlInitUnicodeString( &nameW
, WineW
);
536 if (!NtOpenKey( &hkey
, KEY_ALL_ACCESS
, &attr
))
538 RtlInitUnicodeString( &nameW
, ShowDotFilesW
);
539 if (!NtQueryValueKey( hkey
, &nameW
, KeyValuePartialInformation
, tmp
, sizeof(tmp
), &dummy
))
541 WCHAR
*str
= (WCHAR
*)((KEY_VALUE_PARTIAL_INFORMATION
*)tmp
)->Data
;
542 ret
= IS_OPTION_TRUE( str
[0] );
550 /***********************************************************************
553 * Stat a Unix path name. Return TRUE if OK.
555 BOOL
FILE_Stat( LPCSTR unixName
, BY_HANDLE_FILE_INFORMATION
*info
, BOOL
*is_symlink_ptr
)
561 if (lstat( unixName
, &st
) == -1)
566 is_symlink
= S_ISLNK(st
.st_mode
);
569 /* do a "real" stat to find out
570 about the type of the symlink destination */
571 if (stat( unixName
, &st
) == -1)
578 /* fill in the information we gathered so far */
579 FILE_FillInfo( &st
, info
);
581 /* and now see if this is a hidden file, based on the name */
582 p
= strrchr( unixName
, '/');
583 p
= p
? p
+ 1 : unixName
;
584 if (*p
== '.' && *(p
+1) && (*(p
+1) != '.' || *(p
+2)))
586 static int show_dot_files
= -1;
587 if (show_dot_files
== -1)
588 show_dot_files
= get_show_dot_files_option();
590 info
->dwFileAttributes
|= FILE_ATTRIBUTE_HIDDEN
;
592 if (is_symlink_ptr
) *is_symlink_ptr
= is_symlink
;
597 /***********************************************************************
598 * GetFileInformationByHandle (KERNEL32.@)
600 DWORD WINAPI
GetFileInformationByHandle( HANDLE hFile
,
601 BY_HANDLE_FILE_INFORMATION
*info
)
606 TRACE("%p\n", hFile
);
608 SERVER_START_REQ( get_file_info
)
611 if ((ret
= !wine_server_call_err( req
)))
613 /* FIXME: which file types are supported ?
614 * Serial ports (FILE_TYPE_CHAR) are not,
615 * and MSDN also says that pipes are not supported.
616 * FILE_TYPE_REMOTE seems to be supported according to
617 * MSDN q234741.txt */
618 if ((reply
->type
== FILE_TYPE_DISK
) || (reply
->type
== FILE_TYPE_REMOTE
))
620 RtlSecondsSince1970ToTime( reply
->write_time
, (LARGE_INTEGER
*)&info
->ftCreationTime
);
621 RtlSecondsSince1970ToTime( reply
->write_time
, (LARGE_INTEGER
*)&info
->ftLastWriteTime
);
622 RtlSecondsSince1970ToTime( reply
->access_time
, (LARGE_INTEGER
*)&info
->ftLastAccessTime
);
623 info
->dwFileAttributes
= reply
->attr
;
624 info
->dwVolumeSerialNumber
= reply
->serial
;
625 info
->nFileSizeHigh
= reply
->size_high
;
626 info
->nFileSizeLow
= reply
->size_low
;
627 info
->nNumberOfLinks
= reply
->links
;
628 info
->nFileIndexHigh
= reply
->index_high
;
629 info
->nFileIndexLow
= reply
->index_low
;
633 SetLastError(ERROR_NOT_SUPPORTED
);
643 /**************************************************************************
644 * GetFileAttributesW (KERNEL32.@)
646 DWORD WINAPI
GetFileAttributesW( LPCWSTR name
)
648 DOS_FULL_NAME full_name
;
649 BY_HANDLE_FILE_INFORMATION info
;
653 SetLastError( ERROR_INVALID_PARAMETER
);
654 return INVALID_FILE_ATTRIBUTES
;
656 if (!DOSFS_GetFullName( name
, TRUE
, &full_name
) )
657 return INVALID_FILE_ATTRIBUTES
;
658 if (!FILE_Stat( full_name
.long_name
, &info
, NULL
))
659 return INVALID_FILE_ATTRIBUTES
;
660 return info
.dwFileAttributes
;
664 /**************************************************************************
665 * GetFileAttributesA (KERNEL32.@)
667 DWORD WINAPI
GetFileAttributesA( LPCSTR name
)
669 UNICODE_STRING nameW
;
670 DWORD ret
= INVALID_FILE_ATTRIBUTES
;
674 SetLastError( ERROR_INVALID_PARAMETER
);
675 return INVALID_FILE_ATTRIBUTES
;
678 if (RtlCreateUnicodeStringFromAsciiz(&nameW
, name
))
680 ret
= GetFileAttributesW(nameW
.Buffer
);
681 RtlFreeUnicodeString(&nameW
);
684 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
689 /**************************************************************************
690 * SetFileAttributesW (KERNEL32.@)
692 BOOL WINAPI
SetFileAttributesW(LPCWSTR lpFileName
, DWORD attributes
)
695 DOS_FULL_NAME full_name
;
699 SetLastError( ERROR_INVALID_PARAMETER
);
703 TRACE("(%s,%lx)\n", debugstr_w(lpFileName
), attributes
);
705 if (!DOSFS_GetFullName( lpFileName
, TRUE
, &full_name
))
708 if(stat(full_name
.long_name
,&buf
)==-1)
713 if (attributes
& FILE_ATTRIBUTE_READONLY
)
715 if(S_ISDIR(buf
.st_mode
))
717 WARN("FILE_ATTRIBUTE_READONLY ignored for directory.\n");
719 buf
.st_mode
&= ~0222; /* octal!, clear write permission bits */
720 attributes
&= ~FILE_ATTRIBUTE_READONLY
;
724 /* add write permission */
725 buf
.st_mode
|= (0600 | ((buf
.st_mode
& 044) >> 1)) & (~FILE_umask
);
727 if (attributes
& FILE_ATTRIBUTE_DIRECTORY
)
729 if (!S_ISDIR(buf
.st_mode
))
730 FIXME("SetFileAttributes expected the file %s to be a directory\n",
731 debugstr_w(lpFileName
));
732 attributes
&= ~FILE_ATTRIBUTE_DIRECTORY
;
734 attributes
&= ~(FILE_ATTRIBUTE_NORMAL
|FILE_ATTRIBUTE_ARCHIVE
|FILE_ATTRIBUTE_HIDDEN
|
735 FILE_ATTRIBUTE_SYSTEM
|FILE_ATTRIBUTE_TEMPORARY
);
737 FIXME("(%s):%lx attribute(s) not implemented.\n", debugstr_w(lpFileName
), attributes
);
738 if (-1==chmod(full_name
.long_name
,buf
.st_mode
))
740 if (GetDriveTypeW(lpFileName
) == DRIVE_CDROM
)
742 SetLastError( ERROR_ACCESS_DENIED
);
747 * FIXME: We don't return FALSE here because of differences between
748 * Linux and Windows privileges. Under Linux only the owner of
749 * the file is allowed to change file attributes. Under Windows,
750 * applications expect that if you can write to a file, you can also
751 * change its attributes (see GENERIC_WRITE). We could try to be
752 * clever here but that would break multi-user installations where
753 * users share read-only DLLs. This is because some installers like
754 * to change attributes of already installed DLLs.
756 FIXME("Couldn't set file attributes for existing file \"%s\".\n"
757 "Check permissions or set VFAT \"quiet\" mount flag\n", full_name
.long_name
);
763 /**************************************************************************
764 * SetFileAttributesA (KERNEL32.@)
766 BOOL WINAPI
SetFileAttributesA(LPCSTR lpFileName
, DWORD attributes
)
768 UNICODE_STRING filenameW
;
773 SetLastError( ERROR_INVALID_PARAMETER
);
777 if (RtlCreateUnicodeStringFromAsciiz(&filenameW
, lpFileName
))
779 ret
= SetFileAttributesW(filenameW
.Buffer
, attributes
);
780 RtlFreeUnicodeString(&filenameW
);
783 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
788 /******************************************************************************
789 * GetCompressedFileSizeA [KERNEL32.@]
791 DWORD WINAPI
GetCompressedFileSizeA(
793 LPDWORD lpFileSizeHigh
)
795 UNICODE_STRING filenameW
;
798 if (RtlCreateUnicodeStringFromAsciiz(&filenameW
, lpFileName
))
800 ret
= GetCompressedFileSizeW(filenameW
.Buffer
, lpFileSizeHigh
);
801 RtlFreeUnicodeString(&filenameW
);
805 ret
= INVALID_FILE_SIZE
;
806 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
812 /******************************************************************************
813 * GetCompressedFileSizeW [KERNEL32.@]
816 * Success: Low-order doubleword of number of bytes
817 * Failure: INVALID_FILE_SIZE
819 DWORD WINAPI
GetCompressedFileSizeW(
820 LPCWSTR lpFileName
, /* [in] Pointer to name of file */
821 LPDWORD lpFileSizeHigh
) /* [out] Receives high-order doubleword of size */
823 DOS_FULL_NAME full_name
;
827 TRACE("(%s,%p)\n",debugstr_w(lpFileName
),lpFileSizeHigh
);
829 if (!DOSFS_GetFullName( lpFileName
, TRUE
, &full_name
)) return INVALID_FILE_SIZE
;
830 if (stat(full_name
.long_name
, &st
) != 0)
833 return INVALID_FILE_SIZE
;
835 #if HAVE_STRUCT_STAT_ST_BLOCKS
836 /* blocks are 512 bytes long */
837 if (lpFileSizeHigh
) *lpFileSizeHigh
= (st
.st_blocks
>> 23);
838 low
= (DWORD
)(st
.st_blocks
<< 9);
840 if (lpFileSizeHigh
) *lpFileSizeHigh
= (st
.st_size
>> 32);
841 low
= (DWORD
)st
.st_size
;
847 /***********************************************************************
848 * GetFileTime (KERNEL32.@)
850 BOOL WINAPI
GetFileTime( HANDLE hFile
, FILETIME
*lpCreationTime
,
851 FILETIME
*lpLastAccessTime
,
852 FILETIME
*lpLastWriteTime
)
854 BY_HANDLE_FILE_INFORMATION info
;
855 if (!GetFileInformationByHandle( hFile
, &info
)) return FALSE
;
856 if (lpCreationTime
) *lpCreationTime
= info
.ftCreationTime
;
857 if (lpLastAccessTime
) *lpLastAccessTime
= info
.ftLastAccessTime
;
858 if (lpLastWriteTime
) *lpLastWriteTime
= info
.ftLastWriteTime
;
863 /***********************************************************************
864 * GetTempFileNameA (KERNEL32.@)
866 UINT WINAPI
GetTempFileNameA( LPCSTR path
, LPCSTR prefix
, UINT unique
,
869 UNICODE_STRING pathW
, prefixW
;
870 WCHAR bufferW
[MAX_PATH
];
873 if ( !path
|| !prefix
|| !buffer
)
875 SetLastError( ERROR_INVALID_PARAMETER
);
879 RtlCreateUnicodeStringFromAsciiz(&pathW
, path
);
880 RtlCreateUnicodeStringFromAsciiz(&prefixW
, prefix
);
882 ret
= GetTempFileNameW(pathW
.Buffer
, prefixW
.Buffer
, unique
, bufferW
);
884 WideCharToMultiByte(CP_ACP
, 0, bufferW
, -1, buffer
, MAX_PATH
, NULL
, NULL
);
886 RtlFreeUnicodeString(&pathW
);
887 RtlFreeUnicodeString(&prefixW
);
891 /***********************************************************************
892 * GetTempFileNameW (KERNEL32.@)
894 UINT WINAPI
GetTempFileNameW( LPCWSTR path
, LPCWSTR prefix
, UINT unique
,
897 static const WCHAR formatW
[] = {'%','x','.','t','m','p',0};
899 DOS_FULL_NAME full_name
;
903 if ( !path
|| !prefix
|| !buffer
)
905 SetLastError( ERROR_INVALID_PARAMETER
);
909 strcpyW( buffer
, path
);
910 p
= buffer
+ strlenW(buffer
);
912 /* add a \, if there isn't one */
913 if ((p
== buffer
) || (p
[-1] != '\\')) *p
++ = '\\';
915 for (i
= 3; (i
> 0) && (*prefix
); i
--) *p
++ = *prefix
++;
919 if (unique
) sprintfW( p
, formatW
, unique
);
922 /* get a "random" unique number and try to create the file */
924 UINT num
= GetTickCount() & 0xffff;
930 sprintfW( p
, formatW
, unique
);
931 handle
= CreateFileW( buffer
, GENERIC_WRITE
, 0, NULL
,
932 CREATE_NEW
, FILE_ATTRIBUTE_NORMAL
, 0 );
933 if (handle
!= INVALID_HANDLE_VALUE
)
934 { /* We created it */
935 TRACE("created %s\n", debugstr_w(buffer
) );
936 CloseHandle( handle
);
939 if (GetLastError() != ERROR_FILE_EXISTS
&&
940 GetLastError() != ERROR_SHARING_VIOLATION
)
941 break; /* No need to go on */
942 if (!(++unique
& 0xffff)) unique
= 1;
943 } while (unique
!= num
);
946 /* Get the full path name */
948 if (DOSFS_GetFullName( buffer
, FALSE
, &full_name
))
951 /* Check if we have write access in the directory */
952 if ((slash
= strrchr( full_name
.long_name
, '/' ))) *slash
= '\0';
953 if (access( full_name
.long_name
, W_OK
) == -1)
954 WARN("returns %s, which doesn't seem to be writeable.\n",
955 debugstr_w(buffer
) );
957 TRACE("returning %s\n", debugstr_w(buffer
) );
962 /***********************************************************************
965 * Implementation of OpenFile16() and OpenFile32().
967 static HFILE
FILE_DoOpenFile( LPCSTR name
, OFSTRUCT
*ofs
, UINT mode
, BOOL win32
)
972 WORD filedatetime
[2];
973 DOS_FULL_NAME full_name
;
974 DWORD access
, sharing
;
976 WCHAR buffer
[MAX_PATH
];
979 if (!ofs
) return HFILE_ERROR
;
981 TRACE("%s %s %s %s%s%s%s%s%s%s%s%s\n",name
,
982 ((mode
& 0x3 )==OF_READ
)?"OF_READ":
983 ((mode
& 0x3 )==OF_WRITE
)?"OF_WRITE":
984 ((mode
& 0x3 )==OF_READWRITE
)?"OF_READWRITE":"unknown",
985 ((mode
& 0x70 )==OF_SHARE_COMPAT
)?"OF_SHARE_COMPAT":
986 ((mode
& 0x70 )==OF_SHARE_DENY_NONE
)?"OF_SHARE_DENY_NONE":
987 ((mode
& 0x70 )==OF_SHARE_DENY_READ
)?"OF_SHARE_DENY_READ":
988 ((mode
& 0x70 )==OF_SHARE_DENY_WRITE
)?"OF_SHARE_DENY_WRITE":
989 ((mode
& 0x70 )==OF_SHARE_EXCLUSIVE
)?"OF_SHARE_EXCLUSIVE":"unknown",
990 ((mode
& OF_PARSE
)==OF_PARSE
)?"OF_PARSE ":"",
991 ((mode
& OF_DELETE
)==OF_DELETE
)?"OF_DELETE ":"",
992 ((mode
& OF_VERIFY
)==OF_VERIFY
)?"OF_VERIFY ":"",
993 ((mode
& OF_SEARCH
)==OF_SEARCH
)?"OF_SEARCH ":"",
994 ((mode
& OF_CANCEL
)==OF_CANCEL
)?"OF_CANCEL ":"",
995 ((mode
& OF_CREATE
)==OF_CREATE
)?"OF_CREATE ":"",
996 ((mode
& OF_PROMPT
)==OF_PROMPT
)?"OF_PROMPT ":"",
997 ((mode
& OF_EXIST
)==OF_EXIST
)?"OF_EXIST ":"",
998 ((mode
& OF_REOPEN
)==OF_REOPEN
)?"OF_REOPEN ":""
1002 ofs
->cBytes
= sizeof(OFSTRUCT
);
1004 if (mode
& OF_REOPEN
) name
= ofs
->szPathName
;
1007 ERR("called with `name' set to NULL ! Please debug.\n");
1011 TRACE("%s %04x\n", name
, mode
);
1013 /* the watcom 10.6 IDE relies on a valid path returned in ofs->szPathName
1014 Are there any cases where getting the path here is wrong?
1015 Uwe Bonnes 1997 Apr 2 */
1016 if (!GetFullPathNameA( name
, sizeof(ofs
->szPathName
),
1017 ofs
->szPathName
, NULL
)) goto error
;
1018 FILE_ConvertOFMode( mode
, &access
, &sharing
);
1020 /* OF_PARSE simply fills the structure */
1022 if (mode
& OF_PARSE
)
1024 ofs
->fFixedDisk
= (GetDriveType16( ofs
->szPathName
[0]-'A' )
1025 != DRIVE_REMOVABLE
);
1026 TRACE("(%s): OF_PARSE, res = '%s'\n",
1027 name
, ofs
->szPathName
);
1031 /* OF_CREATE is completely different from all other options, so
1034 if (mode
& OF_CREATE
)
1036 if ((handle
= CreateFileA( name
, GENERIC_READ
| GENERIC_WRITE
,
1037 sharing
, NULL
, CREATE_ALWAYS
,
1038 FILE_ATTRIBUTE_NORMAL
, 0 ))== INVALID_HANDLE_VALUE
)
1043 MultiByteToWideChar(CP_ACP
, 0, name
, -1, buffer
, MAX_PATH
);
1046 /* If OF_SEARCH is set, ignore the given path */
1048 if ((mode
& OF_SEARCH
) && !(mode
& OF_REOPEN
))
1050 /* First try the file name as is */
1051 if (DOSFS_GetFullName( nameW
, TRUE
, &full_name
)) goto found
;
1052 /* Now remove the path */
1053 if (nameW
[0] && (nameW
[1] == ':')) nameW
+= 2;
1054 if ((p
= strrchrW( nameW
, '\\' ))) nameW
= p
+ 1;
1055 if ((p
= strrchrW( nameW
, '/' ))) nameW
= p
+ 1;
1056 if (!nameW
[0]) goto not_found
;
1059 /* Now look for the file */
1061 if (!DIR_SearchPath( NULL
, nameW
, NULL
, &full_name
, win32
)) goto not_found
;
1064 TRACE("found %s = %s\n",
1065 full_name
.long_name
, debugstr_w(full_name
.short_name
) );
1066 WideCharToMultiByte(CP_ACP
, 0, full_name
.short_name
, -1,
1067 ofs
->szPathName
, sizeof(ofs
->szPathName
), NULL
, NULL
);
1069 if (mode
& OF_DELETE
)
1071 handle
= FILE_CreateFile( full_name
.long_name
, GENERIC_READ
|GENERIC_WRITE
, 0,
1072 NULL
, OPEN_EXISTING
, 0, 0, TRUE
,
1073 GetDriveTypeW( full_name
.short_name
) );
1074 if (!handle
) goto error
;
1075 CloseHandle( handle
);
1076 if (unlink( full_name
.long_name
) == -1) goto not_found
;
1077 TRACE("(%s): OF_DELETE return = OK\n", name
);
1081 handle
= FILE_CreateFile( full_name
.long_name
, access
, sharing
,
1082 NULL
, OPEN_EXISTING
, 0, 0,
1083 DRIVE_GetFlags(full_name
.drive
) & DRIVE_FAIL_READ_ONLY
,
1084 GetDriveTypeW( full_name
.short_name
) );
1085 if (!handle
) goto not_found
;
1087 GetFileTime( handle
, NULL
, NULL
, &filetime
);
1088 FileTimeToDosDateTime( &filetime
, &filedatetime
[0], &filedatetime
[1] );
1089 if ((mode
& OF_VERIFY
) && (mode
& OF_REOPEN
))
1091 if (ofs
->Reserved1
!= filedatetime
[0] || ofs
->Reserved2
!= filedatetime
[1] )
1093 CloseHandle( handle
);
1094 WARN("(%s): OF_VERIFY failed\n", name
);
1095 /* FIXME: what error here? */
1096 SetLastError( ERROR_FILE_NOT_FOUND
);
1100 ofs
->Reserved1
= filedatetime
[0];
1101 ofs
->Reserved2
= filedatetime
[1];
1103 success
: /* We get here if the open was successful */
1104 TRACE("(%s): OK, return = %p\n", name
, handle
);
1107 hFileRet
= (HFILE
)handle
;
1108 if (mode
& OF_EXIST
) /* Return the handle, but close it first */
1109 CloseHandle( handle
);
1113 hFileRet
= Win32HandleToDosFileHandle( handle
);
1114 if (hFileRet
== HFILE_ERROR16
) goto error
;
1115 if (mode
& OF_EXIST
) /* Return the handle, but close it first */
1116 _lclose16( hFileRet
);
1120 not_found
: /* We get here if the file does not exist */
1121 WARN("'%s' not found or sharing violation\n", name
);
1122 SetLastError( ERROR_FILE_NOT_FOUND
);
1125 error
: /* We get here if there was an error opening the file */
1126 ofs
->nErrCode
= GetLastError();
1127 WARN("(%s): return = HFILE_ERROR error= %d\n",
1128 name
,ofs
->nErrCode
);
1133 /***********************************************************************
1134 * OpenFile (KERNEL.74)
1135 * OpenFileEx (KERNEL.360)
1137 HFILE16 WINAPI
OpenFile16( LPCSTR name
, OFSTRUCT
*ofs
, UINT16 mode
)
1139 return FILE_DoOpenFile( name
, ofs
, mode
, FALSE
);
1143 /***********************************************************************
1144 * OpenFile (KERNEL32.@)
1146 HFILE WINAPI
OpenFile( LPCSTR name
, OFSTRUCT
*ofs
, UINT mode
)
1148 return FILE_DoOpenFile( name
, ofs
, mode
, TRUE
);
1152 /******************************************************************
1153 * FILE_ReadWriteApc (internal)
1157 static void WINAPI
FILE_ReadWriteApc(void* apc_user
, PIO_STATUS_BLOCK io_status
, ULONG len
)
1159 LPOVERLAPPED_COMPLETION_ROUTINE cr
= (LPOVERLAPPED_COMPLETION_ROUTINE
)apc_user
;
1161 cr(RtlNtStatusToDosError(io_status
->u
.Status
), len
, (LPOVERLAPPED
)io_status
);
1164 /***********************************************************************
1165 * ReadFileEx (KERNEL32.@)
1167 BOOL WINAPI
ReadFileEx(HANDLE hFile
, LPVOID buffer
, DWORD bytesToRead
,
1168 LPOVERLAPPED overlapped
,
1169 LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine
)
1171 LARGE_INTEGER offset
;
1173 PIO_STATUS_BLOCK io_status
;
1177 SetLastError(ERROR_INVALID_PARAMETER
);
1181 offset
.u
.LowPart
= overlapped
->Offset
;
1182 offset
.u
.HighPart
= overlapped
->OffsetHigh
;
1183 io_status
= (PIO_STATUS_BLOCK
)overlapped
;
1184 io_status
->u
.Status
= STATUS_PENDING
;
1186 status
= NtReadFile(hFile
, NULL
, FILE_ReadWriteApc
, lpCompletionRoutine
,
1187 io_status
, buffer
, bytesToRead
, &offset
, NULL
);
1191 SetLastError( RtlNtStatusToDosError(status
) );
1197 /***********************************************************************
1198 * ReadFile (KERNEL32.@)
1200 BOOL WINAPI
ReadFile( HANDLE hFile
, LPVOID buffer
, DWORD bytesToRead
,
1201 LPDWORD bytesRead
, LPOVERLAPPED overlapped
)
1203 LARGE_INTEGER offset
;
1204 PLARGE_INTEGER poffset
= NULL
;
1205 IO_STATUS_BLOCK iosb
;
1206 PIO_STATUS_BLOCK io_status
= &iosb
;
1210 TRACE("%p %p %ld %p %p\n", hFile
, buffer
, bytesToRead
,
1211 bytesRead
, overlapped
);
1213 if (bytesRead
) *bytesRead
= 0; /* Do this before anything else */
1214 if (!bytesToRead
) return TRUE
;
1216 if (IsBadReadPtr(buffer
, bytesToRead
))
1218 SetLastError(ERROR_WRITE_FAULT
); /* FIXME */
1221 if (is_console_handle(hFile
))
1222 return ReadConsoleA(hFile
, buffer
, bytesToRead
, bytesRead
, NULL
);
1224 if (overlapped
!= NULL
)
1226 offset
.u
.LowPart
= overlapped
->Offset
;
1227 offset
.u
.HighPart
= overlapped
->OffsetHigh
;
1229 hEvent
= overlapped
->hEvent
;
1230 io_status
= (PIO_STATUS_BLOCK
)overlapped
;
1232 io_status
->u
.Status
= STATUS_PENDING
;
1233 io_status
->Information
= 0;
1235 status
= NtReadFile(hFile
, hEvent
, NULL
, NULL
, io_status
, buffer
, bytesToRead
, poffset
, NULL
);
1237 if (status
!= STATUS_PENDING
&& bytesRead
)
1238 *bytesRead
= io_status
->Information
;
1240 if (status
&& status
!= STATUS_END_OF_FILE
)
1242 SetLastError( RtlNtStatusToDosError(status
) );
1249 /***********************************************************************
1250 * WriteFileEx (KERNEL32.@)
1252 BOOL WINAPI
WriteFileEx(HANDLE hFile
, LPCVOID buffer
, DWORD bytesToWrite
,
1253 LPOVERLAPPED overlapped
,
1254 LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine
)
1256 LARGE_INTEGER offset
;
1258 PIO_STATUS_BLOCK io_status
;
1260 TRACE("%p %p %ld %p %p\n",
1261 hFile
, buffer
, bytesToWrite
, overlapped
, lpCompletionRoutine
);
1263 if (overlapped
== NULL
)
1265 SetLastError(ERROR_INVALID_PARAMETER
);
1268 offset
.u
.LowPart
= overlapped
->Offset
;
1269 offset
.u
.HighPart
= overlapped
->OffsetHigh
;
1271 io_status
= (PIO_STATUS_BLOCK
)overlapped
;
1272 io_status
->u
.Status
= STATUS_PENDING
;
1274 status
= NtWriteFile(hFile
, NULL
, FILE_ReadWriteApc
, lpCompletionRoutine
,
1275 io_status
, buffer
, bytesToWrite
, &offset
, NULL
);
1277 if (status
) SetLastError( RtlNtStatusToDosError(status
) );
1281 /***********************************************************************
1282 * WriteFile (KERNEL32.@)
1284 BOOL WINAPI
WriteFile( HANDLE hFile
, LPCVOID buffer
, DWORD bytesToWrite
,
1285 LPDWORD bytesWritten
, LPOVERLAPPED overlapped
)
1287 HANDLE hEvent
= NULL
;
1288 LARGE_INTEGER offset
;
1289 PLARGE_INTEGER poffset
= NULL
;
1291 IO_STATUS_BLOCK iosb
;
1292 PIO_STATUS_BLOCK piosb
= &iosb
;
1294 TRACE("%p %p %ld %p %p\n",
1295 hFile
, buffer
, bytesToWrite
, bytesWritten
, overlapped
);
1297 if (is_console_handle(hFile
))
1298 return WriteConsoleA(hFile
, buffer
, bytesToWrite
, bytesWritten
, NULL
);
1300 if (IsBadReadPtr(buffer
, bytesToWrite
))
1302 SetLastError(ERROR_READ_FAULT
); /* FIXME */
1308 offset
.u
.LowPart
= overlapped
->Offset
;
1309 offset
.u
.HighPart
= overlapped
->OffsetHigh
;
1311 hEvent
= overlapped
->hEvent
;
1312 piosb
= (PIO_STATUS_BLOCK
)overlapped
;
1314 piosb
->u
.Status
= STATUS_PENDING
;
1315 piosb
->Information
= 0;
1317 status
= NtWriteFile(hFile
, hEvent
, NULL
, NULL
, piosb
,
1318 buffer
, bytesToWrite
, poffset
, NULL
);
1321 SetLastError( RtlNtStatusToDosError(status
) );
1324 if (bytesWritten
) *bytesWritten
= piosb
->Information
;
1330 /***********************************************************************
1331 * SetFilePointer (KERNEL32.@)
1333 DWORD WINAPI
SetFilePointer( HANDLE hFile
, LONG distance
, LONG
*highword
,
1336 DWORD ret
= INVALID_SET_FILE_POINTER
;
1338 TRACE("handle %p offset %ld high %ld origin %ld\n",
1339 hFile
, distance
, highword
?*highword
:0, method
);
1341 SERVER_START_REQ( set_file_pointer
)
1343 req
->handle
= hFile
;
1344 req
->low
= distance
;
1345 req
->high
= highword
? *highword
: (distance
>= 0) ? 0 : -1;
1346 /* FIXME: assumes 1:1 mapping between Windows and Unix seek constants */
1347 req
->whence
= method
;
1349 if (!wine_server_call_err( req
))
1351 ret
= reply
->new_low
;
1352 if (highword
) *highword
= reply
->new_high
;
1360 /*************************************************************************
1361 * SetHandleCount (KERNEL32.@)
1363 UINT WINAPI
SetHandleCount( UINT count
)
1365 return min( 256, count
);
1369 /**************************************************************************
1370 * SetEndOfFile (KERNEL32.@)
1372 BOOL WINAPI
SetEndOfFile( HANDLE hFile
)
1375 SERVER_START_REQ( truncate_file
)
1377 req
->handle
= hFile
;
1378 ret
= !wine_server_call_err( req
);
1385 /***********************************************************************
1386 * DeleteFileW (KERNEL32.@)
1388 BOOL WINAPI
DeleteFileW( LPCWSTR path
)
1390 DOS_FULL_NAME full_name
;
1393 TRACE("%s\n", debugstr_w(path
) );
1394 if (!path
|| !*path
)
1396 SetLastError(ERROR_PATH_NOT_FOUND
);
1399 if (RtlIsDosDeviceName_U( path
))
1401 WARN("cannot remove DOS device %s!\n", debugstr_w(path
));
1402 SetLastError( ERROR_FILE_NOT_FOUND
);
1406 if (!DOSFS_GetFullName( path
, TRUE
, &full_name
)) return FALSE
;
1408 /* check if we are allowed to delete the source */
1409 hFile
= FILE_CreateFile( full_name
.long_name
, GENERIC_READ
|GENERIC_WRITE
, 0,
1410 NULL
, OPEN_EXISTING
, 0, 0, TRUE
,
1411 GetDriveTypeW( full_name
.short_name
) );
1412 if (!hFile
) return FALSE
;
1414 if (unlink( full_name
.long_name
) == -1)
1425 /***********************************************************************
1426 * DeleteFileA (KERNEL32.@)
1428 BOOL WINAPI
DeleteFileA( LPCSTR path
)
1430 UNICODE_STRING pathW
;
1435 SetLastError(ERROR_INVALID_PARAMETER
);
1439 if (RtlCreateUnicodeStringFromAsciiz(&pathW
, path
))
1441 ret
= DeleteFileW(pathW
.Buffer
);
1442 RtlFreeUnicodeString(&pathW
);
1445 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
1450 /***********************************************************************
1451 * GetFileType (KERNEL32.@)
1453 DWORD WINAPI
GetFileType( HANDLE hFile
)
1455 DWORD ret
= FILE_TYPE_UNKNOWN
;
1457 if (is_console_handle( hFile
))
1458 return FILE_TYPE_CHAR
;
1460 SERVER_START_REQ( get_file_info
)
1462 req
->handle
= hFile
;
1463 if (!wine_server_call_err( req
)) ret
= reply
->type
;
1470 /* check if a file name is for an executable file (.exe or .com) */
1471 inline static BOOL
is_executable( const char *name
)
1473 int len
= strlen(name
);
1475 if (len
< 4) return FALSE
;
1476 return (!strcasecmp( name
+ len
- 4, ".exe" ) ||
1477 !strcasecmp( name
+ len
- 4, ".com" ));
1481 /***********************************************************************
1482 * FILE_AddBootRenameEntry
1484 * Adds an entry to the registry that is loaded when windows boots and
1485 * checks if there are some files to be removed or renamed/moved.
1486 * <fn1> has to be valid and <fn2> may be NULL. If both pointers are
1487 * non-NULL then the file is moved, otherwise it is deleted. The
1488 * entry of the registrykey is always appended with two zero
1489 * terminated strings. If <fn2> is NULL then the second entry is
1490 * simply a single 0-byte. Otherwise the second filename goes
1491 * there. The entries are prepended with \??\ before the path and the
1492 * second filename gets also a '!' as the first character if
1493 * MOVEFILE_REPLACE_EXISTING is set. After the final string another
1494 * 0-byte follows to indicate the end of the strings.
1496 * \??\D:\test\file1[0]
1497 * !\??\D:\test\file1_renamed[0]
1498 * \??\D:\Test|delete[0]
1499 * [0] <- file is to be deleted, second string empty
1500 * \??\D:\test\file2[0]
1501 * !\??\D:\test\file2_renamed[0]
1502 * [0] <- indicates end of strings
1505 * \??\D:\test\file1[0]
1506 * !\??\D:\test\file1_renamed[0]
1507 * \??\D:\Test|delete[0]
1508 * [0] <- file is to be deleted, second string empty
1509 * [0] <- indicates end of strings
1512 static BOOL
FILE_AddBootRenameEntry( LPCWSTR fn1
, LPCWSTR fn2
, DWORD flags
)
1514 static const WCHAR PreString
[] = {'\\','?','?','\\',0};
1515 static const WCHAR ValueName
[] = {'P','e','n','d','i','n','g',
1516 'F','i','l','e','R','e','n','a','m','e',
1517 'O','p','e','r','a','t','i','o','n','s',0};
1518 static const WCHAR SessionW
[] = {'M','a','c','h','i','n','e','\\',
1519 'S','y','s','t','e','m','\\',
1520 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
1521 'C','o','n','t','r','o','l','\\',
1522 'S','e','s','s','i','o','n',' ','M','a','n','a','g','e','r',0};
1523 static const int info_size
= FIELD_OFFSET( KEY_VALUE_PARTIAL_INFORMATION
, Data
);
1525 OBJECT_ATTRIBUTES attr
;
1526 UNICODE_STRING nameW
;
1527 KEY_VALUE_PARTIAL_INFORMATION
*info
;
1530 DWORD len0
, len1
, len2
;
1532 BYTE
*Buffer
= NULL
;
1535 attr
.Length
= sizeof(attr
);
1536 attr
.RootDirectory
= 0;
1537 attr
.ObjectName
= &nameW
;
1538 attr
.Attributes
= 0;
1539 attr
.SecurityDescriptor
= NULL
;
1540 attr
.SecurityQualityOfService
= NULL
;
1541 RtlInitUnicodeString( &nameW
, SessionW
);
1543 if (NtCreateKey( &Reboot
, KEY_ALL_ACCESS
, &attr
, 0, NULL
, 0, NULL
) != STATUS_SUCCESS
)
1545 WARN("Error creating key for reboot managment [%s]\n",
1546 "SYSTEM\\CurrentControlSet\\Control\\Session Manager");
1550 len0
= strlenW(PreString
);
1551 len1
= strlenW(fn1
) + len0
+ 1;
1554 len2
= strlenW(fn2
) + len0
+ 1;
1555 if (flags
& MOVEFILE_REPLACE_EXISTING
) len2
++; /* Plus 1 because of the leading '!' */
1557 else len2
= 1; /* minimum is the 0 characters for the empty second string */
1559 /* convert characters to bytes */
1560 len0
*= sizeof(WCHAR
);
1561 len1
*= sizeof(WCHAR
);
1562 len2
*= sizeof(WCHAR
);
1564 RtlInitUnicodeString( &nameW
, ValueName
);
1566 /* First we check if the key exists and if so how many bytes it already contains. */
1567 if (NtQueryValueKey( Reboot
, &nameW
, KeyValuePartialInformation
,
1568 NULL
, 0, &DataSize
) == STATUS_BUFFER_OVERFLOW
)
1570 if (!(Buffer
= HeapAlloc( GetProcessHeap(), 0, DataSize
+ len1
+ len2
+ sizeof(WCHAR
) )))
1572 if (NtQueryValueKey( Reboot
, &nameW
, KeyValuePartialInformation
,
1573 Buffer
, DataSize
, &DataSize
)) goto Quit
;
1574 info
= (KEY_VALUE_PARTIAL_INFORMATION
*)Buffer
;
1575 if (info
->Type
!= REG_MULTI_SZ
) goto Quit
;
1576 if (DataSize
> sizeof(info
)) DataSize
-= sizeof(WCHAR
); /* remove terminating null (will be added back later) */
1580 DataSize
= info_size
;
1581 if (!(Buffer
= HeapAlloc( GetProcessHeap(), 0, DataSize
+ len1
+ len2
+ sizeof(WCHAR
) )))
1585 p
= (WCHAR
*)(Buffer
+ DataSize
);
1586 strcpyW( p
, PreString
);
1591 p
= (WCHAR
*)(Buffer
+ DataSize
);
1592 if (flags
& MOVEFILE_REPLACE_EXISTING
)
1594 strcpyW( p
, PreString
);
1600 p
= (WCHAR
*)(Buffer
+ DataSize
);
1602 DataSize
+= sizeof(WCHAR
);
1605 /* add final null */
1606 p
= (WCHAR
*)(Buffer
+ DataSize
);
1608 DataSize
+= sizeof(WCHAR
);
1610 rc
= !NtSetValueKey(Reboot
, &nameW
, 0, REG_MULTI_SZ
, Buffer
+ info_size
, DataSize
- info_size
);
1613 if (Reboot
) NtClose(Reboot
);
1614 if (Buffer
) HeapFree( GetProcessHeap(), 0, Buffer
);
1619 /**************************************************************************
1620 * MoveFileExW (KERNEL32.@)
1622 BOOL WINAPI
MoveFileExW( LPCWSTR fn1
, LPCWSTR fn2
, DWORD flag
)
1624 DOS_FULL_NAME full_name1
, full_name2
;
1626 DWORD attr
= INVALID_FILE_ATTRIBUTES
;
1628 TRACE("(%s,%s,%04lx)\n", debugstr_w(fn1
), debugstr_w(fn2
), flag
);
1630 /* FIXME: <Gerhard W. Gruber>sparhawk@gmx.at
1631 In case of W9x and lesser this function should return 120 (ERROR_CALL_NOT_IMPLEMENTED)
1632 to be really compatible. Most programs won't have any problems though. In case
1633 you encounter one, this is what you should return here. I don't know what's up
1634 with NT 3.5. Is this function available there or not?
1635 Does anybody really care about 3.5? :)
1638 /* Filename1 has to be always set to a valid path. Filename2 may be NULL
1639 if the source file has to be deleted.
1642 SetLastError(ERROR_INVALID_PARAMETER
);
1646 /* This function has to be run through in order to process the name properly.
1647 If the BOOTDELAY flag is set, the file doesn't need to exist though. At least
1648 that is the behaviour on NT 4.0. The operation accepts the filenames as
1649 they are given but it can't reply with a reasonable returncode. Success
1650 means in that case success for entering the values into the registry.
1652 if(!DOSFS_GetFullName( fn1
, TRUE
, &full_name1
))
1654 if(!(flag
& MOVEFILE_DELAY_UNTIL_REBOOT
))
1658 if (fn2
) /* !fn2 means delete fn1 */
1660 if (DOSFS_GetFullName( fn2
, TRUE
, &full_name2
))
1662 if(!(flag
& MOVEFILE_DELAY_UNTIL_REBOOT
))
1664 /* target exists, check if we may overwrite */
1665 if (!(flag
& MOVEFILE_REPLACE_EXISTING
))
1667 SetLastError( ERROR_ALREADY_EXISTS
);
1674 if (!DOSFS_GetFullName( fn2
, FALSE
, &full_name2
))
1676 if(!(flag
& MOVEFILE_DELAY_UNTIL_REBOOT
))
1681 /* Source name and target path are valid */
1683 if (flag
& MOVEFILE_DELAY_UNTIL_REBOOT
)
1685 return FILE_AddBootRenameEntry( fn1
, fn2
, flag
);
1688 attr
= GetFileAttributesW( fn1
);
1689 if ( attr
== INVALID_FILE_ATTRIBUTES
) return FALSE
;
1691 /* check if we are allowed to rename the source */
1692 hFile
= FILE_CreateFile( full_name1
.long_name
, 0, 0,
1693 NULL
, OPEN_EXISTING
, 0, 0, TRUE
,
1694 GetDriveTypeW( full_name1
.short_name
) );
1697 if (GetLastError() != ERROR_ACCESS_DENIED
) return FALSE
;
1698 if ( !(attr
& FILE_ATTRIBUTE_DIRECTORY
) ) return FALSE
;
1699 /* if it's a directory we can continue */
1701 else CloseHandle(hFile
);
1703 /* check, if we are allowed to delete the destination,
1704 ** (but the file not being there is fine) */
1705 hFile
= FILE_CreateFile( full_name2
.long_name
, GENERIC_READ
|GENERIC_WRITE
, 0,
1706 NULL
, OPEN_EXISTING
, 0, 0, TRUE
,
1707 GetDriveTypeW( full_name2
.short_name
) );
1708 if(!hFile
&& GetLastError() != ERROR_FILE_NOT_FOUND
) return FALSE
;
1711 if (full_name1
.drive
!= full_name2
.drive
)
1713 if (!(flag
& MOVEFILE_COPY_ALLOWED
))
1715 SetLastError( ERROR_NOT_SAME_DEVICE
);
1718 else if ( attr
& FILE_ATTRIBUTE_DIRECTORY
)
1720 /* Strange, but that's what Windows returns */
1721 SetLastError ( ERROR_ACCESS_DENIED
);
1725 if (rename( full_name1
.long_name
, full_name2
.long_name
) == -1)
1726 /* Try copy/delete unless it's a directory. */
1727 /* FIXME: This does not handle the (unlikely) case that the two locations
1728 are on the same Wine drive, but on different Unix file systems. */
1730 if ( attr
& FILE_ATTRIBUTE_DIRECTORY
)
1737 if ( ! CopyFileW( fn1
, fn2
, !(flag
& MOVEFILE_REPLACE_EXISTING
) ))
1739 if ( ! DeleteFileW ( fn1
) )
1743 if (is_executable( full_name1
.long_name
) != is_executable( full_name2
.long_name
))
1746 if (stat( full_name2
.long_name
, &fstat
) != -1)
1748 if (is_executable( full_name2
.long_name
))
1749 /* set executable bit where read bit is set */
1750 fstat
.st_mode
|= (fstat
.st_mode
& 0444) >> 2;
1752 fstat
.st_mode
&= ~0111;
1753 chmod( full_name2
.long_name
, fstat
.st_mode
);
1758 else /* fn2 == NULL means delete source */
1760 if (flag
& MOVEFILE_DELAY_UNTIL_REBOOT
)
1762 if (flag
& MOVEFILE_COPY_ALLOWED
) {
1763 WARN("Illegal flag\n");
1764 SetLastError( ERROR_GEN_FAILURE
);
1768 return FILE_AddBootRenameEntry( fn1
, NULL
, flag
);
1771 if (unlink( full_name1
.long_name
) == -1)
1776 return TRUE
; /* successfully deleted */
1780 /**************************************************************************
1781 * MoveFileExA (KERNEL32.@)
1783 BOOL WINAPI
MoveFileExA( LPCSTR fn1
, LPCSTR fn2
, DWORD flag
)
1785 UNICODE_STRING fn1W
, fn2W
;
1790 SetLastError(ERROR_INVALID_PARAMETER
);
1794 RtlCreateUnicodeStringFromAsciiz(&fn1W
, fn1
);
1795 if (fn2
) RtlCreateUnicodeStringFromAsciiz(&fn2W
, fn2
);
1796 else fn2W
.Buffer
= NULL
;
1798 ret
= MoveFileExW( fn1W
.Buffer
, fn2W
.Buffer
, flag
);
1800 RtlFreeUnicodeString(&fn1W
);
1801 RtlFreeUnicodeString(&fn2W
);
1806 /**************************************************************************
1807 * MoveFileW (KERNEL32.@)
1809 * Move file or directory
1811 BOOL WINAPI
MoveFileW( LPCWSTR fn1
, LPCWSTR fn2
)
1813 return MoveFileExW( fn1
, fn2
, MOVEFILE_COPY_ALLOWED
);
1817 /**************************************************************************
1818 * MoveFileA (KERNEL32.@)
1820 BOOL WINAPI
MoveFileA( LPCSTR fn1
, LPCSTR fn2
)
1822 return MoveFileExA( fn1
, fn2
, MOVEFILE_COPY_ALLOWED
);
1826 /**************************************************************************
1827 * CopyFileW (KERNEL32.@)
1829 BOOL WINAPI
CopyFileW( LPCWSTR source
, LPCWSTR dest
, BOOL fail_if_exists
)
1832 BY_HANDLE_FILE_INFORMATION info
;
1837 if (!source
|| !dest
)
1839 SetLastError(ERROR_INVALID_PARAMETER
);
1843 TRACE("%s -> %s\n", debugstr_w(source
), debugstr_w(dest
));
1845 if ((h1
= CreateFileW(source
, GENERIC_READ
, FILE_SHARE_READ
| FILE_SHARE_WRITE
,
1846 NULL
, OPEN_EXISTING
, 0, 0)) == INVALID_HANDLE_VALUE
)
1848 WARN("Unable to open source %s\n", debugstr_w(source
));
1852 if (!GetFileInformationByHandle( h1
, &info
))
1854 WARN("GetFileInformationByHandle returned error for %s\n", debugstr_w(source
));
1859 if ((h2
= CreateFileW( dest
, GENERIC_WRITE
, FILE_SHARE_READ
| FILE_SHARE_WRITE
, NULL
,
1860 fail_if_exists
? CREATE_NEW
: CREATE_ALWAYS
,
1861 info
.dwFileAttributes
, h1
)) == INVALID_HANDLE_VALUE
)
1863 WARN("Unable to open dest %s\n", debugstr_w(dest
));
1868 while (ReadFile( h1
, buffer
, sizeof(buffer
), &count
, NULL
) && count
)
1874 if (!WriteFile( h2
, p
, count
, &res
, NULL
) || !res
) goto done
;
1887 /**************************************************************************
1888 * CopyFileA (KERNEL32.@)
1890 BOOL WINAPI
CopyFileA( LPCSTR source
, LPCSTR dest
, BOOL fail_if_exists
)
1892 UNICODE_STRING sourceW
, destW
;
1895 if (!source
|| !dest
)
1897 SetLastError(ERROR_INVALID_PARAMETER
);
1901 RtlCreateUnicodeStringFromAsciiz(&sourceW
, source
);
1902 RtlCreateUnicodeStringFromAsciiz(&destW
, dest
);
1904 ret
= CopyFileW(sourceW
.Buffer
, destW
.Buffer
, fail_if_exists
);
1906 RtlFreeUnicodeString(&sourceW
);
1907 RtlFreeUnicodeString(&destW
);
1912 /**************************************************************************
1913 * CopyFileExW (KERNEL32.@)
1915 * This implementation ignores most of the extra parameters passed-in into
1916 * the "ex" version of the method and calls the CopyFile method.
1917 * It will have to be fixed eventually.
1919 BOOL WINAPI
CopyFileExW(LPCWSTR sourceFilename
, LPCWSTR destFilename
,
1920 LPPROGRESS_ROUTINE progressRoutine
, LPVOID appData
,
1921 LPBOOL cancelFlagPointer
, DWORD copyFlags
)
1924 * Interpret the only flag that CopyFile can interpret.
1926 return CopyFileW(sourceFilename
, destFilename
, (copyFlags
& COPY_FILE_FAIL_IF_EXISTS
) != 0);
1930 /**************************************************************************
1931 * CopyFileExA (KERNEL32.@)
1933 BOOL WINAPI
CopyFileExA(LPCSTR sourceFilename
, LPCSTR destFilename
,
1934 LPPROGRESS_ROUTINE progressRoutine
, LPVOID appData
,
1935 LPBOOL cancelFlagPointer
, DWORD copyFlags
)
1937 UNICODE_STRING sourceW
, destW
;
1940 if (!sourceFilename
|| !destFilename
)
1942 SetLastError(ERROR_INVALID_PARAMETER
);
1946 RtlCreateUnicodeStringFromAsciiz(&sourceW
, sourceFilename
);
1947 RtlCreateUnicodeStringFromAsciiz(&destW
, destFilename
);
1949 ret
= CopyFileExW(sourceW
.Buffer
, destW
.Buffer
, progressRoutine
, appData
,
1950 cancelFlagPointer
, copyFlags
);
1952 RtlFreeUnicodeString(&sourceW
);
1953 RtlFreeUnicodeString(&destW
);
1958 /***********************************************************************
1959 * SetFileTime (KERNEL32.@)
1961 BOOL WINAPI
SetFileTime( HANDLE hFile
,
1962 const FILETIME
*lpCreationTime
,
1963 const FILETIME
*lpLastAccessTime
,
1964 const FILETIME
*lpLastWriteTime
)
1967 SERVER_START_REQ( set_file_time
)
1969 req
->handle
= hFile
;
1970 if (lpLastAccessTime
)
1971 RtlTimeToSecondsSince1970( (PLARGE_INTEGER
) lpLastAccessTime
, (DWORD
*)&req
->access_time
);
1973 req
->access_time
= 0; /* FIXME */
1974 if (lpLastWriteTime
)
1975 RtlTimeToSecondsSince1970( (PLARGE_INTEGER
) lpLastWriteTime
, (DWORD
*)&req
->write_time
);
1977 req
->write_time
= 0; /* FIXME */
1978 ret
= !wine_server_call_err( req
);
1985 /**************************************************************************
1986 * GetFileAttributesExW (KERNEL32.@)
1988 BOOL WINAPI
GetFileAttributesExW(
1989 LPCWSTR lpFileName
, GET_FILEEX_INFO_LEVELS fInfoLevelId
,
1990 LPVOID lpFileInformation
)
1992 DOS_FULL_NAME full_name
;
1993 BY_HANDLE_FILE_INFORMATION info
;
1995 if (!lpFileName
|| !lpFileInformation
)
1997 SetLastError(ERROR_INVALID_PARAMETER
);
2001 if (fInfoLevelId
== GetFileExInfoStandard
) {
2002 LPWIN32_FILE_ATTRIBUTE_DATA lpFad
=
2003 (LPWIN32_FILE_ATTRIBUTE_DATA
) lpFileInformation
;
2004 if (!DOSFS_GetFullName( lpFileName
, TRUE
, &full_name
)) return FALSE
;
2005 if (!FILE_Stat( full_name
.long_name
, &info
, NULL
)) return FALSE
;
2007 lpFad
->dwFileAttributes
= info
.dwFileAttributes
;
2008 lpFad
->ftCreationTime
= info
.ftCreationTime
;
2009 lpFad
->ftLastAccessTime
= info
.ftLastAccessTime
;
2010 lpFad
->ftLastWriteTime
= info
.ftLastWriteTime
;
2011 lpFad
->nFileSizeHigh
= info
.nFileSizeHigh
;
2012 lpFad
->nFileSizeLow
= info
.nFileSizeLow
;
2015 FIXME("invalid info level %d!\n", fInfoLevelId
);
2023 /**************************************************************************
2024 * GetFileAttributesExA (KERNEL32.@)
2026 BOOL WINAPI
GetFileAttributesExA(
2027 LPCSTR filename
, GET_FILEEX_INFO_LEVELS fInfoLevelId
,
2028 LPVOID lpFileInformation
)
2030 UNICODE_STRING filenameW
;
2033 if (!filename
|| !lpFileInformation
)
2035 SetLastError(ERROR_INVALID_PARAMETER
);
2039 if (RtlCreateUnicodeStringFromAsciiz(&filenameW
, filename
))
2041 ret
= GetFileAttributesExW(filenameW
.Buffer
, fInfoLevelId
, lpFileInformation
);
2042 RtlFreeUnicodeString(&filenameW
);
2045 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);