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"
75 #include "../kernel/kernel_private.h"
78 #include "wine/unicode.h"
79 #include "wine/debug.h"
81 WINE_DEFAULT_DEBUG_CHANNEL(file
);
83 #if defined(MAP_ANONYMOUS) && !defined(MAP_ANON)
84 #define MAP_ANON MAP_ANONYMOUS
87 #define IS_OPTION_TRUE(ch) ((ch) == 'y' || (ch) == 'Y' || (ch) == 't' || (ch) == 'T' || (ch) == '1')
89 HANDLE dos_handles
[DOS_TABLE_SIZE
];
92 /***********************************************************************
95 * Convert OF_* mode into flags for CreateFile.
97 void FILE_ConvertOFMode( INT mode
, DWORD
*access
, DWORD
*sharing
)
101 case OF_READ
: *access
= GENERIC_READ
; break;
102 case OF_WRITE
: *access
= GENERIC_WRITE
; break;
103 case OF_READWRITE
: *access
= GENERIC_READ
| GENERIC_WRITE
; break;
104 default: *access
= 0; break;
108 case OF_SHARE_EXCLUSIVE
: *sharing
= 0; break;
109 case OF_SHARE_DENY_WRITE
: *sharing
= FILE_SHARE_READ
; break;
110 case OF_SHARE_DENY_READ
: *sharing
= FILE_SHARE_WRITE
; break;
111 case OF_SHARE_DENY_NONE
:
112 case OF_SHARE_COMPAT
:
113 default: *sharing
= FILE_SHARE_READ
| FILE_SHARE_WRITE
; break;
118 /***********************************************************************
121 * locale-independent case conversion for file I/O
123 int FILE_strcasecmp( const char *str1
, const char *str2
)
126 for ( ; ; str1
++, str2
++)
127 if ((ret
= FILE_toupper(*str1
) - FILE_toupper(*str2
)) || !*str1
) break;
132 /***********************************************************************
135 * locale-independent case conversion for file I/O
137 int FILE_strncasecmp( const char *str1
, const char *str2
, int len
)
140 for ( ; len
> 0; len
--, str1
++, str2
++)
141 if ((ret
= FILE_toupper(*str1
) - FILE_toupper(*str2
)) || !*str1
) break;
146 /***********************************************************************
149 * Set the DOS error code from errno.
151 void FILE_SetDosError(void)
153 int save_errno
= errno
; /* errno gets overwritten by printf */
155 TRACE("errno = %d %s\n", errno
, strerror(errno
));
159 SetLastError( ERROR_SHARING_VIOLATION
);
162 SetLastError( ERROR_INVALID_HANDLE
);
165 SetLastError( ERROR_HANDLE_DISK_FULL
);
170 SetLastError( ERROR_ACCESS_DENIED
);
173 SetLastError( ERROR_LOCK_VIOLATION
);
176 SetLastError( ERROR_FILE_NOT_FOUND
);
179 SetLastError( ERROR_CANNOT_MAKE
);
183 SetLastError( ERROR_NO_MORE_FILES
);
186 SetLastError( ERROR_FILE_EXISTS
);
190 SetLastError( ERROR_SEEK
);
193 SetLastError( ERROR_DIR_NOT_EMPTY
);
196 SetLastError( ERROR_BAD_FORMAT
);
199 WARN("unknown file error: %s\n", strerror(save_errno
) );
200 SetLastError( ERROR_GEN_FAILURE
);
207 /***********************************************************************
208 * FILE_GetUnixHandleType
210 * Retrieve the Unix handle corresponding to a file handle.
211 * Returns -1 on failure.
213 static int FILE_GetUnixHandleType( HANDLE handle
, DWORD access
, enum fd_type
*type
, int *flags_ptr
)
215 int ret
, flags
, fd
= -1;
217 ret
= wine_server_handle_to_fd( handle
, access
, &fd
, type
, &flags
);
218 if (flags_ptr
) *flags_ptr
= flags
;
219 if (ret
) SetLastError( RtlNtStatusToDosError(ret
) );
220 else if (((access
& GENERIC_READ
) && (flags
& FD_FLAG_RECV_SHUTDOWN
)) ||
221 ((access
& GENERIC_WRITE
) && (flags
& FD_FLAG_SEND_SHUTDOWN
)))
224 SetLastError ( ERROR_PIPE_NOT_CONNECTED
);
230 /***********************************************************************
233 * Retrieve the Unix handle corresponding to a file handle.
234 * Returns -1 on failure.
236 int FILE_GetUnixHandle( HANDLE handle
, DWORD access
)
238 return FILE_GetUnixHandleType( handle
, access
, NULL
, NULL
);
241 /******************************************************************
242 * OpenConsoleW (KERNEL32.@)
245 * Open a handle to the current process console.
246 * Returns INVALID_HANDLE_VALUE on failure.
248 HANDLE WINAPI
OpenConsoleW(LPCWSTR name
, DWORD access
, LPSECURITY_ATTRIBUTES sa
,
251 static const WCHAR coninW
[] = {'C','O','N','I','N','$',0};
252 static const WCHAR conoutW
[] = {'C','O','N','O','U','T','$',0};
256 if (strcmpW(coninW
, name
) == 0)
258 else if (strcmpW(conoutW
, name
) == 0)
262 SetLastError(ERROR_INVALID_NAME
);
263 return INVALID_HANDLE_VALUE
;
265 if (creation
!= OPEN_EXISTING
)
267 SetLastError(ERROR_INVALID_PARAMETER
);
268 return INVALID_HANDLE_VALUE
;
271 SERVER_START_REQ( open_console
)
274 req
->access
= access
;
275 req
->share
= FILE_SHARE_READ
| FILE_SHARE_WRITE
;
276 req
->inherit
= (sa
&& (sa
->nLength
>=sizeof(*sa
)) && sa
->bInheritHandle
);
278 wine_server_call_err( req
);
282 return ret
? console_handle_map(ret
) : INVALID_HANDLE_VALUE
;
285 /******************************************************************
286 * VerifyConsoleIoHandle (KERNEL32.@)
290 BOOL WINAPI
VerifyConsoleIoHandle(HANDLE handle
)
294 if (!is_console_handle(handle
)) return FALSE
;
295 SERVER_START_REQ(get_console_mode
)
297 req
->handle
= console_handle_unmap(handle
);
298 ret
= !wine_server_call_err( req
);
304 /******************************************************************
305 * DuplicateConsoleHandle (KERNEL32.@)
309 HANDLE WINAPI
DuplicateConsoleHandle(HANDLE handle
, DWORD access
, BOOL inherit
,
314 if (!is_console_handle(handle
) ||
315 !DuplicateHandle(GetCurrentProcess(), console_handle_unmap(handle
),
316 GetCurrentProcess(), &ret
, access
, inherit
, options
))
317 return INVALID_HANDLE_VALUE
;
318 return console_handle_map(ret
);
321 /******************************************************************
322 * CloseConsoleHandle (KERNEL32.@)
326 BOOL WINAPI
CloseConsoleHandle(HANDLE handle
)
328 if (!is_console_handle(handle
))
330 SetLastError(ERROR_INVALID_PARAMETER
);
333 return CloseHandle(console_handle_unmap(handle
));
336 /******************************************************************
337 * GetConsoleInputWaitHandle (KERNEL32.@)
341 HANDLE WINAPI
GetConsoleInputWaitHandle(void)
343 static HANDLE console_wait_event
;
345 /* FIXME: this is not thread safe */
346 if (!console_wait_event
)
348 SERVER_START_REQ(get_console_wait_event
)
350 if (!wine_server_call_err( req
)) console_wait_event
= reply
->handle
;
354 return console_wait_event
;
359 /* FIXME: those routines defined as pointers are needed, because this file is
360 * currently compiled into NTDLL whereas it belongs to kernel32.
361 * this shall go away once all the DLL separation process is done
363 typedef BOOL (WINAPI
* pRW
)(HANDLE
, const void*, DWORD
, DWORD
*, void*);
365 static BOOL
FILE_ReadConsole(HANDLE hCon
, void* buf
, DWORD nb
, DWORD
* nr
, void* p
)
367 static HANDLE hKernel
/* = 0 */;
368 static pRW pReadConsole
/* = 0 */;
370 if ((!hKernel
&& !(hKernel
= LoadLibraryA("kernel32"))) ||
372 !(pReadConsole
= GetProcAddress(hKernel
, "ReadConsoleA"))))
377 return (pReadConsole
)(hCon
, buf
, nb
, nr
, p
);
380 static BOOL
FILE_WriteConsole(HANDLE hCon
, const void* buf
, DWORD nb
, DWORD
* nr
, void* p
)
382 static HANDLE hKernel
/* = 0 */;
383 static pRW pWriteConsole
/* = 0 */;
385 if ((!hKernel
&& !(hKernel
= LoadLibraryA("kernel32"))) ||
387 !(pWriteConsole
= GetProcAddress(hKernel
, "WriteConsoleA"))))
392 return (pWriteConsole
)(hCon
, buf
, nb
, nr
, p
);
396 /***********************************************************************
399 * Implementation of CreateFile. Takes a Unix path name.
400 * Returns 0 on failure.
402 HANDLE
FILE_CreateFile( LPCSTR filename
, DWORD access
, DWORD sharing
,
403 LPSECURITY_ATTRIBUTES sa
, DWORD creation
,
404 DWORD attributes
, HANDLE
template, BOOL fail_read_only
,
412 SERVER_START_REQ( create_file
)
414 req
->access
= access
;
415 req
->inherit
= (sa
&& (sa
->nLength
>=sizeof(*sa
)) && sa
->bInheritHandle
);
416 req
->sharing
= sharing
;
417 req
->create
= creation
;
418 req
->attrs
= attributes
;
419 req
->drive_type
= drive_type
;
420 wine_server_add_data( req
, filename
, strlen(filename
) );
422 err
= wine_server_call( req
);
427 /* If write access failed, retry without GENERIC_WRITE */
429 if (!ret
&& !fail_read_only
&& (access
& GENERIC_WRITE
))
431 if ((err
== STATUS_MEDIA_WRITE_PROTECTED
) || (err
== STATUS_ACCESS_DENIED
))
433 TRACE("Write access failed for file '%s', trying without "
434 "write access\n", filename
);
435 access
&= ~GENERIC_WRITE
;
442 /* In the case file creation was rejected due to CREATE_NEW flag
443 * was specified and file with that name already exists, correct
444 * last error is ERROR_FILE_EXISTS and not ERROR_ALREADY_EXISTS.
445 * Note: RtlNtStatusToDosError is not the subject to blame here.
447 if (err
== STATUS_OBJECT_NAME_COLLISION
)
448 SetLastError( ERROR_FILE_EXISTS
);
450 SetLastError( RtlNtStatusToDosError(err
) );
453 if (!ret
) WARN("Unable to create file '%s' (GLE %ld)\n", filename
, GetLastError());
459 /***********************************************************************
462 * Same as FILE_CreateFile but for a device
463 * Returns 0 on failure.
465 HANDLE
FILE_CreateDevice( int client_id
, DWORD access
, LPSECURITY_ATTRIBUTES sa
)
468 SERVER_START_REQ( create_device
)
470 req
->access
= access
;
471 req
->inherit
= (sa
&& (sa
->nLength
>=sizeof(*sa
)) && sa
->bInheritHandle
);
474 wine_server_call_err( req
);
481 static HANDLE
FILE_OpenPipe(LPCWSTR name
, DWORD access
, LPSECURITY_ATTRIBUTES sa
)
486 if (name
&& (len
= strlenW(name
)) > MAX_PATH
)
488 SetLastError( ERROR_FILENAME_EXCED_RANGE
);
491 SERVER_START_REQ( open_named_pipe
)
493 req
->access
= access
;
494 req
->inherit
= (sa
&& (sa
->nLength
>=sizeof(*sa
)) && sa
->bInheritHandle
);
496 wine_server_add_data( req
, name
, len
* sizeof(WCHAR
) );
497 wine_server_call_err( req
);
501 TRACE("Returned %p\n",ret
);
505 /*************************************************************************
506 * CreateFileW [KERNEL32.@] Creates or opens a file or other object
508 * Creates or opens an object, and returns a handle that can be used to
509 * access that object.
513 * filename [in] pointer to filename to be accessed
514 * access [in] access mode requested
515 * sharing [in] share mode
516 * sa [in] pointer to security attributes
517 * creation [in] how to create the file
518 * attributes [in] attributes for newly created file
519 * template [in] handle to file with extended attributes to copy
522 * Success: Open handle to specified file
523 * Failure: INVALID_HANDLE_VALUE
526 * Should call SetLastError() on failure.
530 * Doesn't support character devices, template files, or a
531 * lot of the 'attributes' flags yet.
533 HANDLE WINAPI
CreateFileW( LPCWSTR filename
, DWORD access
, DWORD sharing
,
534 LPSECURITY_ATTRIBUTES sa
, DWORD creation
,
535 DWORD attributes
, HANDLE
template )
537 DOS_FULL_NAME full_name
;
539 static const WCHAR bkslashes_with_question_markW
[] = {'\\','\\','?','\\',0};
540 static const WCHAR bkslashes_with_dotW
[] = {'\\','\\','.','\\',0};
541 static const WCHAR bkslashesW
[] = {'\\','\\',0};
542 static const WCHAR coninW
[] = {'C','O','N','I','N','$',0};
543 static const WCHAR conoutW
[] = {'C','O','N','O','U','T','$',0};
547 SetLastError( ERROR_INVALID_PARAMETER
);
548 return INVALID_HANDLE_VALUE
;
550 TRACE("%s %s%s%s%s%s%s%s attributes 0x%lx\n", debugstr_w(filename
),
551 ((access
& GENERIC_READ
)==GENERIC_READ
)?"GENERIC_READ ":"",
552 ((access
& GENERIC_WRITE
)==GENERIC_WRITE
)?"GENERIC_WRITE ":"",
553 (!access
)?"QUERY_ACCESS ":"",
554 ((sharing
& FILE_SHARE_READ
)==FILE_SHARE_READ
)?"FILE_SHARE_READ ":"",
555 ((sharing
& FILE_SHARE_WRITE
)==FILE_SHARE_WRITE
)?"FILE_SHARE_WRITE ":"",
556 ((sharing
& FILE_SHARE_DELETE
)==FILE_SHARE_DELETE
)?"FILE_SHARE_DELETE ":"",
557 (creation
==CREATE_NEW
)?"CREATE_NEW":
558 (creation
==CREATE_ALWAYS
)?"CREATE_ALWAYS ":
559 (creation
==OPEN_EXISTING
)?"OPEN_EXISTING ":
560 (creation
==OPEN_ALWAYS
)?"OPEN_ALWAYS ":
561 (creation
==TRUNCATE_EXISTING
)?"TRUNCATE_EXISTING ":"", attributes
);
563 /* If the name starts with '\\?\', ignore the first 4 chars. */
564 if (!strncmpW(filename
, bkslashes_with_question_markW
, 4))
566 static const WCHAR uncW
[] = {'U','N','C','\\',0};
568 if (!strncmpiW(filename
, uncW
, 4))
570 FIXME("UNC name (%s) not supported.\n", debugstr_w(filename
) );
571 SetLastError( ERROR_PATH_NOT_FOUND
);
572 return INVALID_HANDLE_VALUE
;
576 if (!strncmpW(filename
, bkslashes_with_dotW
, 4))
578 static const WCHAR pipeW
[] = {'P','I','P','E','\\',0};
579 if(!strncmpiW(filename
+ 4, pipeW
, 5))
581 TRACE("Opening a pipe: %s\n", debugstr_w(filename
));
582 ret
= FILE_OpenPipe( filename
, access
, sa
);
585 else if (isalphaW(filename
[4]) && filename
[5] == ':' && filename
[6] == '\0')
587 ret
= FILE_CreateDevice( (toupperW(filename
[4]) - 'A') | 0x20000, access
, sa
);
590 else if (!DOSFS_GetDevice( filename
))
592 ret
= DEVICE_Open( filename
+4, access
, sa
);
596 filename
+=4; /* fall into DOSFS_Device case below */
599 /* If the name still starts with '\\', it's a UNC name. */
600 if (!strncmpW(filename
, bkslashesW
, 2))
602 ret
= SMB_CreateFileW(filename
, access
, sharing
, sa
, creation
, attributes
, template );
606 /* If the name contains a DOS wild card (* or ?), do no create a file */
607 if(strchrW(filename
, '*') || strchrW(filename
, '?'))
609 SetLastError(ERROR_BAD_PATHNAME
);
610 return INVALID_HANDLE_VALUE
;
613 /* Open a console for CONIN$ or CONOUT$ */
614 if (!strcmpiW(filename
, coninW
) || !strcmpiW(filename
, conoutW
))
616 ret
= OpenConsoleW(filename
, access
, sa
, creation
);
620 if (DOSFS_GetDevice( filename
))
622 TRACE("opening device %s\n", debugstr_w(filename
) );
624 if (!(ret
= DOSFS_OpenDevice( filename
, access
, attributes
, sa
)))
626 /* Do not silence this please. It is a critical error. -MM */
627 ERR("Couldn't open device %s!\n", debugstr_w(filename
));
628 SetLastError( ERROR_FILE_NOT_FOUND
);
633 /* check for filename, don't check for last entry if creating */
634 if (!DOSFS_GetFullName( filename
,
635 (creation
== OPEN_EXISTING
) ||
636 (creation
== TRUNCATE_EXISTING
),
638 WARN("Unable to get full filename from %s (GLE %ld)\n",
639 debugstr_w(filename
), GetLastError());
640 return INVALID_HANDLE_VALUE
;
643 ret
= FILE_CreateFile( full_name
.long_name
, access
, sharing
,
644 sa
, creation
, attributes
, template,
645 DRIVE_GetFlags(full_name
.drive
) & DRIVE_FAIL_READ_ONLY
,
646 GetDriveTypeW( full_name
.short_name
) );
648 if (!ret
) ret
= INVALID_HANDLE_VALUE
;
649 TRACE("returning %p\n", ret
);
655 /*************************************************************************
656 * CreateFileA (KERNEL32.@)
658 HANDLE WINAPI
CreateFileA( LPCSTR filename
, DWORD access
, DWORD sharing
,
659 LPSECURITY_ATTRIBUTES sa
, DWORD creation
,
660 DWORD attributes
, HANDLE
template)
662 UNICODE_STRING filenameW
;
663 HANDLE ret
= INVALID_HANDLE_VALUE
;
667 SetLastError( ERROR_INVALID_PARAMETER
);
668 return INVALID_HANDLE_VALUE
;
671 if (RtlCreateUnicodeStringFromAsciiz(&filenameW
, filename
))
673 ret
= CreateFileW(filenameW
.Buffer
, access
, sharing
, sa
, creation
,
674 attributes
, template);
675 RtlFreeUnicodeString(&filenameW
);
678 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
683 /***********************************************************************
686 * Fill a file information from a struct stat.
688 static void FILE_FillInfo( struct stat
*st
, BY_HANDLE_FILE_INFORMATION
*info
)
690 if (S_ISDIR(st
->st_mode
))
691 info
->dwFileAttributes
= FILE_ATTRIBUTE_DIRECTORY
;
693 info
->dwFileAttributes
= FILE_ATTRIBUTE_ARCHIVE
;
694 if (!(st
->st_mode
& S_IWUSR
))
695 info
->dwFileAttributes
|= FILE_ATTRIBUTE_READONLY
;
697 RtlSecondsSince1970ToTime( st
->st_mtime
, (LARGE_INTEGER
*)&info
->ftCreationTime
);
698 RtlSecondsSince1970ToTime( st
->st_mtime
, (LARGE_INTEGER
*)&info
->ftLastWriteTime
);
699 RtlSecondsSince1970ToTime( st
->st_atime
, (LARGE_INTEGER
*)&info
->ftLastAccessTime
);
701 info
->dwVolumeSerialNumber
= 0; /* FIXME */
702 info
->nFileSizeHigh
= 0;
703 info
->nFileSizeLow
= 0;
704 if (!S_ISDIR(st
->st_mode
)) {
705 info
->nFileSizeHigh
= st
->st_size
>> 32;
706 info
->nFileSizeLow
= st
->st_size
& 0xffffffff;
708 info
->nNumberOfLinks
= st
->st_nlink
;
709 info
->nFileIndexHigh
= 0;
710 info
->nFileIndexLow
= st
->st_ino
;
714 /***********************************************************************
715 * get_show_dot_files_option
717 static BOOL
get_show_dot_files_option(void)
719 static const WCHAR WineW
[] = {'M','a','c','h','i','n','e','\\',
720 'S','o','f','t','w','a','r','e','\\',
721 'W','i','n','e','\\','W','i','n','e','\\',
722 'C','o','n','f','i','g','\\','W','i','n','e',0};
723 static const WCHAR ShowDotFilesW
[] = {'S','h','o','w','D','o','t','F','i','l','e','s',0};
728 OBJECT_ATTRIBUTES attr
;
729 UNICODE_STRING nameW
;
732 attr
.Length
= sizeof(attr
);
733 attr
.RootDirectory
= 0;
734 attr
.ObjectName
= &nameW
;
736 attr
.SecurityDescriptor
= NULL
;
737 attr
.SecurityQualityOfService
= NULL
;
738 RtlInitUnicodeString( &nameW
, WineW
);
740 if (!NtOpenKey( &hkey
, KEY_ALL_ACCESS
, &attr
))
742 RtlInitUnicodeString( &nameW
, ShowDotFilesW
);
743 if (!NtQueryValueKey( hkey
, &nameW
, KeyValuePartialInformation
, tmp
, sizeof(tmp
), &dummy
))
745 WCHAR
*str
= (WCHAR
*)((KEY_VALUE_PARTIAL_INFORMATION
*)tmp
)->Data
;
746 ret
= IS_OPTION_TRUE( str
[0] );
754 /***********************************************************************
757 * Stat a Unix path name. Return TRUE if OK.
759 BOOL
FILE_Stat( LPCSTR unixName
, BY_HANDLE_FILE_INFORMATION
*info
, BOOL
*is_symlink_ptr
)
765 if (lstat( unixName
, &st
) == -1)
770 is_symlink
= S_ISLNK(st
.st_mode
);
773 /* do a "real" stat to find out
774 about the type of the symlink destination */
775 if (stat( unixName
, &st
) == -1)
782 /* fill in the information we gathered so far */
783 FILE_FillInfo( &st
, info
);
785 /* and now see if this is a hidden file, based on the name */
786 p
= strrchr( unixName
, '/');
787 p
= p
? p
+ 1 : unixName
;
788 if (*p
== '.' && *(p
+1) && (*(p
+1) != '.' || *(p
+2)))
790 static int show_dot_files
= -1;
791 if (show_dot_files
== -1)
792 show_dot_files
= get_show_dot_files_option();
794 info
->dwFileAttributes
|= FILE_ATTRIBUTE_HIDDEN
;
796 if (is_symlink_ptr
) *is_symlink_ptr
= is_symlink
;
801 /***********************************************************************
802 * GetFileInformationByHandle (KERNEL32.@)
804 DWORD WINAPI
GetFileInformationByHandle( HANDLE hFile
,
805 BY_HANDLE_FILE_INFORMATION
*info
)
810 TRACE("%p\n", hFile
);
812 SERVER_START_REQ( get_file_info
)
815 if ((ret
= !wine_server_call_err( req
)))
817 /* FIXME: which file types are supported ?
818 * Serial ports (FILE_TYPE_CHAR) are not,
819 * and MSDN also says that pipes are not supported.
820 * FILE_TYPE_REMOTE seems to be supported according to
821 * MSDN q234741.txt */
822 if ((reply
->type
== FILE_TYPE_DISK
) || (reply
->type
== FILE_TYPE_REMOTE
))
824 RtlSecondsSince1970ToTime( reply
->write_time
, (LARGE_INTEGER
*)&info
->ftCreationTime
);
825 RtlSecondsSince1970ToTime( reply
->write_time
, (LARGE_INTEGER
*)&info
->ftLastWriteTime
);
826 RtlSecondsSince1970ToTime( reply
->access_time
, (LARGE_INTEGER
*)&info
->ftLastAccessTime
);
827 info
->dwFileAttributes
= reply
->attr
;
828 info
->dwVolumeSerialNumber
= reply
->serial
;
829 info
->nFileSizeHigh
= reply
->size_high
;
830 info
->nFileSizeLow
= reply
->size_low
;
831 info
->nNumberOfLinks
= reply
->links
;
832 info
->nFileIndexHigh
= reply
->index_high
;
833 info
->nFileIndexLow
= reply
->index_low
;
837 SetLastError(ERROR_NOT_SUPPORTED
);
847 /**************************************************************************
848 * GetFileAttributesW (KERNEL32.@)
850 DWORD WINAPI
GetFileAttributesW( LPCWSTR name
)
852 DOS_FULL_NAME full_name
;
853 BY_HANDLE_FILE_INFORMATION info
;
857 SetLastError( ERROR_INVALID_PARAMETER
);
860 if (!DOSFS_GetFullName( name
, TRUE
, &full_name
) )
862 if (!FILE_Stat( full_name
.long_name
, &info
, NULL
)) return -1;
863 return info
.dwFileAttributes
;
867 /**************************************************************************
868 * GetFileAttributesA (KERNEL32.@)
870 DWORD WINAPI
GetFileAttributesA( LPCSTR name
)
872 UNICODE_STRING nameW
;
873 DWORD ret
= (DWORD
)-1;
877 SetLastError( ERROR_INVALID_PARAMETER
);
881 if (RtlCreateUnicodeStringFromAsciiz(&nameW
, name
))
883 ret
= GetFileAttributesW(nameW
.Buffer
);
884 RtlFreeUnicodeString(&nameW
);
887 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
892 /**************************************************************************
893 * SetFileAttributesW (KERNEL32.@)
895 BOOL WINAPI
SetFileAttributesW(LPCWSTR lpFileName
, DWORD attributes
)
898 DOS_FULL_NAME full_name
;
902 SetLastError( ERROR_INVALID_PARAMETER
);
906 TRACE("(%s,%lx)\n", debugstr_w(lpFileName
), attributes
);
908 if (!DOSFS_GetFullName( lpFileName
, TRUE
, &full_name
))
911 if(stat(full_name
.long_name
,&buf
)==-1)
916 if (attributes
& FILE_ATTRIBUTE_READONLY
)
918 if(S_ISDIR(buf
.st_mode
))
920 WARN("FILE_ATTRIBUTE_READONLY ignored for directory.\n");
922 buf
.st_mode
&= ~0222; /* octal!, clear write permission bits */
923 attributes
&= ~FILE_ATTRIBUTE_READONLY
;
927 /* add write permission */
928 buf
.st_mode
|= (0600 | ((buf
.st_mode
& 044) >> 1)) & (~FILE_umask
);
930 if (attributes
& FILE_ATTRIBUTE_DIRECTORY
)
932 if (!S_ISDIR(buf
.st_mode
))
933 FIXME("SetFileAttributes expected the file %s to be a directory\n",
934 debugstr_w(lpFileName
));
935 attributes
&= ~FILE_ATTRIBUTE_DIRECTORY
;
937 attributes
&= ~(FILE_ATTRIBUTE_NORMAL
|FILE_ATTRIBUTE_ARCHIVE
|FILE_ATTRIBUTE_HIDDEN
|FILE_ATTRIBUTE_SYSTEM
);
939 FIXME("(%s):%lx attribute(s) not implemented.\n", debugstr_w(lpFileName
), attributes
);
940 if (-1==chmod(full_name
.long_name
,buf
.st_mode
))
942 if (GetDriveTypeW(lpFileName
) == DRIVE_CDROM
)
944 SetLastError( ERROR_ACCESS_DENIED
);
949 * FIXME: We don't return FALSE here because of differences between
950 * Linux and Windows privileges. Under Linux only the owner of
951 * the file is allowed to change file attributes. Under Windows,
952 * applications expect that if you can write to a file, you can also
953 * change its attributes (see GENERIC_WRITE). We could try to be
954 * clever here but that would break multi-user installations where
955 * users share read-only DLLs. This is because some installers like
956 * to change attributes of already installed DLLs.
958 FIXME("Couldn't set file attributes for existing file \"%s\".\n"
959 "Check permissions or set VFAT \"quiet\" mount flag\n", full_name
.long_name
);
965 /**************************************************************************
966 * SetFileAttributesA (KERNEL32.@)
968 BOOL WINAPI
SetFileAttributesA(LPCSTR lpFileName
, DWORD attributes
)
970 UNICODE_STRING filenameW
;
975 SetLastError( ERROR_INVALID_PARAMETER
);
979 if (RtlCreateUnicodeStringFromAsciiz(&filenameW
, lpFileName
))
981 ret
= SetFileAttributesW(filenameW
.Buffer
, attributes
);
982 RtlFreeUnicodeString(&filenameW
);
985 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
990 /***********************************************************************
991 * GetFileTime (KERNEL32.@)
993 BOOL WINAPI
GetFileTime( HANDLE hFile
, FILETIME
*lpCreationTime
,
994 FILETIME
*lpLastAccessTime
,
995 FILETIME
*lpLastWriteTime
)
997 BY_HANDLE_FILE_INFORMATION info
;
998 if (!GetFileInformationByHandle( hFile
, &info
)) return FALSE
;
999 if (lpCreationTime
) *lpCreationTime
= info
.ftCreationTime
;
1000 if (lpLastAccessTime
) *lpLastAccessTime
= info
.ftLastAccessTime
;
1001 if (lpLastWriteTime
) *lpLastWriteTime
= info
.ftLastWriteTime
;
1006 /***********************************************************************
1007 * FILE_GetTempFileName : utility for GetTempFileName
1009 static UINT
FILE_GetTempFileName( LPCWSTR path
, LPCWSTR prefix
, UINT unique
,
1012 static UINT unique_temp
;
1013 DOS_FULL_NAME full_name
;
1019 if ( !path
|| !prefix
|| !buffer
)
1021 SetLastError( ERROR_INVALID_PARAMETER
);
1025 if (!unique_temp
) unique_temp
= time(NULL
) & 0xffff;
1026 num
= unique
? (unique
& 0xffff) : (unique_temp
++ & 0xffff);
1028 strcpyW( buffer
, path
);
1029 p
= buffer
+ strlenW(buffer
);
1031 /* add a \, if there isn't one and path is more than just the drive letter ... */
1032 if ( !((strlenW(buffer
) == 2) && (buffer
[1] == ':'))
1033 && ((p
== buffer
) || (p
[-1] != '\\'))) *p
++ = '\\';
1035 for (i
= 3; (i
> 0) && (*prefix
); i
--) *p
++ = *prefix
++;
1037 sprintf( buf
, "%04x.tmp", num
);
1038 MultiByteToWideChar(CP_ACP
, 0, buf
, -1, p
, 20);
1040 /* Now try to create it */
1046 HANDLE handle
= CreateFileW( buffer
, GENERIC_WRITE
, 0, NULL
,
1047 CREATE_NEW
, FILE_ATTRIBUTE_NORMAL
, 0 );
1048 if (handle
!= INVALID_HANDLE_VALUE
)
1049 { /* We created it */
1050 TRACE("created %s\n", debugstr_w(buffer
) );
1051 CloseHandle( handle
);
1054 if (GetLastError() != ERROR_FILE_EXISTS
&&
1055 GetLastError() != ERROR_SHARING_VIOLATION
)
1056 break; /* No need to go on */
1058 sprintf( buf
, "%04x.tmp", num
);
1059 MultiByteToWideChar(CP_ACP
, 0, buf
, -1, p
, 20);
1060 } while (num
!= (unique
& 0xffff));
1063 /* Get the full path name */
1065 if (DOSFS_GetFullName( buffer
, FALSE
, &full_name
))
1068 /* Check if we have write access in the directory */
1069 if ((slash
= strrchr( full_name
.long_name
, '/' ))) *slash
= '\0';
1070 if (access( full_name
.long_name
, W_OK
) == -1)
1071 WARN("returns %s, which doesn't seem to be writeable.\n",
1072 debugstr_w(buffer
) );
1074 TRACE("returning %s\n", debugstr_w(buffer
) );
1075 return unique
? unique
: num
;
1079 /***********************************************************************
1080 * GetTempFileNameA (KERNEL32.@)
1082 UINT WINAPI
GetTempFileNameA( LPCSTR path
, LPCSTR prefix
, UINT unique
,
1085 UNICODE_STRING pathW
, prefixW
;
1086 WCHAR bufferW
[MAX_PATH
];
1089 if ( !path
|| !prefix
|| !buffer
)
1091 SetLastError( ERROR_INVALID_PARAMETER
);
1095 RtlCreateUnicodeStringFromAsciiz(&pathW
, path
);
1096 RtlCreateUnicodeStringFromAsciiz(&prefixW
, prefix
);
1098 ret
= GetTempFileNameW(pathW
.Buffer
, prefixW
.Buffer
, unique
, bufferW
);
1100 WideCharToMultiByte(CP_ACP
, 0, bufferW
, -1, buffer
, MAX_PATH
, NULL
, NULL
);
1102 RtlFreeUnicodeString(&pathW
);
1103 RtlFreeUnicodeString(&prefixW
);
1107 /***********************************************************************
1108 * GetTempFileNameW (KERNEL32.@)
1110 UINT WINAPI
GetTempFileNameW( LPCWSTR path
, LPCWSTR prefix
, UINT unique
,
1113 return FILE_GetTempFileName( path
, prefix
, unique
, buffer
);
1117 /***********************************************************************
1120 * Implementation of OpenFile16() and OpenFile32().
1122 static HFILE
FILE_DoOpenFile( LPCSTR name
, OFSTRUCT
*ofs
, UINT mode
, BOOL win32
)
1127 WORD filedatetime
[2];
1128 DOS_FULL_NAME full_name
;
1129 DWORD access
, sharing
;
1131 WCHAR buffer
[MAX_PATH
];
1134 if (!ofs
) return HFILE_ERROR
;
1136 TRACE("%s %s %s %s%s%s%s%s%s%s%s%s\n",name
,
1137 ((mode
& 0x3 )==OF_READ
)?"OF_READ":
1138 ((mode
& 0x3 )==OF_WRITE
)?"OF_WRITE":
1139 ((mode
& 0x3 )==OF_READWRITE
)?"OF_READWRITE":"unknown",
1140 ((mode
& 0x70 )==OF_SHARE_COMPAT
)?"OF_SHARE_COMPAT":
1141 ((mode
& 0x70 )==OF_SHARE_DENY_NONE
)?"OF_SHARE_DENY_NONE":
1142 ((mode
& 0x70 )==OF_SHARE_DENY_READ
)?"OF_SHARE_DENY_READ":
1143 ((mode
& 0x70 )==OF_SHARE_DENY_WRITE
)?"OF_SHARE_DENY_WRITE":
1144 ((mode
& 0x70 )==OF_SHARE_EXCLUSIVE
)?"OF_SHARE_EXCLUSIVE":"unknown",
1145 ((mode
& OF_PARSE
)==OF_PARSE
)?"OF_PARSE ":"",
1146 ((mode
& OF_DELETE
)==OF_DELETE
)?"OF_DELETE ":"",
1147 ((mode
& OF_VERIFY
)==OF_VERIFY
)?"OF_VERIFY ":"",
1148 ((mode
& OF_SEARCH
)==OF_SEARCH
)?"OF_SEARCH ":"",
1149 ((mode
& OF_CANCEL
)==OF_CANCEL
)?"OF_CANCEL ":"",
1150 ((mode
& OF_CREATE
)==OF_CREATE
)?"OF_CREATE ":"",
1151 ((mode
& OF_PROMPT
)==OF_PROMPT
)?"OF_PROMPT ":"",
1152 ((mode
& OF_EXIST
)==OF_EXIST
)?"OF_EXIST ":"",
1153 ((mode
& OF_REOPEN
)==OF_REOPEN
)?"OF_REOPEN ":""
1157 ofs
->cBytes
= sizeof(OFSTRUCT
);
1159 if (mode
& OF_REOPEN
) name
= ofs
->szPathName
;
1162 ERR("called with `name' set to NULL ! Please debug.\n");
1166 TRACE("%s %04x\n", name
, mode
);
1168 /* the watcom 10.6 IDE relies on a valid path returned in ofs->szPathName
1169 Are there any cases where getting the path here is wrong?
1170 Uwe Bonnes 1997 Apr 2 */
1171 if (!GetFullPathNameA( name
, sizeof(ofs
->szPathName
),
1172 ofs
->szPathName
, NULL
)) goto error
;
1173 FILE_ConvertOFMode( mode
, &access
, &sharing
);
1175 /* OF_PARSE simply fills the structure */
1177 if (mode
& OF_PARSE
)
1179 ofs
->fFixedDisk
= (GetDriveType16( ofs
->szPathName
[0]-'A' )
1180 != DRIVE_REMOVABLE
);
1181 TRACE("(%s): OF_PARSE, res = '%s'\n",
1182 name
, ofs
->szPathName
);
1186 /* OF_CREATE is completely different from all other options, so
1189 if (mode
& OF_CREATE
)
1191 if ((handle
= CreateFileA( name
, GENERIC_READ
| GENERIC_WRITE
,
1192 sharing
, NULL
, CREATE_ALWAYS
,
1193 FILE_ATTRIBUTE_NORMAL
, 0 ))== INVALID_HANDLE_VALUE
)
1198 MultiByteToWideChar(CP_ACP
, 0, name
, -1, buffer
, MAX_PATH
);
1201 /* If OF_SEARCH is set, ignore the given path */
1203 if ((mode
& OF_SEARCH
) && !(mode
& OF_REOPEN
))
1205 /* First try the file name as is */
1206 if (DOSFS_GetFullName( nameW
, TRUE
, &full_name
)) goto found
;
1207 /* Now remove the path */
1208 if (nameW
[0] && (nameW
[1] == ':')) nameW
+= 2;
1209 if ((p
= strrchrW( nameW
, '\\' ))) nameW
= p
+ 1;
1210 if ((p
= strrchrW( nameW
, '/' ))) nameW
= p
+ 1;
1211 if (!nameW
[0]) goto not_found
;
1214 /* Now look for the file */
1216 if (!DIR_SearchPath( NULL
, nameW
, NULL
, &full_name
, win32
)) goto not_found
;
1219 TRACE("found %s = %s\n",
1220 full_name
.long_name
, debugstr_w(full_name
.short_name
) );
1221 WideCharToMultiByte(CP_ACP
, 0, full_name
.short_name
, -1,
1222 ofs
->szPathName
, sizeof(ofs
->szPathName
), NULL
, NULL
);
1224 if (mode
& OF_DELETE
)
1226 handle
= FILE_CreateFile( full_name
.long_name
, GENERIC_READ
|GENERIC_WRITE
, 0,
1227 NULL
, OPEN_EXISTING
, 0, 0, TRUE
,
1228 GetDriveTypeW( full_name
.short_name
) );
1229 if (!handle
) goto error
;
1230 CloseHandle( handle
);
1231 if (unlink( full_name
.long_name
) == -1) goto not_found
;
1232 TRACE("(%s): OF_DELETE return = OK\n", name
);
1236 handle
= FILE_CreateFile( full_name
.long_name
, access
, sharing
,
1237 NULL
, OPEN_EXISTING
, 0, 0,
1238 DRIVE_GetFlags(full_name
.drive
) & DRIVE_FAIL_READ_ONLY
,
1239 GetDriveTypeW( full_name
.short_name
) );
1240 if (!handle
) goto not_found
;
1242 GetFileTime( handle
, NULL
, NULL
, &filetime
);
1243 FileTimeToDosDateTime( &filetime
, &filedatetime
[0], &filedatetime
[1] );
1244 if ((mode
& OF_VERIFY
) && (mode
& OF_REOPEN
))
1246 if (ofs
->Reserved1
!= filedatetime
[0] || ofs
->Reserved2
!= filedatetime
[1] )
1248 CloseHandle( handle
);
1249 WARN("(%s): OF_VERIFY failed\n", name
);
1250 /* FIXME: what error here? */
1251 SetLastError( ERROR_FILE_NOT_FOUND
);
1255 ofs
->Reserved1
= filedatetime
[0];
1256 ofs
->Reserved2
= filedatetime
[1];
1258 success
: /* We get here if the open was successful */
1259 TRACE("(%s): OK, return = %p\n", name
, handle
);
1262 hFileRet
= (HFILE
)handle
;
1263 if (mode
& OF_EXIST
) /* Return the handle, but close it first */
1264 CloseHandle( handle
);
1268 hFileRet
= Win32HandleToDosFileHandle( handle
);
1269 if (hFileRet
== HFILE_ERROR16
) goto error
;
1270 if (mode
& OF_EXIST
) /* Return the handle, but close it first */
1271 _lclose16( hFileRet
);
1275 not_found
: /* We get here if the file does not exist */
1276 WARN("'%s' not found or sharing violation\n", name
);
1277 SetLastError( ERROR_FILE_NOT_FOUND
);
1280 error
: /* We get here if there was an error opening the file */
1281 ofs
->nErrCode
= GetLastError();
1282 WARN("(%s): return = HFILE_ERROR error= %d\n",
1283 name
,ofs
->nErrCode
);
1288 /***********************************************************************
1289 * OpenFile (KERNEL.74)
1290 * OpenFileEx (KERNEL.360)
1292 HFILE16 WINAPI
OpenFile16( LPCSTR name
, OFSTRUCT
*ofs
, UINT16 mode
)
1294 return FILE_DoOpenFile( name
, ofs
, mode
, FALSE
);
1298 /***********************************************************************
1299 * OpenFile (KERNEL32.@)
1301 HFILE WINAPI
OpenFile( LPCSTR name
, OFSTRUCT
*ofs
, UINT mode
)
1303 return FILE_DoOpenFile( name
, ofs
, mode
, TRUE
);
1307 /***********************************************************************
1308 * FILE_InitProcessDosHandles
1310 * Allocates the default DOS handles for a process. Called either by
1311 * Win32HandleToDosFileHandle below or by the DOSVM stuff.
1313 static void FILE_InitProcessDosHandles( void )
1315 HANDLE cp
= GetCurrentProcess();
1316 DuplicateHandle(cp
, GetStdHandle(STD_INPUT_HANDLE
), cp
, &dos_handles
[0],
1317 0, TRUE
, DUPLICATE_SAME_ACCESS
);
1318 DuplicateHandle(cp
, GetStdHandle(STD_OUTPUT_HANDLE
), cp
, &dos_handles
[1],
1319 0, TRUE
, DUPLICATE_SAME_ACCESS
);
1320 DuplicateHandle(cp
, GetStdHandle(STD_ERROR_HANDLE
), cp
, &dos_handles
[2],
1321 0, TRUE
, DUPLICATE_SAME_ACCESS
);
1322 DuplicateHandle(cp
, GetStdHandle(STD_ERROR_HANDLE
), cp
, &dos_handles
[3],
1323 0, TRUE
, DUPLICATE_SAME_ACCESS
);
1324 DuplicateHandle(cp
, GetStdHandle(STD_ERROR_HANDLE
), cp
, &dos_handles
[4],
1325 0, TRUE
, DUPLICATE_SAME_ACCESS
);
1328 /***********************************************************************
1329 * Win32HandleToDosFileHandle (KERNEL32.21)
1331 * Allocate a DOS handle for a Win32 handle. The Win32 handle is no
1332 * longer valid after this function (even on failure).
1334 * Note: this is not exactly right, since on Win95 the Win32 handles
1335 * are on top of DOS handles and we do it the other way
1336 * around. Should be good enough though.
1338 HFILE WINAPI
Win32HandleToDosFileHandle( HANDLE handle
)
1342 if (!handle
|| (handle
== INVALID_HANDLE_VALUE
))
1345 for (i
= 5; i
< DOS_TABLE_SIZE
; i
++)
1346 if (!dos_handles
[i
])
1348 dos_handles
[i
] = handle
;
1349 TRACE("Got %d for h32 %p\n", i
, handle
);
1352 CloseHandle( handle
);
1353 SetLastError( ERROR_TOO_MANY_OPEN_FILES
);
1358 /***********************************************************************
1359 * DosFileHandleToWin32Handle (KERNEL32.20)
1361 * Return the Win32 handle for a DOS handle.
1363 * Note: this is not exactly right, since on Win95 the Win32 handles
1364 * are on top of DOS handles and we do it the other way
1365 * around. Should be good enough though.
1367 HANDLE WINAPI
DosFileHandleToWin32Handle( HFILE handle
)
1369 HFILE16 hfile
= (HFILE16
)handle
;
1370 if (hfile
< 5 && !dos_handles
[hfile
]) FILE_InitProcessDosHandles();
1371 if ((hfile
>= DOS_TABLE_SIZE
) || !dos_handles
[hfile
])
1373 SetLastError( ERROR_INVALID_HANDLE
);
1374 return INVALID_HANDLE_VALUE
;
1376 return dos_handles
[hfile
];
1380 /***********************************************************************
1381 * DisposeLZ32Handle (KERNEL32.22)
1383 * Note: this is not entirely correct, we should only close the
1384 * 32-bit handle and not the 16-bit one, but we cannot do
1385 * this because of the way our DOS handles are implemented.
1386 * It shouldn't break anything though.
1388 void WINAPI
DisposeLZ32Handle( HANDLE handle
)
1392 if (!handle
|| (handle
== INVALID_HANDLE_VALUE
)) return;
1394 for (i
= 5; i
< DOS_TABLE_SIZE
; i
++)
1395 if (dos_handles
[i
] == handle
)
1398 CloseHandle( handle
);
1404 /***********************************************************************
1407 * dup2() function for DOS handles.
1409 HFILE16
FILE_Dup2( HFILE16 hFile1
, HFILE16 hFile2
)
1413 if (hFile1
< 5 && !dos_handles
[hFile1
]) FILE_InitProcessDosHandles();
1415 if ((hFile1
>= DOS_TABLE_SIZE
) || (hFile2
>= DOS_TABLE_SIZE
) || !dos_handles
[hFile1
])
1417 SetLastError( ERROR_INVALID_HANDLE
);
1418 return HFILE_ERROR16
;
1420 if (!DuplicateHandle( GetCurrentProcess(), dos_handles
[hFile1
],
1421 GetCurrentProcess(), &new_handle
,
1422 0, FALSE
, DUPLICATE_SAME_ACCESS
))
1423 return HFILE_ERROR16
;
1424 if (dos_handles
[hFile2
]) CloseHandle( dos_handles
[hFile2
] );
1425 dos_handles
[hFile2
] = new_handle
;
1430 /***********************************************************************
1431 * _lclose (KERNEL.81)
1433 HFILE16 WINAPI
_lclose16( HFILE16 hFile
)
1435 if ((hFile
>= DOS_TABLE_SIZE
) || !dos_handles
[hFile
])
1437 SetLastError( ERROR_INVALID_HANDLE
);
1438 return HFILE_ERROR16
;
1440 TRACE("%d (handle32=%p)\n", hFile
, dos_handles
[hFile
] );
1441 CloseHandle( dos_handles
[hFile
] );
1442 dos_handles
[hFile
] = 0;
1447 /******************************************************************
1448 * FILE_ReadWriteApc (internal)
1452 static void WINAPI
FILE_ReadWriteApc(void* apc_user
, PIO_STATUS_BLOCK io_status
, ULONG len
)
1454 LPOVERLAPPED_COMPLETION_ROUTINE cr
= (LPOVERLAPPED_COMPLETION_ROUTINE
)apc_user
;
1456 cr(RtlNtStatusToDosError(io_status
->u
.Status
), len
, (LPOVERLAPPED
)io_status
);
1459 /***********************************************************************
1460 * ReadFileEx (KERNEL32.@)
1462 BOOL WINAPI
ReadFileEx(HANDLE hFile
, LPVOID buffer
, DWORD bytesToRead
,
1463 LPOVERLAPPED overlapped
,
1464 LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine
)
1466 LARGE_INTEGER offset
;
1468 PIO_STATUS_BLOCK io_status
;
1472 SetLastError(ERROR_INVALID_PARAMETER
);
1476 offset
.s
.LowPart
= overlapped
->Offset
;
1477 offset
.s
.HighPart
= overlapped
->OffsetHigh
;
1478 io_status
= (PIO_STATUS_BLOCK
)overlapped
;
1479 io_status
->u
.Status
= STATUS_PENDING
;
1481 status
= NtReadFile(hFile
, NULL
, FILE_ReadWriteApc
, lpCompletionRoutine
,
1482 io_status
, buffer
, bytesToRead
, &offset
, NULL
);
1486 SetLastError( RtlNtStatusToDosError(status
) );
1492 /***********************************************************************
1493 * ReadFile (KERNEL32.@)
1495 BOOL WINAPI
ReadFile( HANDLE hFile
, LPVOID buffer
, DWORD bytesToRead
,
1496 LPDWORD bytesRead
, LPOVERLAPPED overlapped
)
1498 LARGE_INTEGER offset
;
1499 PLARGE_INTEGER poffset
= NULL
;
1500 IO_STATUS_BLOCK iosb
;
1501 PIO_STATUS_BLOCK io_status
= &iosb
;
1505 TRACE("%p %p %ld %p %p\n", hFile
, buffer
, bytesToRead
,
1506 bytesRead
, overlapped
);
1508 if (bytesRead
) *bytesRead
= 0; /* Do this before anything else */
1509 if (!bytesToRead
) return TRUE
;
1511 if (IsBadReadPtr(buffer
, bytesToRead
))
1513 SetLastError(ERROR_WRITE_FAULT
); /* FIXME */
1516 if (is_console_handle(hFile
))
1517 return FILE_ReadConsole(hFile
, buffer
, bytesToRead
, bytesRead
, NULL
);
1519 if (overlapped
!= NULL
)
1521 offset
.s
.LowPart
= overlapped
->Offset
;
1522 offset
.s
.HighPart
= overlapped
->OffsetHigh
;
1524 hEvent
= overlapped
->hEvent
;
1525 io_status
= (PIO_STATUS_BLOCK
)overlapped
;
1527 io_status
->u
.Status
= STATUS_PENDING
;
1528 io_status
->Information
= 0;
1530 status
= NtReadFile(hFile
, hEvent
, NULL
, NULL
, io_status
, buffer
, bytesToRead
, poffset
, NULL
);
1532 if (status
!= STATUS_PENDING
&& bytesRead
)
1533 *bytesRead
= io_status
->Information
;
1535 if (status
&& status
!= STATUS_END_OF_FILE
)
1537 SetLastError( RtlNtStatusToDosError(status
) );
1544 /***********************************************************************
1545 * WriteFileEx (KERNEL32.@)
1547 BOOL WINAPI
WriteFileEx(HANDLE hFile
, LPCVOID buffer
, DWORD bytesToWrite
,
1548 LPOVERLAPPED overlapped
,
1549 LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine
)
1551 LARGE_INTEGER offset
;
1553 PIO_STATUS_BLOCK io_status
;
1555 TRACE("%p %p %ld %p %p\n",
1556 hFile
, buffer
, bytesToWrite
, overlapped
, lpCompletionRoutine
);
1558 if (overlapped
== NULL
)
1560 SetLastError(ERROR_INVALID_PARAMETER
);
1563 offset
.s
.LowPart
= overlapped
->Offset
;
1564 offset
.s
.HighPart
= overlapped
->OffsetHigh
;
1566 io_status
= (PIO_STATUS_BLOCK
)overlapped
;
1567 io_status
->u
.Status
= STATUS_PENDING
;
1569 status
= NtWriteFile(hFile
, NULL
, FILE_ReadWriteApc
, lpCompletionRoutine
,
1570 io_status
, buffer
, bytesToWrite
, &offset
, NULL
);
1572 if (status
) SetLastError( RtlNtStatusToDosError(status
) );
1576 /***********************************************************************
1577 * WriteFile (KERNEL32.@)
1579 BOOL WINAPI
WriteFile( HANDLE hFile
, LPCVOID buffer
, DWORD bytesToWrite
,
1580 LPDWORD bytesWritten
, LPOVERLAPPED overlapped
)
1582 HANDLE hEvent
= NULL
;
1583 LARGE_INTEGER offset
;
1584 PLARGE_INTEGER poffset
= NULL
;
1586 IO_STATUS_BLOCK iosb
;
1587 PIO_STATUS_BLOCK piosb
= &iosb
;
1589 TRACE("%p %p %ld %p %p\n",
1590 hFile
, buffer
, bytesToWrite
, bytesWritten
, overlapped
);
1592 if (is_console_handle(hFile
))
1593 return FILE_WriteConsole(hFile
, buffer
, bytesToWrite
, bytesWritten
, NULL
);
1595 if (IsBadReadPtr(buffer
, bytesToWrite
))
1597 SetLastError(ERROR_READ_FAULT
); /* FIXME */
1603 offset
.s
.LowPart
= overlapped
->Offset
;
1604 offset
.s
.HighPart
= overlapped
->OffsetHigh
;
1606 hEvent
= overlapped
->hEvent
;
1607 piosb
= (PIO_STATUS_BLOCK
)overlapped
;
1609 piosb
->u
.Status
= STATUS_PENDING
;
1610 piosb
->Information
= 0;
1612 status
= NtWriteFile(hFile
, hEvent
, NULL
, NULL
, piosb
,
1613 buffer
, bytesToWrite
, poffset
, NULL
);
1616 SetLastError( RtlNtStatusToDosError(status
) );
1619 if (bytesWritten
) *bytesWritten
= piosb
->Information
;
1625 /***********************************************************************
1626 * SetFilePointer (KERNEL32.@)
1628 DWORD WINAPI
SetFilePointer( HANDLE hFile
, LONG distance
, LONG
*highword
,
1631 DWORD ret
= INVALID_SET_FILE_POINTER
;
1633 TRACE("handle %p offset %ld high %ld origin %ld\n",
1634 hFile
, distance
, highword
?*highword
:0, method
);
1636 SERVER_START_REQ( set_file_pointer
)
1638 req
->handle
= hFile
;
1639 req
->low
= distance
;
1640 req
->high
= highword
? *highword
: (distance
>= 0) ? 0 : -1;
1641 /* FIXME: assumes 1:1 mapping between Windows and Unix seek constants */
1642 req
->whence
= method
;
1644 if (!wine_server_call_err( req
))
1646 ret
= reply
->new_low
;
1647 if (highword
) *highword
= reply
->new_high
;
1655 /*************************************************************************
1656 * SetHandleCount (KERNEL32.@)
1658 UINT WINAPI
SetHandleCount( UINT count
)
1660 return min( 256, count
);
1664 /**************************************************************************
1665 * SetEndOfFile (KERNEL32.@)
1667 BOOL WINAPI
SetEndOfFile( HANDLE hFile
)
1670 SERVER_START_REQ( truncate_file
)
1672 req
->handle
= hFile
;
1673 ret
= !wine_server_call_err( req
);
1680 /***********************************************************************
1681 * DeleteFileW (KERNEL32.@)
1683 BOOL WINAPI
DeleteFileW( LPCWSTR path
)
1685 DOS_FULL_NAME full_name
;
1688 TRACE("%s\n", debugstr_w(path
) );
1689 if (!path
|| !*path
)
1691 SetLastError(ERROR_PATH_NOT_FOUND
);
1694 if (DOSFS_GetDevice( path
))
1696 WARN("cannot remove DOS device %s!\n", debugstr_w(path
));
1697 SetLastError( ERROR_FILE_NOT_FOUND
);
1701 if (!DOSFS_GetFullName( path
, TRUE
, &full_name
)) return FALSE
;
1703 /* check if we are allowed to delete the source */
1704 hFile
= FILE_CreateFile( full_name
.long_name
, GENERIC_READ
|GENERIC_WRITE
, 0,
1705 NULL
, OPEN_EXISTING
, 0, 0, TRUE
,
1706 GetDriveTypeW( full_name
.short_name
) );
1707 if (!hFile
) return FALSE
;
1709 if (unlink( full_name
.long_name
) == -1)
1720 /***********************************************************************
1721 * DeleteFileA (KERNEL32.@)
1723 BOOL WINAPI
DeleteFileA( LPCSTR path
)
1725 UNICODE_STRING pathW
;
1730 SetLastError(ERROR_INVALID_PARAMETER
);
1734 if (RtlCreateUnicodeStringFromAsciiz(&pathW
, path
))
1736 ret
= DeleteFileW(pathW
.Buffer
);
1737 RtlFreeUnicodeString(&pathW
);
1740 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
1745 /***********************************************************************
1746 * GetFileType (KERNEL32.@)
1748 DWORD WINAPI
GetFileType( HANDLE hFile
)
1750 DWORD ret
= FILE_TYPE_UNKNOWN
;
1752 if (is_console_handle( hFile
))
1753 return FILE_TYPE_CHAR
;
1755 SERVER_START_REQ( get_file_info
)
1757 req
->handle
= hFile
;
1758 if (!wine_server_call_err( req
)) ret
= reply
->type
;
1765 /* check if a file name is for an executable file (.exe or .com) */
1766 inline static BOOL
is_executable( const char *name
)
1768 int len
= strlen(name
);
1770 if (len
< 4) return FALSE
;
1771 return (!strcasecmp( name
+ len
- 4, ".exe" ) ||
1772 !strcasecmp( name
+ len
- 4, ".com" ));
1776 /***********************************************************************
1777 * FILE_AddBootRenameEntry
1779 * Adds an entry to the registry that is loaded when windows boots and
1780 * checks if there are some files to be removed or renamed/moved.
1781 * <fn1> has to be valid and <fn2> may be NULL. If both pointers are
1782 * non-NULL then the file is moved, otherwise it is deleted. The
1783 * entry of the registrykey is always appended with two zero
1784 * terminated strings. If <fn2> is NULL then the second entry is
1785 * simply a single 0-byte. Otherwise the second filename goes
1786 * there. The entries are prepended with \??\ before the path and the
1787 * second filename gets also a '!' as the first character if
1788 * MOVEFILE_REPLACE_EXISTING is set. After the final string another
1789 * 0-byte follows to indicate the end of the strings.
1791 * \??\D:\test\file1[0]
1792 * !\??\D:\test\file1_renamed[0]
1793 * \??\D:\Test|delete[0]
1794 * [0] <- file is to be deleted, second string empty
1795 * \??\D:\test\file2[0]
1796 * !\??\D:\test\file2_renamed[0]
1797 * [0] <- indicates end of strings
1800 * \??\D:\test\file1[0]
1801 * !\??\D:\test\file1_renamed[0]
1802 * \??\D:\Test|delete[0]
1803 * [0] <- file is to be deleted, second string empty
1804 * [0] <- indicates end of strings
1807 static BOOL
FILE_AddBootRenameEntry( LPCWSTR fn1
, LPCWSTR fn2
, DWORD flags
)
1809 static const WCHAR PreString
[] = {'\\','?','?','\\',0};
1810 static const WCHAR ValueName
[] = {'P','e','n','d','i','n','g',
1811 'F','i','l','e','R','e','n','a','m','e',
1812 'O','p','e','r','a','t','i','o','n','s',0};
1813 static const WCHAR SessionW
[] = {'M','a','c','h','i','n','e','\\',
1814 'S','y','s','t','e','m','\\',
1815 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
1816 'C','o','n','t','r','o','l','\\',
1817 'S','e','s','s','i','o','n',' ','M','a','n','a','g','e','r',0};
1818 static const int info_size
= FIELD_OFFSET( KEY_VALUE_PARTIAL_INFORMATION
, Data
);
1820 OBJECT_ATTRIBUTES attr
;
1821 UNICODE_STRING nameW
;
1822 KEY_VALUE_PARTIAL_INFORMATION
*info
;
1825 DWORD len0
, len1
, len2
;
1827 BYTE
*Buffer
= NULL
;
1830 attr
.Length
= sizeof(attr
);
1831 attr
.RootDirectory
= 0;
1832 attr
.ObjectName
= &nameW
;
1833 attr
.Attributes
= 0;
1834 attr
.SecurityDescriptor
= NULL
;
1835 attr
.SecurityQualityOfService
= NULL
;
1836 RtlInitUnicodeString( &nameW
, SessionW
);
1838 if (NtCreateKey( &Reboot
, KEY_ALL_ACCESS
, &attr
, 0, NULL
, 0, NULL
) != STATUS_SUCCESS
)
1840 WARN("Error creating key for reboot managment [%s]\n",
1841 "SYSTEM\\CurrentControlSet\\Control\\Session Manager");
1845 len0
= strlenW(PreString
);
1846 len1
= strlenW(fn1
) + len0
+ 1;
1849 len2
= strlenW(fn2
) + len0
+ 1;
1850 if (flags
& MOVEFILE_REPLACE_EXISTING
) len2
++; /* Plus 1 because of the leading '!' */
1852 else len2
= 1; /* minimum is the 0 characters for the empty second string */
1854 /* convert characters to bytes */
1855 len0
*= sizeof(WCHAR
);
1856 len1
*= sizeof(WCHAR
);
1857 len2
*= sizeof(WCHAR
);
1859 RtlInitUnicodeString( &nameW
, ValueName
);
1861 /* First we check if the key exists and if so how many bytes it already contains. */
1862 if (NtQueryValueKey( Reboot
, &nameW
, KeyValuePartialInformation
,
1863 NULL
, 0, &DataSize
) == STATUS_BUFFER_OVERFLOW
)
1865 if (!(Buffer
= HeapAlloc( GetProcessHeap(), 0, DataSize
+ len1
+ len2
+ sizeof(WCHAR
) )))
1867 if (NtQueryValueKey( Reboot
, &nameW
, KeyValuePartialInformation
,
1868 Buffer
, DataSize
, &DataSize
)) goto Quit
;
1869 info
= (KEY_VALUE_PARTIAL_INFORMATION
*)Buffer
;
1870 if (info
->Type
!= REG_MULTI_SZ
) goto Quit
;
1871 if (DataSize
> sizeof(info
)) DataSize
-= sizeof(WCHAR
); /* remove terminating null (will be added back later) */
1875 DataSize
= info_size
;
1876 if (!(Buffer
= HeapAlloc( GetProcessHeap(), 0, DataSize
+ len1
+ len2
+ sizeof(WCHAR
) )))
1880 p
= (WCHAR
*)(Buffer
+ DataSize
);
1881 strcpyW( p
, PreString
);
1886 p
= (WCHAR
*)(Buffer
+ DataSize
);
1887 if (flags
& MOVEFILE_REPLACE_EXISTING
)
1889 strcpyW( p
, PreString
);
1895 p
= (WCHAR
*)(Buffer
+ DataSize
);
1897 DataSize
+= sizeof(WCHAR
);
1900 /* add final null */
1901 p
= (WCHAR
*)(Buffer
+ DataSize
);
1903 DataSize
+= sizeof(WCHAR
);
1905 rc
= !NtSetValueKey(Reboot
, &nameW
, 0, REG_MULTI_SZ
, Buffer
+ info_size
, DataSize
- info_size
);
1908 if (Reboot
) NtClose(Reboot
);
1909 if (Buffer
) HeapFree( GetProcessHeap(), 0, Buffer
);
1914 /**************************************************************************
1915 * MoveFileExW (KERNEL32.@)
1917 BOOL WINAPI
MoveFileExW( LPCWSTR fn1
, LPCWSTR fn2
, DWORD flag
)
1919 DOS_FULL_NAME full_name1
, full_name2
;
1921 DWORD attr
= INVALID_FILE_ATTRIBUTES
;
1923 TRACE("(%s,%s,%04lx)\n", debugstr_w(fn1
), debugstr_w(fn2
), flag
);
1925 /* FIXME: <Gerhard W. Gruber>sparhawk@gmx.at
1926 In case of W9x and lesser this function should return 120 (ERROR_CALL_NOT_IMPLEMENTED)
1927 to be really compatible. Most programs wont have any problems though. In case
1928 you encounter one, this is what you should return here. I don't know what's up
1929 with NT 3.5. Is this function available there or not?
1930 Does anybody really care about 3.5? :)
1933 /* Filename1 has to be always set to a valid path. Filename2 may be NULL
1934 if the source file has to be deleted.
1937 SetLastError(ERROR_INVALID_PARAMETER
);
1941 /* This function has to be run through in order to process the name properly.
1942 If the BOOTDELAY flag is set, the file doesn't need to exist though. At least
1943 that is the behaviour on NT 4.0. The operation accepts the filenames as
1944 they are given but it can't reply with a reasonable returncode. Success
1945 means in that case success for entering the values into the registry.
1947 if(!DOSFS_GetFullName( fn1
, TRUE
, &full_name1
))
1949 if(!(flag
& MOVEFILE_DELAY_UNTIL_REBOOT
))
1953 if (fn2
) /* !fn2 means delete fn1 */
1955 if (DOSFS_GetFullName( fn2
, TRUE
, &full_name2
))
1957 if(!(flag
& MOVEFILE_DELAY_UNTIL_REBOOT
))
1959 /* target exists, check if we may overwrite */
1960 if (!(flag
& MOVEFILE_REPLACE_EXISTING
))
1962 SetLastError( ERROR_FILE_EXISTS
);
1969 if (!DOSFS_GetFullName( fn2
, FALSE
, &full_name2
))
1971 if(!(flag
& MOVEFILE_DELAY_UNTIL_REBOOT
))
1976 /* Source name and target path are valid */
1978 if (flag
& MOVEFILE_DELAY_UNTIL_REBOOT
)
1980 return FILE_AddBootRenameEntry( fn1
, fn2
, flag
);
1983 attr
= GetFileAttributesW( fn1
);
1984 if ( attr
== INVALID_FILE_ATTRIBUTES
) return FALSE
;
1986 /* check if we are allowed to rename the source */
1987 hFile
= FILE_CreateFile( full_name1
.long_name
, 0, 0,
1988 NULL
, OPEN_EXISTING
, 0, 0, TRUE
,
1989 GetDriveTypeW( full_name1
.short_name
) );
1992 if (GetLastError() != ERROR_ACCESS_DENIED
) return FALSE
;
1993 if ( !(attr
& FILE_ATTRIBUTE_DIRECTORY
) ) return FALSE
;
1994 /* if it's a directory we can continue */
1996 else CloseHandle(hFile
);
1998 /* check, if we are allowed to delete the destination,
1999 ** (but the file not being there is fine) */
2000 hFile
= FILE_CreateFile( full_name2
.long_name
, GENERIC_READ
|GENERIC_WRITE
, 0,
2001 NULL
, OPEN_EXISTING
, 0, 0, TRUE
,
2002 GetDriveTypeW( full_name2
.short_name
) );
2003 if(!hFile
&& GetLastError() != ERROR_FILE_NOT_FOUND
) return FALSE
;
2006 if (full_name1
.drive
!= full_name2
.drive
)
2008 if (!(flag
& MOVEFILE_COPY_ALLOWED
))
2010 SetLastError( ERROR_NOT_SAME_DEVICE
);
2013 else if ( attr
& FILE_ATTRIBUTE_DIRECTORY
)
2015 /* Strange, but that's what Windows returns */
2016 SetLastError ( ERROR_ACCESS_DENIED
);
2020 if (rename( full_name1
.long_name
, full_name2
.long_name
) == -1)
2021 /* Try copy/delete unless it's a directory. */
2022 /* FIXME: This does not handle the (unlikely) case that the two locations
2023 are on the same Wine drive, but on different Unix file systems. */
2025 if ( attr
& FILE_ATTRIBUTE_DIRECTORY
)
2032 if ( ! CopyFileW( fn1
, fn2
, !(flag
& MOVEFILE_REPLACE_EXISTING
) ))
2034 if ( ! DeleteFileW ( fn1
) )
2038 if (is_executable( full_name1
.long_name
) != is_executable( full_name2
.long_name
))
2041 if (stat( full_name2
.long_name
, &fstat
) != -1)
2043 if (is_executable( full_name2
.long_name
))
2044 /* set executable bit where read bit is set */
2045 fstat
.st_mode
|= (fstat
.st_mode
& 0444) >> 2;
2047 fstat
.st_mode
&= ~0111;
2048 chmod( full_name2
.long_name
, fstat
.st_mode
);
2053 else /* fn2 == NULL means delete source */
2055 if (flag
& MOVEFILE_DELAY_UNTIL_REBOOT
)
2057 if (flag
& MOVEFILE_COPY_ALLOWED
) {
2058 WARN("Illegal flag\n");
2059 SetLastError( ERROR_GEN_FAILURE
);
2063 return FILE_AddBootRenameEntry( fn1
, NULL
, flag
);
2066 if (unlink( full_name1
.long_name
) == -1)
2071 return TRUE
; /* successfully deleted */
2075 /**************************************************************************
2076 * MoveFileExA (KERNEL32.@)
2078 BOOL WINAPI
MoveFileExA( LPCSTR fn1
, LPCSTR fn2
, DWORD flag
)
2080 UNICODE_STRING fn1W
, fn2W
;
2085 SetLastError(ERROR_INVALID_PARAMETER
);
2089 RtlCreateUnicodeStringFromAsciiz(&fn1W
, fn1
);
2090 if (fn2
) RtlCreateUnicodeStringFromAsciiz(&fn2W
, fn2
);
2091 else fn2W
.Buffer
= NULL
;
2093 ret
= MoveFileExW( fn1W
.Buffer
, fn2W
.Buffer
, flag
);
2095 RtlFreeUnicodeString(&fn1W
);
2096 RtlFreeUnicodeString(&fn2W
);
2101 /**************************************************************************
2102 * MoveFileW (KERNEL32.@)
2104 * Move file or directory
2106 BOOL WINAPI
MoveFileW( LPCWSTR fn1
, LPCWSTR fn2
)
2108 return MoveFileExW( fn1
, fn2
, MOVEFILE_COPY_ALLOWED
);
2112 /**************************************************************************
2113 * MoveFileA (KERNEL32.@)
2115 BOOL WINAPI
MoveFileA( LPCSTR fn1
, LPCSTR fn2
)
2117 return MoveFileExA( fn1
, fn2
, MOVEFILE_COPY_ALLOWED
);
2121 /**************************************************************************
2122 * CopyFileW (KERNEL32.@)
2124 BOOL WINAPI
CopyFileW( LPCWSTR source
, LPCWSTR dest
, BOOL fail_if_exists
)
2127 BY_HANDLE_FILE_INFORMATION info
;
2132 if (!source
|| !dest
)
2134 SetLastError(ERROR_INVALID_PARAMETER
);
2138 TRACE("%s -> %s\n", debugstr_w(source
), debugstr_w(dest
));
2140 if ((h1
= CreateFileW(source
, GENERIC_READ
, FILE_SHARE_READ
| FILE_SHARE_WRITE
,
2141 NULL
, OPEN_EXISTING
, 0, 0)) == INVALID_HANDLE_VALUE
)
2143 WARN("Unable to open source %s\n", debugstr_w(source
));
2147 if (!GetFileInformationByHandle( h1
, &info
))
2149 WARN("GetFileInformationByHandle returned error for %s\n", debugstr_w(source
));
2154 if ((h2
= CreateFileW( dest
, GENERIC_WRITE
, FILE_SHARE_READ
| FILE_SHARE_WRITE
, NULL
,
2155 fail_if_exists
? CREATE_NEW
: CREATE_ALWAYS
,
2156 info
.dwFileAttributes
, h1
)) == INVALID_HANDLE_VALUE
)
2158 WARN("Unable to open dest %s\n", debugstr_w(dest
));
2163 while (ReadFile( h1
, buffer
, sizeof(buffer
), &count
, NULL
) && count
)
2169 if (!WriteFile( h2
, p
, count
, &res
, NULL
) || !res
) goto done
;
2182 /**************************************************************************
2183 * CopyFileA (KERNEL32.@)
2185 BOOL WINAPI
CopyFileA( LPCSTR source
, LPCSTR dest
, BOOL fail_if_exists
)
2187 UNICODE_STRING sourceW
, destW
;
2190 if (!source
|| !dest
)
2192 SetLastError(ERROR_INVALID_PARAMETER
);
2196 RtlCreateUnicodeStringFromAsciiz(&sourceW
, source
);
2197 RtlCreateUnicodeStringFromAsciiz(&destW
, dest
);
2199 ret
= CopyFileW(sourceW
.Buffer
, destW
.Buffer
, fail_if_exists
);
2201 RtlFreeUnicodeString(&sourceW
);
2202 RtlFreeUnicodeString(&destW
);
2207 /**************************************************************************
2208 * CopyFileExW (KERNEL32.@)
2210 * This implementation ignores most of the extra parameters passed-in into
2211 * the "ex" version of the method and calls the CopyFile method.
2212 * It will have to be fixed eventually.
2214 BOOL WINAPI
CopyFileExW(LPCWSTR sourceFilename
, LPCWSTR destFilename
,
2215 LPPROGRESS_ROUTINE progressRoutine
, LPVOID appData
,
2216 LPBOOL cancelFlagPointer
, DWORD copyFlags
)
2219 * Interpret the only flag that CopyFile can interpret.
2221 return CopyFileW(sourceFilename
, destFilename
, (copyFlags
& COPY_FILE_FAIL_IF_EXISTS
) != 0);
2225 /**************************************************************************
2226 * CopyFileExA (KERNEL32.@)
2228 BOOL WINAPI
CopyFileExA(LPCSTR sourceFilename
, LPCSTR destFilename
,
2229 LPPROGRESS_ROUTINE progressRoutine
, LPVOID appData
,
2230 LPBOOL cancelFlagPointer
, DWORD copyFlags
)
2232 UNICODE_STRING sourceW
, destW
;
2235 if (!sourceFilename
|| !destFilename
)
2237 SetLastError(ERROR_INVALID_PARAMETER
);
2241 RtlCreateUnicodeStringFromAsciiz(&sourceW
, sourceFilename
);
2242 RtlCreateUnicodeStringFromAsciiz(&destW
, destFilename
);
2244 ret
= CopyFileExW(sourceW
.Buffer
, destW
.Buffer
, progressRoutine
, appData
,
2245 cancelFlagPointer
, copyFlags
);
2247 RtlFreeUnicodeString(&sourceW
);
2248 RtlFreeUnicodeString(&destW
);
2253 /***********************************************************************
2254 * SetFileTime (KERNEL32.@)
2256 BOOL WINAPI
SetFileTime( HANDLE hFile
,
2257 const FILETIME
*lpCreationTime
,
2258 const FILETIME
*lpLastAccessTime
,
2259 const FILETIME
*lpLastWriteTime
)
2262 SERVER_START_REQ( set_file_time
)
2264 req
->handle
= hFile
;
2265 if (lpLastAccessTime
)
2266 RtlTimeToSecondsSince1970( (PLARGE_INTEGER
) lpLastAccessTime
, (DWORD
*)&req
->access_time
);
2268 req
->access_time
= 0; /* FIXME */
2269 if (lpLastWriteTime
)
2270 RtlTimeToSecondsSince1970( (PLARGE_INTEGER
) lpLastWriteTime
, (DWORD
*)&req
->write_time
);
2272 req
->write_time
= 0; /* FIXME */
2273 ret
= !wine_server_call_err( req
);
2280 /**************************************************************************
2281 * GetFileAttributesExW (KERNEL32.@)
2283 BOOL WINAPI
GetFileAttributesExW(
2284 LPCWSTR lpFileName
, GET_FILEEX_INFO_LEVELS fInfoLevelId
,
2285 LPVOID lpFileInformation
)
2287 DOS_FULL_NAME full_name
;
2288 BY_HANDLE_FILE_INFORMATION info
;
2290 if (!lpFileName
|| !lpFileInformation
)
2292 SetLastError(ERROR_INVALID_PARAMETER
);
2296 if (fInfoLevelId
== GetFileExInfoStandard
) {
2297 LPWIN32_FILE_ATTRIBUTE_DATA lpFad
=
2298 (LPWIN32_FILE_ATTRIBUTE_DATA
) lpFileInformation
;
2299 if (!DOSFS_GetFullName( lpFileName
, TRUE
, &full_name
)) return FALSE
;
2300 if (!FILE_Stat( full_name
.long_name
, &info
, NULL
)) return FALSE
;
2302 lpFad
->dwFileAttributes
= info
.dwFileAttributes
;
2303 lpFad
->ftCreationTime
= info
.ftCreationTime
;
2304 lpFad
->ftLastAccessTime
= info
.ftLastAccessTime
;
2305 lpFad
->ftLastWriteTime
= info
.ftLastWriteTime
;
2306 lpFad
->nFileSizeHigh
= info
.nFileSizeHigh
;
2307 lpFad
->nFileSizeLow
= info
.nFileSizeLow
;
2310 FIXME("invalid info level %d!\n", fInfoLevelId
);
2318 /**************************************************************************
2319 * GetFileAttributesExA (KERNEL32.@)
2321 BOOL WINAPI
GetFileAttributesExA(
2322 LPCSTR filename
, GET_FILEEX_INFO_LEVELS fInfoLevelId
,
2323 LPVOID lpFileInformation
)
2325 UNICODE_STRING filenameW
;
2328 if (!filename
|| !lpFileInformation
)
2330 SetLastError(ERROR_INVALID_PARAMETER
);
2334 if (RtlCreateUnicodeStringFromAsciiz(&filenameW
, filename
))
2336 ret
= GetFileAttributesExW(filenameW
.Buffer
, fInfoLevelId
, lpFileInformation
);
2337 RtlFreeUnicodeString(&filenameW
);
2340 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);