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')
88 /***********************************************************************
91 * Convert OF_* mode into flags for CreateFile.
93 void FILE_ConvertOFMode( INT mode
, DWORD
*access
, DWORD
*sharing
)
97 case OF_READ
: *access
= GENERIC_READ
; break;
98 case OF_WRITE
: *access
= GENERIC_WRITE
; break;
99 case OF_READWRITE
: *access
= GENERIC_READ
| GENERIC_WRITE
; break;
100 default: *access
= 0; break;
104 case OF_SHARE_EXCLUSIVE
: *sharing
= 0; break;
105 case OF_SHARE_DENY_WRITE
: *sharing
= FILE_SHARE_READ
; break;
106 case OF_SHARE_DENY_READ
: *sharing
= FILE_SHARE_WRITE
; break;
107 case OF_SHARE_DENY_NONE
:
108 case OF_SHARE_COMPAT
:
109 default: *sharing
= FILE_SHARE_READ
| FILE_SHARE_WRITE
; break;
114 /***********************************************************************
117 * Set the DOS error code from errno.
119 void FILE_SetDosError(void)
121 int save_errno
= errno
; /* errno gets overwritten by printf */
123 TRACE("errno = %d %s\n", errno
, strerror(errno
));
127 SetLastError( ERROR_SHARING_VIOLATION
);
130 SetLastError( ERROR_INVALID_HANDLE
);
133 SetLastError( ERROR_HANDLE_DISK_FULL
);
138 SetLastError( ERROR_ACCESS_DENIED
);
141 SetLastError( ERROR_LOCK_VIOLATION
);
144 SetLastError( ERROR_FILE_NOT_FOUND
);
147 SetLastError( ERROR_CANNOT_MAKE
);
151 SetLastError( ERROR_NO_MORE_FILES
);
154 SetLastError( ERROR_FILE_EXISTS
);
158 SetLastError( ERROR_SEEK
);
161 SetLastError( ERROR_DIR_NOT_EMPTY
);
164 SetLastError( ERROR_BAD_FORMAT
);
167 WARN("unknown file error: %s\n", strerror(save_errno
) );
168 SetLastError( ERROR_GEN_FAILURE
);
175 /***********************************************************************
178 * Implementation of CreateFile. Takes a Unix path name.
179 * Returns 0 on failure.
181 HANDLE
FILE_CreateFile( LPCSTR filename
, DWORD access
, DWORD sharing
,
182 LPSECURITY_ATTRIBUTES sa
, DWORD creation
,
183 DWORD attributes
, HANDLE
template, BOOL fail_read_only
,
192 case CREATE_ALWAYS
: disp
= FILE_OVERWRITE_IF
; break;
193 case CREATE_NEW
: disp
= FILE_CREATE
; break;
194 case OPEN_ALWAYS
: disp
= FILE_OPEN_IF
; break;
195 case OPEN_EXISTING
: disp
= FILE_OPEN
; break;
196 case TRUNCATE_EXISTING
: disp
= FILE_OVERWRITE
; break;
198 SetLastError( ERROR_INVALID_PARAMETER
);
203 if (attributes
& FILE_FLAG_BACKUP_SEMANTICS
)
204 options
|= FILE_OPEN_FOR_BACKUP_INTENT
;
205 if (attributes
& FILE_FLAG_DELETE_ON_CLOSE
)
206 options
|= FILE_DELETE_ON_CLOSE
;
207 if (!(attributes
& FILE_FLAG_OVERLAPPED
))
208 options
|= FILE_SYNCHRONOUS_IO_ALERT
;
209 if (attributes
& FILE_FLAG_RANDOM_ACCESS
)
210 options
|= FILE_RANDOM_ACCESS
;
211 attributes
&= FILE_ATTRIBUTE_VALID_FLAGS
;
215 SERVER_START_REQ( create_file
)
217 req
->access
= access
;
218 req
->inherit
= (sa
&& (sa
->nLength
>=sizeof(*sa
)) && sa
->bInheritHandle
);
219 req
->sharing
= sharing
;
221 req
->options
= options
;
222 req
->attrs
= attributes
;
223 req
->removable
= (drive_type
== DRIVE_REMOVABLE
|| drive_type
== DRIVE_CDROM
);
224 wine_server_add_data( req
, filename
, strlen(filename
) );
226 err
= wine_server_call( req
);
231 /* If write access failed, retry without GENERIC_WRITE */
233 if (!ret
&& !fail_read_only
&& (access
& GENERIC_WRITE
))
235 if ((err
== STATUS_MEDIA_WRITE_PROTECTED
) || (err
== STATUS_ACCESS_DENIED
))
237 TRACE("Write access failed for file '%s', trying without "
238 "write access\n", filename
);
239 access
&= ~GENERIC_WRITE
;
246 /* In the case file creation was rejected due to CREATE_NEW flag
247 * was specified and file with that name already exists, correct
248 * last error is ERROR_FILE_EXISTS and not ERROR_ALREADY_EXISTS.
249 * Note: RtlNtStatusToDosError is not the subject to blame here.
251 if (err
== STATUS_OBJECT_NAME_COLLISION
)
252 SetLastError( ERROR_FILE_EXISTS
);
254 SetLastError( RtlNtStatusToDosError(err
) );
257 if (!ret
) WARN("Unable to create file '%s' (GLE %ld)\n", filename
, GetLastError());
263 static HANDLE
FILE_OpenPipe(LPCWSTR name
, DWORD access
, LPSECURITY_ATTRIBUTES sa
)
268 if (name
&& (len
= strlenW(name
)) > MAX_PATH
)
270 SetLastError( ERROR_FILENAME_EXCED_RANGE
);
273 SERVER_START_REQ( open_named_pipe
)
275 req
->access
= access
;
276 req
->inherit
= (sa
&& (sa
->nLength
>=sizeof(*sa
)) && sa
->bInheritHandle
);
278 wine_server_add_data( req
, name
, len
* sizeof(WCHAR
) );
279 wine_server_call_err( req
);
283 TRACE("Returned %p\n",ret
);
287 /*************************************************************************
288 * CreateFileW [KERNEL32.@] Creates or opens a file or other object
290 * Creates or opens an object, and returns a handle that can be used to
291 * access that object.
295 * filename [in] pointer to filename to be accessed
296 * access [in] access mode requested
297 * sharing [in] share mode
298 * sa [in] pointer to security attributes
299 * creation [in] how to create the file
300 * attributes [in] attributes for newly created file
301 * template [in] handle to file with extended attributes to copy
304 * Success: Open handle to specified file
305 * Failure: INVALID_HANDLE_VALUE
308 * Should call SetLastError() on failure.
312 * Doesn't support character devices, template files, or a
313 * lot of the 'attributes' flags yet.
315 HANDLE WINAPI
CreateFileW( LPCWSTR filename
, DWORD access
, DWORD sharing
,
316 LPSECURITY_ATTRIBUTES sa
, DWORD creation
,
317 DWORD attributes
, HANDLE
template )
319 DOS_FULL_NAME full_name
;
322 static const WCHAR bkslashes_with_question_markW
[] = {'\\','\\','?','\\',0};
323 static const WCHAR bkslashes_with_dotW
[] = {'\\','\\','.','\\',0};
324 static const WCHAR bkslashesW
[] = {'\\','\\',0};
325 static const WCHAR coninW
[] = {'C','O','N','I','N','$',0};
326 static const WCHAR conoutW
[] = {'C','O','N','O','U','T','$',0};
330 SetLastError( ERROR_INVALID_PARAMETER
);
331 return INVALID_HANDLE_VALUE
;
333 TRACE("%s %s%s%s%s%s%s%s attributes 0x%lx\n", debugstr_w(filename
),
334 ((access
& GENERIC_READ
)==GENERIC_READ
)?"GENERIC_READ ":"",
335 ((access
& GENERIC_WRITE
)==GENERIC_WRITE
)?"GENERIC_WRITE ":"",
336 (!access
)?"QUERY_ACCESS ":"",
337 ((sharing
& FILE_SHARE_READ
)==FILE_SHARE_READ
)?"FILE_SHARE_READ ":"",
338 ((sharing
& FILE_SHARE_WRITE
)==FILE_SHARE_WRITE
)?"FILE_SHARE_WRITE ":"",
339 ((sharing
& FILE_SHARE_DELETE
)==FILE_SHARE_DELETE
)?"FILE_SHARE_DELETE ":"",
340 (creation
==CREATE_NEW
)?"CREATE_NEW":
341 (creation
==CREATE_ALWAYS
)?"CREATE_ALWAYS ":
342 (creation
==OPEN_EXISTING
)?"OPEN_EXISTING ":
343 (creation
==OPEN_ALWAYS
)?"OPEN_ALWAYS ":
344 (creation
==TRUNCATE_EXISTING
)?"TRUNCATE_EXISTING ":"", attributes
);
346 /* Open a console for CONIN$ or CONOUT$ */
347 if (!strcmpiW(filename
, coninW
) || !strcmpiW(filename
, conoutW
))
349 ret
= OpenConsoleW(filename
, access
, (sa
&& sa
->bInheritHandle
), creation
);
353 /* If the name starts with '\\?\', ignore the first 4 chars. */
354 if (!strncmpW(filename
, bkslashes_with_question_markW
, 4))
356 static const WCHAR uncW
[] = {'U','N','C','\\',0};
358 if (!strncmpiW(filename
, uncW
, 4))
360 FIXME("UNC name (%s) not supported.\n", debugstr_w(filename
) );
361 SetLastError( ERROR_PATH_NOT_FOUND
);
362 return INVALID_HANDLE_VALUE
;
366 if (!strncmpW(filename
, bkslashes_with_dotW
, 4))
368 static const WCHAR pipeW
[] = {'P','I','P','E','\\',0};
369 if(!strncmpiW(filename
+ 4, pipeW
, 5))
371 TRACE("Opening a pipe: %s\n", debugstr_w(filename
));
372 ret
= FILE_OpenPipe( filename
, access
, sa
);
375 else if (isalphaW(filename
[4]) && filename
[5] == ':' && filename
[6] == '\0')
377 const char *device
= DRIVE_GetDevice( toupperW(filename
[4]) - 'A' );
380 ret
= FILE_CreateFile( device
, access
, sharing
, sa
, creation
,
381 attributes
, template, TRUE
, DRIVE_FIXED
);
385 SetLastError( ERROR_ACCESS_DENIED
);
386 ret
= INVALID_HANDLE_VALUE
;
390 else if ((dosdev
= RtlIsDosDeviceName_U( filename
+ 4 )))
392 dosdev
+= MAKELONG( 0, 4*sizeof(WCHAR
) ); /* adjust position to start of filename */
396 ret
= VXD_Open( filename
+4, access
, sa
);
400 else dosdev
= RtlIsDosDeviceName_U( filename
);
404 static const WCHAR conW
[] = {'C','O','N',0};
407 memcpy( dev
, filename
+ HIWORD(dosdev
)/sizeof(WCHAR
), LOWORD(dosdev
) );
408 dev
[LOWORD(dosdev
)/sizeof(WCHAR
)] = 0;
410 TRACE("opening device %s\n", debugstr_w(dev
) );
412 if (!strcmpiW( dev
, conW
))
414 switch (access
& (GENERIC_READ
|GENERIC_WRITE
))
417 ret
= OpenConsoleW(coninW
, access
, (sa
&& sa
->bInheritHandle
), creation
);
420 ret
= OpenConsoleW(conoutW
, access
, (sa
&& sa
->bInheritHandle
), creation
);
423 FIXME("can't open CON read/write\n");
424 SetLastError( ERROR_FILE_NOT_FOUND
);
425 return INVALID_HANDLE_VALUE
;
429 ret
= VOLUME_OpenDevice( dev
, access
, sharing
, sa
, attributes
);
433 /* If the name still starts with '\\', it's a UNC name. */
434 if (!strncmpW(filename
, bkslashesW
, 2))
436 ret
= SMB_CreateFileW(filename
, access
, sharing
, sa
, creation
, attributes
, template );
440 /* If the name contains a DOS wild card (* or ?), do no create a file */
441 if(strchrW(filename
, '*') || strchrW(filename
, '?'))
443 SetLastError(ERROR_BAD_PATHNAME
);
444 return INVALID_HANDLE_VALUE
;
447 /* check for filename, don't check for last entry if creating */
448 if (!DOSFS_GetFullName( filename
,
449 (creation
== OPEN_EXISTING
) ||
450 (creation
== TRUNCATE_EXISTING
),
452 WARN("Unable to get full filename from %s (GLE %ld)\n",
453 debugstr_w(filename
), GetLastError());
454 return INVALID_HANDLE_VALUE
;
457 ret
= FILE_CreateFile( full_name
.long_name
, access
, sharing
,
458 sa
, creation
, attributes
, template,
459 DRIVE_GetFlags(full_name
.drive
) & DRIVE_FAIL_READ_ONLY
,
460 GetDriveTypeW( full_name
.short_name
) );
462 if (!ret
) ret
= INVALID_HANDLE_VALUE
;
463 TRACE("returning %p\n", ret
);
469 /*************************************************************************
470 * CreateFileA (KERNEL32.@)
472 HANDLE WINAPI
CreateFileA( LPCSTR filename
, DWORD access
, DWORD sharing
,
473 LPSECURITY_ATTRIBUTES sa
, DWORD creation
,
474 DWORD attributes
, HANDLE
template)
476 UNICODE_STRING filenameW
;
477 HANDLE ret
= INVALID_HANDLE_VALUE
;
481 SetLastError( ERROR_INVALID_PARAMETER
);
482 return INVALID_HANDLE_VALUE
;
485 if (RtlCreateUnicodeStringFromAsciiz(&filenameW
, filename
))
487 ret
= CreateFileW(filenameW
.Buffer
, access
, sharing
, sa
, creation
,
488 attributes
, template);
489 RtlFreeUnicodeString(&filenameW
);
492 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
497 /***********************************************************************
500 * Fill a file information from a struct stat.
502 static void FILE_FillInfo( struct stat
*st
, BY_HANDLE_FILE_INFORMATION
*info
)
504 if (S_ISDIR(st
->st_mode
))
505 info
->dwFileAttributes
= FILE_ATTRIBUTE_DIRECTORY
;
507 info
->dwFileAttributes
= FILE_ATTRIBUTE_ARCHIVE
;
508 if (!(st
->st_mode
& S_IWUSR
))
509 info
->dwFileAttributes
|= FILE_ATTRIBUTE_READONLY
;
511 RtlSecondsSince1970ToTime( st
->st_mtime
, (LARGE_INTEGER
*)&info
->ftCreationTime
);
512 RtlSecondsSince1970ToTime( st
->st_mtime
, (LARGE_INTEGER
*)&info
->ftLastWriteTime
);
513 RtlSecondsSince1970ToTime( st
->st_atime
, (LARGE_INTEGER
*)&info
->ftLastAccessTime
);
515 info
->dwVolumeSerialNumber
= 0; /* FIXME */
516 info
->nFileSizeHigh
= 0;
517 info
->nFileSizeLow
= 0;
518 if (!S_ISDIR(st
->st_mode
)) {
519 info
->nFileSizeHigh
= st
->st_size
>> 32;
520 info
->nFileSizeLow
= st
->st_size
& 0xffffffff;
522 info
->nNumberOfLinks
= st
->st_nlink
;
523 info
->nFileIndexHigh
= 0;
524 info
->nFileIndexLow
= st
->st_ino
;
528 /***********************************************************************
529 * get_show_dot_files_option
531 static BOOL
get_show_dot_files_option(void)
533 static const WCHAR WineW
[] = {'M','a','c','h','i','n','e','\\',
534 'S','o','f','t','w','a','r','e','\\',
535 'W','i','n','e','\\','W','i','n','e','\\',
536 'C','o','n','f','i','g','\\','W','i','n','e',0};
537 static const WCHAR ShowDotFilesW
[] = {'S','h','o','w','D','o','t','F','i','l','e','s',0};
542 OBJECT_ATTRIBUTES attr
;
543 UNICODE_STRING nameW
;
546 attr
.Length
= sizeof(attr
);
547 attr
.RootDirectory
= 0;
548 attr
.ObjectName
= &nameW
;
550 attr
.SecurityDescriptor
= NULL
;
551 attr
.SecurityQualityOfService
= NULL
;
552 RtlInitUnicodeString( &nameW
, WineW
);
554 if (!NtOpenKey( &hkey
, KEY_ALL_ACCESS
, &attr
))
556 RtlInitUnicodeString( &nameW
, ShowDotFilesW
);
557 if (!NtQueryValueKey( hkey
, &nameW
, KeyValuePartialInformation
, tmp
, sizeof(tmp
), &dummy
))
559 WCHAR
*str
= (WCHAR
*)((KEY_VALUE_PARTIAL_INFORMATION
*)tmp
)->Data
;
560 ret
= IS_OPTION_TRUE( str
[0] );
568 /***********************************************************************
571 * Stat a Unix path name. Return TRUE if OK.
573 BOOL
FILE_Stat( LPCSTR unixName
, BY_HANDLE_FILE_INFORMATION
*info
, BOOL
*is_symlink_ptr
)
579 if (lstat( unixName
, &st
) == -1)
584 is_symlink
= S_ISLNK(st
.st_mode
);
587 /* do a "real" stat to find out
588 about the type of the symlink destination */
589 if (stat( unixName
, &st
) == -1)
596 /* fill in the information we gathered so far */
597 FILE_FillInfo( &st
, info
);
599 /* and now see if this is a hidden file, based on the name */
600 p
= strrchr( unixName
, '/');
601 p
= p
? p
+ 1 : unixName
;
602 if (*p
== '.' && *(p
+1) && (*(p
+1) != '.' || *(p
+2)))
604 static int show_dot_files
= -1;
605 if (show_dot_files
== -1)
606 show_dot_files
= get_show_dot_files_option();
608 info
->dwFileAttributes
|= FILE_ATTRIBUTE_HIDDEN
;
610 if (is_symlink_ptr
) *is_symlink_ptr
= is_symlink
;
615 /***********************************************************************
616 * GetFileInformationByHandle (KERNEL32.@)
618 DWORD WINAPI
GetFileInformationByHandle( HANDLE hFile
,
619 BY_HANDLE_FILE_INFORMATION
*info
)
624 TRACE("%p\n", hFile
);
626 SERVER_START_REQ( get_file_info
)
629 if ((ret
= !wine_server_call_err( req
)))
631 /* FIXME: which file types are supported ?
632 * Serial ports (FILE_TYPE_CHAR) are not,
633 * and MSDN also says that pipes are not supported.
634 * FILE_TYPE_REMOTE seems to be supported according to
635 * MSDN q234741.txt */
636 if ((reply
->type
== FILE_TYPE_DISK
) || (reply
->type
== FILE_TYPE_REMOTE
))
638 RtlSecondsSince1970ToTime( reply
->write_time
, (LARGE_INTEGER
*)&info
->ftCreationTime
);
639 RtlSecondsSince1970ToTime( reply
->write_time
, (LARGE_INTEGER
*)&info
->ftLastWriteTime
);
640 RtlSecondsSince1970ToTime( reply
->access_time
, (LARGE_INTEGER
*)&info
->ftLastAccessTime
);
641 info
->dwFileAttributes
= reply
->attr
;
642 info
->dwVolumeSerialNumber
= reply
->serial
;
643 info
->nFileSizeHigh
= reply
->size_high
;
644 info
->nFileSizeLow
= reply
->size_low
;
645 info
->nNumberOfLinks
= reply
->links
;
646 info
->nFileIndexHigh
= reply
->index_high
;
647 info
->nFileIndexLow
= reply
->index_low
;
651 SetLastError(ERROR_NOT_SUPPORTED
);
661 /**************************************************************************
662 * GetFileAttributesW (KERNEL32.@)
664 DWORD WINAPI
GetFileAttributesW( LPCWSTR name
)
666 DOS_FULL_NAME full_name
;
667 BY_HANDLE_FILE_INFORMATION info
;
671 SetLastError( ERROR_INVALID_PARAMETER
);
672 return INVALID_FILE_ATTRIBUTES
;
674 if (!DOSFS_GetFullName( name
, TRUE
, &full_name
) )
675 return INVALID_FILE_ATTRIBUTES
;
676 if (!FILE_Stat( full_name
.long_name
, &info
, NULL
))
677 return INVALID_FILE_ATTRIBUTES
;
678 return info
.dwFileAttributes
;
682 /**************************************************************************
683 * GetFileAttributesA (KERNEL32.@)
685 DWORD WINAPI
GetFileAttributesA( LPCSTR name
)
687 UNICODE_STRING nameW
;
688 DWORD ret
= INVALID_FILE_ATTRIBUTES
;
692 SetLastError( ERROR_INVALID_PARAMETER
);
693 return INVALID_FILE_ATTRIBUTES
;
696 if (RtlCreateUnicodeStringFromAsciiz(&nameW
, name
))
698 ret
= GetFileAttributesW(nameW
.Buffer
);
699 RtlFreeUnicodeString(&nameW
);
702 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
707 /**************************************************************************
708 * SetFileAttributesW (KERNEL32.@)
710 BOOL WINAPI
SetFileAttributesW(LPCWSTR lpFileName
, DWORD attributes
)
713 DOS_FULL_NAME full_name
;
717 SetLastError( ERROR_INVALID_PARAMETER
);
721 TRACE("(%s,%lx)\n", debugstr_w(lpFileName
), attributes
);
723 if (!DOSFS_GetFullName( lpFileName
, TRUE
, &full_name
))
726 if(stat(full_name
.long_name
,&buf
)==-1)
731 if (attributes
& FILE_ATTRIBUTE_READONLY
)
733 if(S_ISDIR(buf
.st_mode
))
735 WARN("FILE_ATTRIBUTE_READONLY ignored for directory.\n");
737 buf
.st_mode
&= ~0222; /* octal!, clear write permission bits */
738 attributes
&= ~FILE_ATTRIBUTE_READONLY
;
742 /* add write permission */
743 buf
.st_mode
|= (0600 | ((buf
.st_mode
& 044) >> 1)) & (~FILE_umask
);
745 if (attributes
& FILE_ATTRIBUTE_DIRECTORY
)
747 if (!S_ISDIR(buf
.st_mode
))
748 FIXME("SetFileAttributes expected the file %s to be a directory\n",
749 debugstr_w(lpFileName
));
750 attributes
&= ~FILE_ATTRIBUTE_DIRECTORY
;
752 attributes
&= ~(FILE_ATTRIBUTE_NORMAL
|FILE_ATTRIBUTE_ARCHIVE
|FILE_ATTRIBUTE_HIDDEN
|
753 FILE_ATTRIBUTE_SYSTEM
|FILE_ATTRIBUTE_TEMPORARY
);
755 FIXME("(%s):%lx attribute(s) not implemented.\n", debugstr_w(lpFileName
), attributes
);
756 if (-1==chmod(full_name
.long_name
,buf
.st_mode
))
758 if (GetDriveTypeW(lpFileName
) == DRIVE_CDROM
)
760 SetLastError( ERROR_ACCESS_DENIED
);
765 * FIXME: We don't return FALSE here because of differences between
766 * Linux and Windows privileges. Under Linux only the owner of
767 * the file is allowed to change file attributes. Under Windows,
768 * applications expect that if you can write to a file, you can also
769 * change its attributes (see GENERIC_WRITE). We could try to be
770 * clever here but that would break multi-user installations where
771 * users share read-only DLLs. This is because some installers like
772 * to change attributes of already installed DLLs.
774 FIXME("Couldn't set file attributes for existing file \"%s\".\n"
775 "Check permissions or set VFAT \"quiet\" mount flag\n", full_name
.long_name
);
781 /**************************************************************************
782 * SetFileAttributesA (KERNEL32.@)
784 BOOL WINAPI
SetFileAttributesA(LPCSTR lpFileName
, DWORD attributes
)
786 UNICODE_STRING filenameW
;
791 SetLastError( ERROR_INVALID_PARAMETER
);
795 if (RtlCreateUnicodeStringFromAsciiz(&filenameW
, lpFileName
))
797 ret
= SetFileAttributesW(filenameW
.Buffer
, attributes
);
798 RtlFreeUnicodeString(&filenameW
);
801 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
806 /******************************************************************************
807 * GetCompressedFileSizeA [KERNEL32.@]
809 DWORD WINAPI
GetCompressedFileSizeA(
811 LPDWORD lpFileSizeHigh
)
813 UNICODE_STRING filenameW
;
816 if (RtlCreateUnicodeStringFromAsciiz(&filenameW
, lpFileName
))
818 ret
= GetCompressedFileSizeW(filenameW
.Buffer
, lpFileSizeHigh
);
819 RtlFreeUnicodeString(&filenameW
);
823 ret
= INVALID_FILE_SIZE
;
824 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
830 /******************************************************************************
831 * GetCompressedFileSizeW [KERNEL32.@]
834 * Success: Low-order doubleword of number of bytes
835 * Failure: INVALID_FILE_SIZE
837 DWORD WINAPI
GetCompressedFileSizeW(
838 LPCWSTR lpFileName
, /* [in] Pointer to name of file */
839 LPDWORD lpFileSizeHigh
) /* [out] Receives high-order doubleword of size */
841 DOS_FULL_NAME full_name
;
845 TRACE("(%s,%p)\n",debugstr_w(lpFileName
),lpFileSizeHigh
);
847 if (!DOSFS_GetFullName( lpFileName
, TRUE
, &full_name
)) return INVALID_FILE_SIZE
;
848 if (stat(full_name
.long_name
, &st
) != 0)
851 return INVALID_FILE_SIZE
;
853 #if HAVE_STRUCT_STAT_ST_BLOCKS
854 /* blocks are 512 bytes long */
855 if (lpFileSizeHigh
) *lpFileSizeHigh
= (st
.st_blocks
>> 23);
856 low
= (DWORD
)(st
.st_blocks
<< 9);
858 if (lpFileSizeHigh
) *lpFileSizeHigh
= (st
.st_size
>> 32);
859 low
= (DWORD
)st
.st_size
;
865 /***********************************************************************
866 * GetFileTime (KERNEL32.@)
868 BOOL WINAPI
GetFileTime( HANDLE hFile
, FILETIME
*lpCreationTime
,
869 FILETIME
*lpLastAccessTime
,
870 FILETIME
*lpLastWriteTime
)
872 BY_HANDLE_FILE_INFORMATION info
;
873 if (!GetFileInformationByHandle( hFile
, &info
)) return FALSE
;
874 if (lpCreationTime
) *lpCreationTime
= info
.ftCreationTime
;
875 if (lpLastAccessTime
) *lpLastAccessTime
= info
.ftLastAccessTime
;
876 if (lpLastWriteTime
) *lpLastWriteTime
= info
.ftLastWriteTime
;
881 /***********************************************************************
882 * GetTempFileNameA (KERNEL32.@)
884 UINT WINAPI
GetTempFileNameA( LPCSTR path
, LPCSTR prefix
, UINT unique
,
887 UNICODE_STRING pathW
, prefixW
;
888 WCHAR bufferW
[MAX_PATH
];
891 if ( !path
|| !prefix
|| !buffer
)
893 SetLastError( ERROR_INVALID_PARAMETER
);
897 RtlCreateUnicodeStringFromAsciiz(&pathW
, path
);
898 RtlCreateUnicodeStringFromAsciiz(&prefixW
, prefix
);
900 ret
= GetTempFileNameW(pathW
.Buffer
, prefixW
.Buffer
, unique
, bufferW
);
902 WideCharToMultiByte(CP_ACP
, 0, bufferW
, -1, buffer
, MAX_PATH
, NULL
, NULL
);
904 RtlFreeUnicodeString(&pathW
);
905 RtlFreeUnicodeString(&prefixW
);
909 /***********************************************************************
910 * GetTempFileNameW (KERNEL32.@)
912 UINT WINAPI
GetTempFileNameW( LPCWSTR path
, LPCWSTR prefix
, UINT unique
,
915 static const WCHAR formatW
[] = {'%','x','.','t','m','p',0};
917 DOS_FULL_NAME full_name
;
921 if ( !path
|| !prefix
|| !buffer
)
923 SetLastError( ERROR_INVALID_PARAMETER
);
927 strcpyW( buffer
, path
);
928 p
= buffer
+ strlenW(buffer
);
930 /* add a \, if there isn't one */
931 if ((p
== buffer
) || (p
[-1] != '\\')) *p
++ = '\\';
933 for (i
= 3; (i
> 0) && (*prefix
); i
--) *p
++ = *prefix
++;
937 if (unique
) sprintfW( p
, formatW
, unique
);
940 /* get a "random" unique number and try to create the file */
942 UINT num
= GetTickCount() & 0xffff;
948 sprintfW( p
, formatW
, unique
);
949 handle
= CreateFileW( buffer
, GENERIC_WRITE
, 0, NULL
,
950 CREATE_NEW
, FILE_ATTRIBUTE_NORMAL
, 0 );
951 if (handle
!= INVALID_HANDLE_VALUE
)
952 { /* We created it */
953 TRACE("created %s\n", debugstr_w(buffer
) );
954 CloseHandle( handle
);
957 if (GetLastError() != ERROR_FILE_EXISTS
&&
958 GetLastError() != ERROR_SHARING_VIOLATION
)
959 break; /* No need to go on */
960 if (!(++unique
& 0xffff)) unique
= 1;
961 } while (unique
!= num
);
964 /* Get the full path name */
966 if (DOSFS_GetFullName( buffer
, FALSE
, &full_name
))
969 /* Check if we have write access in the directory */
970 if ((slash
= strrchr( full_name
.long_name
, '/' ))) *slash
= '\0';
971 if (access( full_name
.long_name
, W_OK
) == -1)
972 WARN("returns %s, which doesn't seem to be writeable.\n",
973 debugstr_w(buffer
) );
975 TRACE("returning %s\n", debugstr_w(buffer
) );
980 /***********************************************************************
983 * Implementation of OpenFile16() and OpenFile32().
985 static HFILE
FILE_DoOpenFile( LPCSTR name
, OFSTRUCT
*ofs
, UINT mode
, BOOL win32
)
990 WORD filedatetime
[2];
991 DOS_FULL_NAME full_name
;
992 DWORD access
, sharing
;
994 WCHAR buffer
[MAX_PATH
];
997 if (!ofs
) return HFILE_ERROR
;
999 TRACE("%s %s %s %s%s%s%s%s%s%s%s%s\n",name
,
1000 ((mode
& 0x3 )==OF_READ
)?"OF_READ":
1001 ((mode
& 0x3 )==OF_WRITE
)?"OF_WRITE":
1002 ((mode
& 0x3 )==OF_READWRITE
)?"OF_READWRITE":"unknown",
1003 ((mode
& 0x70 )==OF_SHARE_COMPAT
)?"OF_SHARE_COMPAT":
1004 ((mode
& 0x70 )==OF_SHARE_DENY_NONE
)?"OF_SHARE_DENY_NONE":
1005 ((mode
& 0x70 )==OF_SHARE_DENY_READ
)?"OF_SHARE_DENY_READ":
1006 ((mode
& 0x70 )==OF_SHARE_DENY_WRITE
)?"OF_SHARE_DENY_WRITE":
1007 ((mode
& 0x70 )==OF_SHARE_EXCLUSIVE
)?"OF_SHARE_EXCLUSIVE":"unknown",
1008 ((mode
& OF_PARSE
)==OF_PARSE
)?"OF_PARSE ":"",
1009 ((mode
& OF_DELETE
)==OF_DELETE
)?"OF_DELETE ":"",
1010 ((mode
& OF_VERIFY
)==OF_VERIFY
)?"OF_VERIFY ":"",
1011 ((mode
& OF_SEARCH
)==OF_SEARCH
)?"OF_SEARCH ":"",
1012 ((mode
& OF_CANCEL
)==OF_CANCEL
)?"OF_CANCEL ":"",
1013 ((mode
& OF_CREATE
)==OF_CREATE
)?"OF_CREATE ":"",
1014 ((mode
& OF_PROMPT
)==OF_PROMPT
)?"OF_PROMPT ":"",
1015 ((mode
& OF_EXIST
)==OF_EXIST
)?"OF_EXIST ":"",
1016 ((mode
& OF_REOPEN
)==OF_REOPEN
)?"OF_REOPEN ":""
1020 ofs
->cBytes
= sizeof(OFSTRUCT
);
1022 if (mode
& OF_REOPEN
) name
= ofs
->szPathName
;
1025 ERR("called with `name' set to NULL ! Please debug.\n");
1029 TRACE("%s %04x\n", name
, mode
);
1031 /* the watcom 10.6 IDE relies on a valid path returned in ofs->szPathName
1032 Are there any cases where getting the path here is wrong?
1033 Uwe Bonnes 1997 Apr 2 */
1034 if (!GetFullPathNameA( name
, sizeof(ofs
->szPathName
),
1035 ofs
->szPathName
, NULL
)) goto error
;
1036 FILE_ConvertOFMode( mode
, &access
, &sharing
);
1038 /* OF_PARSE simply fills the structure */
1040 if (mode
& OF_PARSE
)
1042 ofs
->fFixedDisk
= (GetDriveType16( ofs
->szPathName
[0]-'A' )
1043 != DRIVE_REMOVABLE
);
1044 TRACE("(%s): OF_PARSE, res = '%s'\n",
1045 name
, ofs
->szPathName
);
1049 /* OF_CREATE is completely different from all other options, so
1052 if (mode
& OF_CREATE
)
1054 if ((handle
= CreateFileA( name
, GENERIC_READ
| GENERIC_WRITE
,
1055 sharing
, NULL
, CREATE_ALWAYS
,
1056 FILE_ATTRIBUTE_NORMAL
, 0 ))== INVALID_HANDLE_VALUE
)
1061 MultiByteToWideChar(CP_ACP
, 0, name
, -1, buffer
, MAX_PATH
);
1064 /* If OF_SEARCH is set, ignore the given path */
1066 if ((mode
& OF_SEARCH
) && !(mode
& OF_REOPEN
))
1068 /* First try the file name as is */
1069 if (DOSFS_GetFullName( nameW
, TRUE
, &full_name
)) goto found
;
1070 /* Now remove the path */
1071 if (nameW
[0] && (nameW
[1] == ':')) nameW
+= 2;
1072 if ((p
= strrchrW( nameW
, '\\' ))) nameW
= p
+ 1;
1073 if ((p
= strrchrW( nameW
, '/' ))) nameW
= p
+ 1;
1074 if (!nameW
[0]) goto not_found
;
1077 /* Now look for the file */
1079 if (!DIR_SearchPath( NULL
, nameW
, NULL
, &full_name
, win32
)) goto not_found
;
1082 TRACE("found %s = %s\n",
1083 full_name
.long_name
, debugstr_w(full_name
.short_name
) );
1084 WideCharToMultiByte(CP_ACP
, 0, full_name
.short_name
, -1,
1085 ofs
->szPathName
, sizeof(ofs
->szPathName
), NULL
, NULL
);
1087 if (mode
& OF_DELETE
)
1089 handle
= FILE_CreateFile( full_name
.long_name
, GENERIC_READ
|GENERIC_WRITE
, 0,
1090 NULL
, OPEN_EXISTING
, 0, 0, TRUE
,
1091 GetDriveTypeW( full_name
.short_name
) );
1092 if (!handle
) goto error
;
1093 CloseHandle( handle
);
1094 if (unlink( full_name
.long_name
) == -1) goto not_found
;
1095 TRACE("(%s): OF_DELETE return = OK\n", name
);
1099 handle
= FILE_CreateFile( full_name
.long_name
, access
, sharing
,
1100 NULL
, OPEN_EXISTING
, 0, 0,
1101 DRIVE_GetFlags(full_name
.drive
) & DRIVE_FAIL_READ_ONLY
,
1102 GetDriveTypeW( full_name
.short_name
) );
1103 if (!handle
) goto not_found
;
1105 GetFileTime( handle
, NULL
, NULL
, &filetime
);
1106 FileTimeToDosDateTime( &filetime
, &filedatetime
[0], &filedatetime
[1] );
1107 if ((mode
& OF_VERIFY
) && (mode
& OF_REOPEN
))
1109 if (ofs
->Reserved1
!= filedatetime
[0] || ofs
->Reserved2
!= filedatetime
[1] )
1111 CloseHandle( handle
);
1112 WARN("(%s): OF_VERIFY failed\n", name
);
1113 /* FIXME: what error here? */
1114 SetLastError( ERROR_FILE_NOT_FOUND
);
1118 ofs
->Reserved1
= filedatetime
[0];
1119 ofs
->Reserved2
= filedatetime
[1];
1121 success
: /* We get here if the open was successful */
1122 TRACE("(%s): OK, return = %p\n", name
, handle
);
1125 hFileRet
= (HFILE
)handle
;
1126 if (mode
& OF_EXIST
) /* Return the handle, but close it first */
1127 CloseHandle( handle
);
1131 hFileRet
= Win32HandleToDosFileHandle( handle
);
1132 if (hFileRet
== HFILE_ERROR16
) goto error
;
1133 if (mode
& OF_EXIST
) /* Return the handle, but close it first */
1134 _lclose16( hFileRet
);
1138 not_found
: /* We get here if the file does not exist */
1139 WARN("'%s' not found or sharing violation\n", name
);
1140 SetLastError( ERROR_FILE_NOT_FOUND
);
1143 error
: /* We get here if there was an error opening the file */
1144 ofs
->nErrCode
= GetLastError();
1145 WARN("(%s): return = HFILE_ERROR error= %d\n",
1146 name
,ofs
->nErrCode
);
1151 /***********************************************************************
1152 * OpenFile (KERNEL.74)
1153 * OpenFileEx (KERNEL.360)
1155 HFILE16 WINAPI
OpenFile16( LPCSTR name
, OFSTRUCT
*ofs
, UINT16 mode
)
1157 return FILE_DoOpenFile( name
, ofs
, mode
, FALSE
);
1161 /***********************************************************************
1162 * OpenFile (KERNEL32.@)
1164 HFILE WINAPI
OpenFile( LPCSTR name
, OFSTRUCT
*ofs
, UINT mode
)
1166 return FILE_DoOpenFile( name
, ofs
, mode
, TRUE
);
1170 /******************************************************************
1171 * FILE_ReadWriteApc (internal)
1175 static void WINAPI
FILE_ReadWriteApc(void* apc_user
, PIO_STATUS_BLOCK io_status
, ULONG len
)
1177 LPOVERLAPPED_COMPLETION_ROUTINE cr
= (LPOVERLAPPED_COMPLETION_ROUTINE
)apc_user
;
1179 cr(RtlNtStatusToDosError(io_status
->u
.Status
), len
, (LPOVERLAPPED
)io_status
);
1182 /***********************************************************************
1183 * ReadFileEx (KERNEL32.@)
1185 BOOL WINAPI
ReadFileEx(HANDLE hFile
, LPVOID buffer
, DWORD bytesToRead
,
1186 LPOVERLAPPED overlapped
,
1187 LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine
)
1189 LARGE_INTEGER offset
;
1191 PIO_STATUS_BLOCK io_status
;
1195 SetLastError(ERROR_INVALID_PARAMETER
);
1199 offset
.u
.LowPart
= overlapped
->Offset
;
1200 offset
.u
.HighPart
= overlapped
->OffsetHigh
;
1201 io_status
= (PIO_STATUS_BLOCK
)overlapped
;
1202 io_status
->u
.Status
= STATUS_PENDING
;
1204 status
= NtReadFile(hFile
, NULL
, FILE_ReadWriteApc
, lpCompletionRoutine
,
1205 io_status
, buffer
, bytesToRead
, &offset
, NULL
);
1209 SetLastError( RtlNtStatusToDosError(status
) );
1215 /***********************************************************************
1216 * ReadFile (KERNEL32.@)
1218 BOOL WINAPI
ReadFile( HANDLE hFile
, LPVOID buffer
, DWORD bytesToRead
,
1219 LPDWORD bytesRead
, LPOVERLAPPED overlapped
)
1221 LARGE_INTEGER offset
;
1222 PLARGE_INTEGER poffset
= NULL
;
1223 IO_STATUS_BLOCK iosb
;
1224 PIO_STATUS_BLOCK io_status
= &iosb
;
1228 TRACE("%p %p %ld %p %p\n", hFile
, buffer
, bytesToRead
,
1229 bytesRead
, overlapped
);
1231 if (bytesRead
) *bytesRead
= 0; /* Do this before anything else */
1232 if (!bytesToRead
) return TRUE
;
1234 if (IsBadReadPtr(buffer
, bytesToRead
))
1236 SetLastError(ERROR_WRITE_FAULT
); /* FIXME */
1239 if (is_console_handle(hFile
))
1240 return ReadConsoleA(hFile
, buffer
, bytesToRead
, bytesRead
, NULL
);
1242 if (overlapped
!= NULL
)
1244 offset
.u
.LowPart
= overlapped
->Offset
;
1245 offset
.u
.HighPart
= overlapped
->OffsetHigh
;
1247 hEvent
= overlapped
->hEvent
;
1248 io_status
= (PIO_STATUS_BLOCK
)overlapped
;
1250 io_status
->u
.Status
= STATUS_PENDING
;
1251 io_status
->Information
= 0;
1253 status
= NtReadFile(hFile
, hEvent
, NULL
, NULL
, io_status
, buffer
, bytesToRead
, poffset
, NULL
);
1255 if (status
!= STATUS_PENDING
&& bytesRead
)
1256 *bytesRead
= io_status
->Information
;
1258 if (status
&& status
!= STATUS_END_OF_FILE
)
1260 SetLastError( RtlNtStatusToDosError(status
) );
1267 /***********************************************************************
1268 * WriteFileEx (KERNEL32.@)
1270 BOOL WINAPI
WriteFileEx(HANDLE hFile
, LPCVOID buffer
, DWORD bytesToWrite
,
1271 LPOVERLAPPED overlapped
,
1272 LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine
)
1274 LARGE_INTEGER offset
;
1276 PIO_STATUS_BLOCK io_status
;
1278 TRACE("%p %p %ld %p %p\n",
1279 hFile
, buffer
, bytesToWrite
, overlapped
, lpCompletionRoutine
);
1281 if (overlapped
== NULL
)
1283 SetLastError(ERROR_INVALID_PARAMETER
);
1286 offset
.u
.LowPart
= overlapped
->Offset
;
1287 offset
.u
.HighPart
= overlapped
->OffsetHigh
;
1289 io_status
= (PIO_STATUS_BLOCK
)overlapped
;
1290 io_status
->u
.Status
= STATUS_PENDING
;
1292 status
= NtWriteFile(hFile
, NULL
, FILE_ReadWriteApc
, lpCompletionRoutine
,
1293 io_status
, buffer
, bytesToWrite
, &offset
, NULL
);
1295 if (status
) SetLastError( RtlNtStatusToDosError(status
) );
1299 /***********************************************************************
1300 * WriteFile (KERNEL32.@)
1302 BOOL WINAPI
WriteFile( HANDLE hFile
, LPCVOID buffer
, DWORD bytesToWrite
,
1303 LPDWORD bytesWritten
, LPOVERLAPPED overlapped
)
1305 HANDLE hEvent
= NULL
;
1306 LARGE_INTEGER offset
;
1307 PLARGE_INTEGER poffset
= NULL
;
1309 IO_STATUS_BLOCK iosb
;
1310 PIO_STATUS_BLOCK piosb
= &iosb
;
1312 TRACE("%p %p %ld %p %p\n",
1313 hFile
, buffer
, bytesToWrite
, bytesWritten
, overlapped
);
1315 if (is_console_handle(hFile
))
1316 return WriteConsoleA(hFile
, buffer
, bytesToWrite
, bytesWritten
, NULL
);
1318 if (IsBadReadPtr(buffer
, bytesToWrite
))
1320 SetLastError(ERROR_READ_FAULT
); /* FIXME */
1326 offset
.u
.LowPart
= overlapped
->Offset
;
1327 offset
.u
.HighPart
= overlapped
->OffsetHigh
;
1329 hEvent
= overlapped
->hEvent
;
1330 piosb
= (PIO_STATUS_BLOCK
)overlapped
;
1332 piosb
->u
.Status
= STATUS_PENDING
;
1333 piosb
->Information
= 0;
1335 status
= NtWriteFile(hFile
, hEvent
, NULL
, NULL
, piosb
,
1336 buffer
, bytesToWrite
, poffset
, NULL
);
1339 SetLastError( RtlNtStatusToDosError(status
) );
1342 if (bytesWritten
) *bytesWritten
= piosb
->Information
;
1348 /***********************************************************************
1349 * SetFilePointer (KERNEL32.@)
1351 DWORD WINAPI
SetFilePointer( HANDLE hFile
, LONG distance
, LONG
*highword
,
1354 DWORD ret
= INVALID_SET_FILE_POINTER
;
1356 TRACE("handle %p offset %ld high %ld origin %ld\n",
1357 hFile
, distance
, highword
?*highword
:0, method
);
1359 SERVER_START_REQ( set_file_pointer
)
1361 req
->handle
= hFile
;
1362 req
->low
= distance
;
1363 req
->high
= highword
? *highword
: (distance
>= 0) ? 0 : -1;
1364 /* FIXME: assumes 1:1 mapping between Windows and Unix seek constants */
1365 req
->whence
= method
;
1367 if (!wine_server_call_err( req
))
1369 ret
= reply
->new_low
;
1370 if (highword
) *highword
= reply
->new_high
;
1378 /*************************************************************************
1379 * SetHandleCount (KERNEL32.@)
1381 UINT WINAPI
SetHandleCount( UINT count
)
1383 return min( 256, count
);
1387 /**************************************************************************
1388 * SetEndOfFile (KERNEL32.@)
1390 BOOL WINAPI
SetEndOfFile( HANDLE hFile
)
1393 SERVER_START_REQ( truncate_file
)
1395 req
->handle
= hFile
;
1396 ret
= !wine_server_call_err( req
);
1403 /***********************************************************************
1404 * DeleteFileW (KERNEL32.@)
1406 BOOL WINAPI
DeleteFileW( LPCWSTR path
)
1408 DOS_FULL_NAME full_name
;
1411 TRACE("%s\n", debugstr_w(path
) );
1412 if (!path
|| !*path
)
1414 SetLastError(ERROR_PATH_NOT_FOUND
);
1417 if (RtlIsDosDeviceName_U( path
))
1419 WARN("cannot remove DOS device %s!\n", debugstr_w(path
));
1420 SetLastError( ERROR_FILE_NOT_FOUND
);
1424 if (!DOSFS_GetFullName( path
, TRUE
, &full_name
)) return FALSE
;
1426 /* check if we are allowed to delete the source */
1427 hFile
= FILE_CreateFile( full_name
.long_name
, GENERIC_READ
|GENERIC_WRITE
, 0,
1428 NULL
, OPEN_EXISTING
, 0, 0, TRUE
,
1429 GetDriveTypeW( full_name
.short_name
) );
1430 if (!hFile
) return FALSE
;
1432 if (unlink( full_name
.long_name
) == -1)
1443 /***********************************************************************
1444 * DeleteFileA (KERNEL32.@)
1446 BOOL WINAPI
DeleteFileA( LPCSTR path
)
1448 UNICODE_STRING pathW
;
1453 SetLastError(ERROR_INVALID_PARAMETER
);
1457 if (RtlCreateUnicodeStringFromAsciiz(&pathW
, path
))
1459 ret
= DeleteFileW(pathW
.Buffer
);
1460 RtlFreeUnicodeString(&pathW
);
1463 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
1468 /***********************************************************************
1469 * GetFileType (KERNEL32.@)
1471 DWORD WINAPI
GetFileType( HANDLE hFile
)
1473 DWORD ret
= FILE_TYPE_UNKNOWN
;
1475 if (is_console_handle( hFile
))
1476 return FILE_TYPE_CHAR
;
1478 SERVER_START_REQ( get_file_info
)
1480 req
->handle
= hFile
;
1481 if (!wine_server_call_err( req
)) ret
= reply
->type
;
1488 /* check if a file name is for an executable file (.exe or .com) */
1489 inline static BOOL
is_executable( const char *name
)
1491 int len
= strlen(name
);
1493 if (len
< 4) return FALSE
;
1494 return (!strcasecmp( name
+ len
- 4, ".exe" ) ||
1495 !strcasecmp( name
+ len
- 4, ".com" ));
1499 /***********************************************************************
1500 * FILE_AddBootRenameEntry
1502 * Adds an entry to the registry that is loaded when windows boots and
1503 * checks if there are some files to be removed or renamed/moved.
1504 * <fn1> has to be valid and <fn2> may be NULL. If both pointers are
1505 * non-NULL then the file is moved, otherwise it is deleted. The
1506 * entry of the registrykey is always appended with two zero
1507 * terminated strings. If <fn2> is NULL then the second entry is
1508 * simply a single 0-byte. Otherwise the second filename goes
1509 * there. The entries are prepended with \??\ before the path and the
1510 * second filename gets also a '!' as the first character if
1511 * MOVEFILE_REPLACE_EXISTING is set. After the final string another
1512 * 0-byte follows to indicate the end of the strings.
1514 * \??\D:\test\file1[0]
1515 * !\??\D:\test\file1_renamed[0]
1516 * \??\D:\Test|delete[0]
1517 * [0] <- file is to be deleted, second string empty
1518 * \??\D:\test\file2[0]
1519 * !\??\D:\test\file2_renamed[0]
1520 * [0] <- indicates end of strings
1523 * \??\D:\test\file1[0]
1524 * !\??\D:\test\file1_renamed[0]
1525 * \??\D:\Test|delete[0]
1526 * [0] <- file is to be deleted, second string empty
1527 * [0] <- indicates end of strings
1530 static BOOL
FILE_AddBootRenameEntry( LPCWSTR fn1
, LPCWSTR fn2
, DWORD flags
)
1532 static const WCHAR PreString
[] = {'\\','?','?','\\',0};
1533 static const WCHAR ValueName
[] = {'P','e','n','d','i','n','g',
1534 'F','i','l','e','R','e','n','a','m','e',
1535 'O','p','e','r','a','t','i','o','n','s',0};
1536 static const WCHAR SessionW
[] = {'M','a','c','h','i','n','e','\\',
1537 'S','y','s','t','e','m','\\',
1538 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
1539 'C','o','n','t','r','o','l','\\',
1540 'S','e','s','s','i','o','n',' ','M','a','n','a','g','e','r',0};
1541 static const int info_size
= FIELD_OFFSET( KEY_VALUE_PARTIAL_INFORMATION
, Data
);
1543 OBJECT_ATTRIBUTES attr
;
1544 UNICODE_STRING nameW
;
1545 KEY_VALUE_PARTIAL_INFORMATION
*info
;
1548 DWORD len0
, len1
, len2
;
1550 BYTE
*Buffer
= NULL
;
1553 attr
.Length
= sizeof(attr
);
1554 attr
.RootDirectory
= 0;
1555 attr
.ObjectName
= &nameW
;
1556 attr
.Attributes
= 0;
1557 attr
.SecurityDescriptor
= NULL
;
1558 attr
.SecurityQualityOfService
= NULL
;
1559 RtlInitUnicodeString( &nameW
, SessionW
);
1561 if (NtCreateKey( &Reboot
, KEY_ALL_ACCESS
, &attr
, 0, NULL
, 0, NULL
) != STATUS_SUCCESS
)
1563 WARN("Error creating key for reboot managment [%s]\n",
1564 "SYSTEM\\CurrentControlSet\\Control\\Session Manager");
1568 len0
= strlenW(PreString
);
1569 len1
= strlenW(fn1
) + len0
+ 1;
1572 len2
= strlenW(fn2
) + len0
+ 1;
1573 if (flags
& MOVEFILE_REPLACE_EXISTING
) len2
++; /* Plus 1 because of the leading '!' */
1575 else len2
= 1; /* minimum is the 0 characters for the empty second string */
1577 /* convert characters to bytes */
1578 len0
*= sizeof(WCHAR
);
1579 len1
*= sizeof(WCHAR
);
1580 len2
*= sizeof(WCHAR
);
1582 RtlInitUnicodeString( &nameW
, ValueName
);
1584 /* First we check if the key exists and if so how many bytes it already contains. */
1585 if (NtQueryValueKey( Reboot
, &nameW
, KeyValuePartialInformation
,
1586 NULL
, 0, &DataSize
) == STATUS_BUFFER_OVERFLOW
)
1588 if (!(Buffer
= HeapAlloc( GetProcessHeap(), 0, DataSize
+ len1
+ len2
+ sizeof(WCHAR
) )))
1590 if (NtQueryValueKey( Reboot
, &nameW
, KeyValuePartialInformation
,
1591 Buffer
, DataSize
, &DataSize
)) goto Quit
;
1592 info
= (KEY_VALUE_PARTIAL_INFORMATION
*)Buffer
;
1593 if (info
->Type
!= REG_MULTI_SZ
) goto Quit
;
1594 if (DataSize
> sizeof(info
)) DataSize
-= sizeof(WCHAR
); /* remove terminating null (will be added back later) */
1598 DataSize
= info_size
;
1599 if (!(Buffer
= HeapAlloc( GetProcessHeap(), 0, DataSize
+ len1
+ len2
+ sizeof(WCHAR
) )))
1603 p
= (WCHAR
*)(Buffer
+ DataSize
);
1604 strcpyW( p
, PreString
);
1609 p
= (WCHAR
*)(Buffer
+ DataSize
);
1610 if (flags
& MOVEFILE_REPLACE_EXISTING
)
1612 strcpyW( p
, PreString
);
1618 p
= (WCHAR
*)(Buffer
+ DataSize
);
1620 DataSize
+= sizeof(WCHAR
);
1623 /* add final null */
1624 p
= (WCHAR
*)(Buffer
+ DataSize
);
1626 DataSize
+= sizeof(WCHAR
);
1628 rc
= !NtSetValueKey(Reboot
, &nameW
, 0, REG_MULTI_SZ
, Buffer
+ info_size
, DataSize
- info_size
);
1631 if (Reboot
) NtClose(Reboot
);
1632 if (Buffer
) HeapFree( GetProcessHeap(), 0, Buffer
);
1637 /**************************************************************************
1638 * MoveFileExW (KERNEL32.@)
1640 BOOL WINAPI
MoveFileExW( LPCWSTR fn1
, LPCWSTR fn2
, DWORD flag
)
1642 DOS_FULL_NAME full_name1
, full_name2
;
1644 DWORD attr
= INVALID_FILE_ATTRIBUTES
;
1646 TRACE("(%s,%s,%04lx)\n", debugstr_w(fn1
), debugstr_w(fn2
), flag
);
1648 /* FIXME: <Gerhard W. Gruber>sparhawk@gmx.at
1649 In case of W9x and lesser this function should return 120 (ERROR_CALL_NOT_IMPLEMENTED)
1650 to be really compatible. Most programs won't have any problems though. In case
1651 you encounter one, this is what you should return here. I don't know what's up
1652 with NT 3.5. Is this function available there or not?
1653 Does anybody really care about 3.5? :)
1656 /* Filename1 has to be always set to a valid path. Filename2 may be NULL
1657 if the source file has to be deleted.
1660 SetLastError(ERROR_INVALID_PARAMETER
);
1664 /* This function has to be run through in order to process the name properly.
1665 If the BOOTDELAY flag is set, the file doesn't need to exist though. At least
1666 that is the behaviour on NT 4.0. The operation accepts the filenames as
1667 they are given but it can't reply with a reasonable returncode. Success
1668 means in that case success for entering the values into the registry.
1670 if(!DOSFS_GetFullName( fn1
, TRUE
, &full_name1
))
1672 if(!(flag
& MOVEFILE_DELAY_UNTIL_REBOOT
))
1676 if (fn2
) /* !fn2 means delete fn1 */
1678 if (DOSFS_GetFullName( fn2
, TRUE
, &full_name2
))
1680 if(!(flag
& MOVEFILE_DELAY_UNTIL_REBOOT
))
1682 /* target exists, check if we may overwrite */
1683 if (!(flag
& MOVEFILE_REPLACE_EXISTING
))
1685 SetLastError( ERROR_ALREADY_EXISTS
);
1692 if (!DOSFS_GetFullName( fn2
, FALSE
, &full_name2
))
1694 if(!(flag
& MOVEFILE_DELAY_UNTIL_REBOOT
))
1699 /* Source name and target path are valid */
1701 if (flag
& MOVEFILE_DELAY_UNTIL_REBOOT
)
1703 return FILE_AddBootRenameEntry( fn1
, fn2
, flag
);
1706 attr
= GetFileAttributesW( fn1
);
1707 if ( attr
== INVALID_FILE_ATTRIBUTES
) return FALSE
;
1709 /* check if we are allowed to rename the source */
1710 hFile
= FILE_CreateFile( full_name1
.long_name
, 0, 0,
1711 NULL
, OPEN_EXISTING
, 0, 0, TRUE
,
1712 GetDriveTypeW( full_name1
.short_name
) );
1715 if (GetLastError() != ERROR_ACCESS_DENIED
) return FALSE
;
1716 if ( !(attr
& FILE_ATTRIBUTE_DIRECTORY
) ) return FALSE
;
1717 /* if it's a directory we can continue */
1719 else CloseHandle(hFile
);
1721 /* check, if we are allowed to delete the destination,
1722 ** (but the file not being there is fine) */
1723 hFile
= FILE_CreateFile( full_name2
.long_name
, GENERIC_READ
|GENERIC_WRITE
, 0,
1724 NULL
, OPEN_EXISTING
, 0, 0, TRUE
,
1725 GetDriveTypeW( full_name2
.short_name
) );
1726 if(!hFile
&& GetLastError() != ERROR_FILE_NOT_FOUND
) return FALSE
;
1729 if (full_name1
.drive
!= full_name2
.drive
)
1731 if (!(flag
& MOVEFILE_COPY_ALLOWED
))
1733 SetLastError( ERROR_NOT_SAME_DEVICE
);
1736 else if ( attr
& FILE_ATTRIBUTE_DIRECTORY
)
1738 /* Strange, but that's what Windows returns */
1739 SetLastError ( ERROR_ACCESS_DENIED
);
1743 if (rename( full_name1
.long_name
, full_name2
.long_name
) == -1)
1744 /* Try copy/delete unless it's a directory. */
1745 /* FIXME: This does not handle the (unlikely) case that the two locations
1746 are on the same Wine drive, but on different Unix file systems. */
1748 if ( attr
& FILE_ATTRIBUTE_DIRECTORY
)
1755 if ( ! CopyFileW( fn1
, fn2
, !(flag
& MOVEFILE_REPLACE_EXISTING
) ))
1757 if ( ! DeleteFileW ( fn1
) )
1761 if (is_executable( full_name1
.long_name
) != is_executable( full_name2
.long_name
))
1764 if (stat( full_name2
.long_name
, &fstat
) != -1)
1766 if (is_executable( full_name2
.long_name
))
1767 /* set executable bit where read bit is set */
1768 fstat
.st_mode
|= (fstat
.st_mode
& 0444) >> 2;
1770 fstat
.st_mode
&= ~0111;
1771 chmod( full_name2
.long_name
, fstat
.st_mode
);
1776 else /* fn2 == NULL means delete source */
1778 if (flag
& MOVEFILE_DELAY_UNTIL_REBOOT
)
1780 if (flag
& MOVEFILE_COPY_ALLOWED
) {
1781 WARN("Illegal flag\n");
1782 SetLastError( ERROR_GEN_FAILURE
);
1786 return FILE_AddBootRenameEntry( fn1
, NULL
, flag
);
1789 if (unlink( full_name1
.long_name
) == -1)
1794 return TRUE
; /* successfully deleted */
1798 /**************************************************************************
1799 * MoveFileExA (KERNEL32.@)
1801 BOOL WINAPI
MoveFileExA( LPCSTR fn1
, LPCSTR fn2
, DWORD flag
)
1803 UNICODE_STRING fn1W
, fn2W
;
1808 SetLastError(ERROR_INVALID_PARAMETER
);
1812 RtlCreateUnicodeStringFromAsciiz(&fn1W
, fn1
);
1813 if (fn2
) RtlCreateUnicodeStringFromAsciiz(&fn2W
, fn2
);
1814 else fn2W
.Buffer
= NULL
;
1816 ret
= MoveFileExW( fn1W
.Buffer
, fn2W
.Buffer
, flag
);
1818 RtlFreeUnicodeString(&fn1W
);
1819 RtlFreeUnicodeString(&fn2W
);
1824 /**************************************************************************
1825 * MoveFileW (KERNEL32.@)
1827 * Move file or directory
1829 BOOL WINAPI
MoveFileW( LPCWSTR fn1
, LPCWSTR fn2
)
1831 return MoveFileExW( fn1
, fn2
, MOVEFILE_COPY_ALLOWED
);
1835 /**************************************************************************
1836 * MoveFileA (KERNEL32.@)
1838 BOOL WINAPI
MoveFileA( LPCSTR fn1
, LPCSTR fn2
)
1840 return MoveFileExA( fn1
, fn2
, MOVEFILE_COPY_ALLOWED
);
1844 /**************************************************************************
1845 * CopyFileW (KERNEL32.@)
1847 BOOL WINAPI
CopyFileW( LPCWSTR source
, LPCWSTR dest
, BOOL fail_if_exists
)
1850 BY_HANDLE_FILE_INFORMATION info
;
1855 if (!source
|| !dest
)
1857 SetLastError(ERROR_INVALID_PARAMETER
);
1861 TRACE("%s -> %s\n", debugstr_w(source
), debugstr_w(dest
));
1863 if ((h1
= CreateFileW(source
, GENERIC_READ
, FILE_SHARE_READ
| FILE_SHARE_WRITE
,
1864 NULL
, OPEN_EXISTING
, 0, 0)) == INVALID_HANDLE_VALUE
)
1866 WARN("Unable to open source %s\n", debugstr_w(source
));
1870 if (!GetFileInformationByHandle( h1
, &info
))
1872 WARN("GetFileInformationByHandle returned error for %s\n", debugstr_w(source
));
1877 if ((h2
= CreateFileW( dest
, GENERIC_WRITE
, FILE_SHARE_READ
| FILE_SHARE_WRITE
, NULL
,
1878 fail_if_exists
? CREATE_NEW
: CREATE_ALWAYS
,
1879 info
.dwFileAttributes
, h1
)) == INVALID_HANDLE_VALUE
)
1881 WARN("Unable to open dest %s\n", debugstr_w(dest
));
1886 while (ReadFile( h1
, buffer
, sizeof(buffer
), &count
, NULL
) && count
)
1892 if (!WriteFile( h2
, p
, count
, &res
, NULL
) || !res
) goto done
;
1905 /**************************************************************************
1906 * CopyFileA (KERNEL32.@)
1908 BOOL WINAPI
CopyFileA( LPCSTR source
, LPCSTR dest
, BOOL fail_if_exists
)
1910 UNICODE_STRING sourceW
, destW
;
1913 if (!source
|| !dest
)
1915 SetLastError(ERROR_INVALID_PARAMETER
);
1919 RtlCreateUnicodeStringFromAsciiz(&sourceW
, source
);
1920 RtlCreateUnicodeStringFromAsciiz(&destW
, dest
);
1922 ret
= CopyFileW(sourceW
.Buffer
, destW
.Buffer
, fail_if_exists
);
1924 RtlFreeUnicodeString(&sourceW
);
1925 RtlFreeUnicodeString(&destW
);
1930 /**************************************************************************
1931 * CopyFileExW (KERNEL32.@)
1933 * This implementation ignores most of the extra parameters passed-in into
1934 * the "ex" version of the method and calls the CopyFile method.
1935 * It will have to be fixed eventually.
1937 BOOL WINAPI
CopyFileExW(LPCWSTR sourceFilename
, LPCWSTR destFilename
,
1938 LPPROGRESS_ROUTINE progressRoutine
, LPVOID appData
,
1939 LPBOOL cancelFlagPointer
, DWORD copyFlags
)
1942 * Interpret the only flag that CopyFile can interpret.
1944 return CopyFileW(sourceFilename
, destFilename
, (copyFlags
& COPY_FILE_FAIL_IF_EXISTS
) != 0);
1948 /**************************************************************************
1949 * CopyFileExA (KERNEL32.@)
1951 BOOL WINAPI
CopyFileExA(LPCSTR sourceFilename
, LPCSTR destFilename
,
1952 LPPROGRESS_ROUTINE progressRoutine
, LPVOID appData
,
1953 LPBOOL cancelFlagPointer
, DWORD copyFlags
)
1955 UNICODE_STRING sourceW
, destW
;
1958 if (!sourceFilename
|| !destFilename
)
1960 SetLastError(ERROR_INVALID_PARAMETER
);
1964 RtlCreateUnicodeStringFromAsciiz(&sourceW
, sourceFilename
);
1965 RtlCreateUnicodeStringFromAsciiz(&destW
, destFilename
);
1967 ret
= CopyFileExW(sourceW
.Buffer
, destW
.Buffer
, progressRoutine
, appData
,
1968 cancelFlagPointer
, copyFlags
);
1970 RtlFreeUnicodeString(&sourceW
);
1971 RtlFreeUnicodeString(&destW
);
1976 /***********************************************************************
1977 * SetFileTime (KERNEL32.@)
1979 BOOL WINAPI
SetFileTime( HANDLE hFile
,
1980 const FILETIME
*lpCreationTime
,
1981 const FILETIME
*lpLastAccessTime
,
1982 const FILETIME
*lpLastWriteTime
)
1985 SERVER_START_REQ( set_file_time
)
1987 req
->handle
= hFile
;
1988 if (lpLastAccessTime
)
1989 RtlTimeToSecondsSince1970( (PLARGE_INTEGER
) lpLastAccessTime
, (DWORD
*)&req
->access_time
);
1991 req
->access_time
= 0; /* FIXME */
1992 if (lpLastWriteTime
)
1993 RtlTimeToSecondsSince1970( (PLARGE_INTEGER
) lpLastWriteTime
, (DWORD
*)&req
->write_time
);
1995 req
->write_time
= 0; /* FIXME */
1996 ret
= !wine_server_call_err( req
);
2003 /**************************************************************************
2004 * GetFileAttributesExW (KERNEL32.@)
2006 BOOL WINAPI
GetFileAttributesExW(
2007 LPCWSTR lpFileName
, GET_FILEEX_INFO_LEVELS fInfoLevelId
,
2008 LPVOID lpFileInformation
)
2010 DOS_FULL_NAME full_name
;
2011 BY_HANDLE_FILE_INFORMATION info
;
2013 if (!lpFileName
|| !lpFileInformation
)
2015 SetLastError(ERROR_INVALID_PARAMETER
);
2019 if (fInfoLevelId
== GetFileExInfoStandard
) {
2020 LPWIN32_FILE_ATTRIBUTE_DATA lpFad
=
2021 (LPWIN32_FILE_ATTRIBUTE_DATA
) lpFileInformation
;
2022 if (!DOSFS_GetFullName( lpFileName
, TRUE
, &full_name
)) return FALSE
;
2023 if (!FILE_Stat( full_name
.long_name
, &info
, NULL
)) return FALSE
;
2025 lpFad
->dwFileAttributes
= info
.dwFileAttributes
;
2026 lpFad
->ftCreationTime
= info
.ftCreationTime
;
2027 lpFad
->ftLastAccessTime
= info
.ftLastAccessTime
;
2028 lpFad
->ftLastWriteTime
= info
.ftLastWriteTime
;
2029 lpFad
->nFileSizeHigh
= info
.nFileSizeHigh
;
2030 lpFad
->nFileSizeLow
= info
.nFileSizeLow
;
2033 FIXME("invalid info level %d!\n", fInfoLevelId
);
2041 /**************************************************************************
2042 * GetFileAttributesExA (KERNEL32.@)
2044 BOOL WINAPI
GetFileAttributesExA(
2045 LPCSTR filename
, GET_FILEEX_INFO_LEVELS fInfoLevelId
,
2046 LPVOID lpFileInformation
)
2048 UNICODE_STRING filenameW
;
2051 if (!filename
|| !lpFileInformation
)
2053 SetLastError(ERROR_INVALID_PARAMETER
);
2057 if (RtlCreateUnicodeStringFromAsciiz(&filenameW
, filename
))
2059 ret
= GetFileAttributesExW(filenameW
.Buffer
, fInfoLevelId
, lpFileInformation
);
2060 RtlFreeUnicodeString(&filenameW
);
2063 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);