2 * File handling functions
4 * Copyright 1993 John Burton
5 * Copyright 1996 Alexandre Julliard
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 * Fix the CopyFileEx methods to implement the "extended" functionality.
23 * Right now, they simply call the CopyFile method.
27 #include "wine/port.h"
37 #ifdef HAVE_SYS_ERRNO_H
38 #include <sys/errno.h>
40 #include <sys/types.h>
42 #ifdef HAVE_SYS_MMAN_H
45 #ifdef HAVE_SYS_TIME_H
46 # include <sys/time.h>
48 #ifdef HAVE_SYS_POLL_H
49 # include <sys/poll.h>
59 #define NONAMELESSUNION
60 #define NONAMELESSSTRUCT
67 #include "wine/winbase16.h"
68 #include "wine/server.h"
73 #include "kernel_private.h"
76 #include "wine/unicode.h"
77 #include "wine/debug.h"
79 WINE_DEFAULT_DEBUG_CHANNEL(file
);
81 #if defined(MAP_ANONYMOUS) && !defined(MAP_ANON)
82 #define MAP_ANON MAP_ANONYMOUS
85 #define IS_OPTION_TRUE(ch) ((ch) == 'y' || (ch) == 'Y' || (ch) == 't' || (ch) == 'T' || (ch) == '1')
87 HANDLE dos_handles
[DOS_TABLE_SIZE
];
90 /***********************************************************************
93 * Convert OF_* mode into flags for CreateFile.
95 void FILE_ConvertOFMode( INT mode
, DWORD
*access
, DWORD
*sharing
)
99 case OF_READ
: *access
= GENERIC_READ
; break;
100 case OF_WRITE
: *access
= GENERIC_WRITE
; break;
101 case OF_READWRITE
: *access
= GENERIC_READ
| GENERIC_WRITE
; break;
102 default: *access
= 0; break;
106 case OF_SHARE_EXCLUSIVE
: *sharing
= 0; break;
107 case OF_SHARE_DENY_WRITE
: *sharing
= FILE_SHARE_READ
; break;
108 case OF_SHARE_DENY_READ
: *sharing
= FILE_SHARE_WRITE
; break;
109 case OF_SHARE_DENY_NONE
:
110 case OF_SHARE_COMPAT
:
111 default: *sharing
= FILE_SHARE_READ
| FILE_SHARE_WRITE
; break;
116 /***********************************************************************
119 * locale-independent case conversion for file I/O
121 int FILE_strcasecmp( const char *str1
, const char *str2
)
124 for ( ; ; str1
++, str2
++)
125 if ((ret
= FILE_toupper(*str1
) - FILE_toupper(*str2
)) || !*str1
) break;
130 /***********************************************************************
133 * locale-independent case conversion for file I/O
135 int FILE_strncasecmp( const char *str1
, const char *str2
, int len
)
138 for ( ; len
> 0; len
--, str1
++, str2
++)
139 if ((ret
= FILE_toupper(*str1
) - FILE_toupper(*str2
)) || !*str1
) break;
144 /***********************************************************************
147 * Set the DOS error code from errno.
149 void FILE_SetDosError(void)
151 int save_errno
= errno
; /* errno gets overwritten by printf */
153 TRACE("errno = %d %s\n", errno
, strerror(errno
));
157 SetLastError( ERROR_SHARING_VIOLATION
);
160 SetLastError( ERROR_INVALID_HANDLE
);
163 SetLastError( ERROR_HANDLE_DISK_FULL
);
168 SetLastError( ERROR_ACCESS_DENIED
);
171 SetLastError( ERROR_LOCK_VIOLATION
);
174 SetLastError( ERROR_FILE_NOT_FOUND
);
177 SetLastError( ERROR_CANNOT_MAKE
);
181 SetLastError( ERROR_NO_MORE_FILES
);
184 SetLastError( ERROR_FILE_EXISTS
);
188 SetLastError( ERROR_SEEK
);
191 SetLastError( ERROR_DIR_NOT_EMPTY
);
194 SetLastError( ERROR_BAD_FORMAT
);
197 WARN("unknown file error: %s\n", strerror(save_errno
) );
198 SetLastError( ERROR_GEN_FAILURE
);
205 /***********************************************************************
206 * FILE_GetUnixHandleType
208 * Retrieve the Unix handle corresponding to a file handle.
209 * Returns -1 on failure.
211 static int FILE_GetUnixHandleType( HANDLE handle
, DWORD access
, enum fd_type
*type
, int *flags_ptr
)
213 int ret
, flags
, fd
= -1;
215 ret
= wine_server_handle_to_fd( handle
, access
, &fd
, type
, &flags
);
216 if (flags_ptr
) *flags_ptr
= flags
;
217 if (ret
) SetLastError( RtlNtStatusToDosError(ret
) );
218 else if (((access
& GENERIC_READ
) && (flags
& FD_FLAG_RECV_SHUTDOWN
)) ||
219 ((access
& GENERIC_WRITE
) && (flags
& FD_FLAG_SEND_SHUTDOWN
)))
222 SetLastError ( ERROR_PIPE_NOT_CONNECTED
);
228 /***********************************************************************
231 * Retrieve the Unix handle corresponding to a file handle.
232 * Returns -1 on failure.
234 int FILE_GetUnixHandle( HANDLE handle
, DWORD access
)
236 return FILE_GetUnixHandleType( handle
, access
, NULL
, NULL
);
239 /******************************************************************
240 * OpenConsoleW (KERNEL32.@)
243 * Open a handle to the current process console.
244 * Returns INVALID_HANDLE_VALUE on failure.
246 HANDLE WINAPI
OpenConsoleW(LPCWSTR name
, DWORD access
, LPSECURITY_ATTRIBUTES sa
,
249 static const WCHAR coninW
[] = {'C','O','N','I','N','$',0};
250 static const WCHAR conoutW
[] = {'C','O','N','O','U','T','$',0};
254 if (strcmpW(coninW
, name
) == 0)
256 else if (strcmpW(conoutW
, name
) == 0)
260 SetLastError(ERROR_INVALID_NAME
);
261 return INVALID_HANDLE_VALUE
;
263 if (creation
!= OPEN_EXISTING
)
265 SetLastError(ERROR_INVALID_PARAMETER
);
266 return INVALID_HANDLE_VALUE
;
269 SERVER_START_REQ( open_console
)
272 req
->access
= access
;
273 req
->share
= FILE_SHARE_READ
| FILE_SHARE_WRITE
;
274 req
->inherit
= (sa
&& (sa
->nLength
>=sizeof(*sa
)) && sa
->bInheritHandle
);
276 wine_server_call_err( req
);
280 return ret
? console_handle_map(ret
) : INVALID_HANDLE_VALUE
;
283 /******************************************************************
284 * VerifyConsoleIoHandle (KERNEL32.@)
288 BOOL WINAPI
VerifyConsoleIoHandle(HANDLE handle
)
292 if (!is_console_handle(handle
)) return FALSE
;
293 SERVER_START_REQ(get_console_mode
)
295 req
->handle
= console_handle_unmap(handle
);
296 ret
= !wine_server_call_err( req
);
302 /******************************************************************
303 * DuplicateConsoleHandle (KERNEL32.@)
307 HANDLE WINAPI
DuplicateConsoleHandle(HANDLE handle
, DWORD access
, BOOL inherit
,
312 if (!is_console_handle(handle
) ||
313 !DuplicateHandle(GetCurrentProcess(), console_handle_unmap(handle
),
314 GetCurrentProcess(), &ret
, access
, inherit
, options
))
315 return INVALID_HANDLE_VALUE
;
316 return console_handle_map(ret
);
319 /******************************************************************
320 * CloseConsoleHandle (KERNEL32.@)
324 BOOL WINAPI
CloseConsoleHandle(HANDLE handle
)
326 if (!is_console_handle(handle
))
328 SetLastError(ERROR_INVALID_PARAMETER
);
331 return CloseHandle(console_handle_unmap(handle
));
334 /******************************************************************
335 * GetConsoleInputWaitHandle (KERNEL32.@)
339 HANDLE WINAPI
GetConsoleInputWaitHandle(void)
341 static HANDLE console_wait_event
;
343 /* FIXME: this is not thread safe */
344 if (!console_wait_event
)
346 SERVER_START_REQ(get_console_wait_event
)
348 if (!wine_server_call_err( req
)) console_wait_event
= reply
->handle
;
352 return console_wait_event
;
357 /* FIXME: those routines defined as pointers are needed, because this file is
358 * currently compiled into NTDLL whereas it belongs to kernel32.
359 * this shall go away once all the DLL separation process is done
361 typedef BOOL (WINAPI
* pRW
)(HANDLE
, const void*, DWORD
, DWORD
*, void*);
363 static BOOL
FILE_ReadConsole(HANDLE hCon
, void* buf
, DWORD nb
, DWORD
* nr
, void* p
)
365 static HANDLE hKernel
/* = 0 */;
366 static pRW pReadConsole
/* = 0 */;
368 if ((!hKernel
&& !(hKernel
= LoadLibraryA("kernel32"))) ||
370 !(pReadConsole
= GetProcAddress(hKernel
, "ReadConsoleA"))))
375 return (pReadConsole
)(hCon
, buf
, nb
, nr
, p
);
378 static BOOL
FILE_WriteConsole(HANDLE hCon
, const void* buf
, DWORD nb
, DWORD
* nr
, void* p
)
380 static HANDLE hKernel
/* = 0 */;
381 static pRW pWriteConsole
/* = 0 */;
383 if ((!hKernel
&& !(hKernel
= LoadLibraryA("kernel32"))) ||
385 !(pWriteConsole
= GetProcAddress(hKernel
, "WriteConsoleA"))))
390 return (pWriteConsole
)(hCon
, buf
, nb
, nr
, p
);
394 /***********************************************************************
397 * Implementation of CreateFile. Takes a Unix path name.
398 * Returns 0 on failure.
400 HANDLE
FILE_CreateFile( LPCSTR filename
, DWORD access
, DWORD sharing
,
401 LPSECURITY_ATTRIBUTES sa
, DWORD creation
,
402 DWORD attributes
, HANDLE
template, BOOL fail_read_only
,
410 SERVER_START_REQ( create_file
)
412 req
->access
= access
;
413 req
->inherit
= (sa
&& (sa
->nLength
>=sizeof(*sa
)) && sa
->bInheritHandle
);
414 req
->sharing
= sharing
;
415 req
->create
= creation
;
416 req
->attrs
= attributes
;
417 req
->removable
= (drive_type
== DRIVE_REMOVABLE
|| drive_type
== DRIVE_CDROM
);
418 wine_server_add_data( req
, filename
, strlen(filename
) );
420 err
= wine_server_call( req
);
425 /* If write access failed, retry without GENERIC_WRITE */
427 if (!ret
&& !fail_read_only
&& (access
& GENERIC_WRITE
))
429 if ((err
== STATUS_MEDIA_WRITE_PROTECTED
) || (err
== STATUS_ACCESS_DENIED
))
431 TRACE("Write access failed for file '%s', trying without "
432 "write access\n", filename
);
433 access
&= ~GENERIC_WRITE
;
440 /* In the case file creation was rejected due to CREATE_NEW flag
441 * was specified and file with that name already exists, correct
442 * last error is ERROR_FILE_EXISTS and not ERROR_ALREADY_EXISTS.
443 * Note: RtlNtStatusToDosError is not the subject to blame here.
445 if (err
== STATUS_OBJECT_NAME_COLLISION
)
446 SetLastError( ERROR_FILE_EXISTS
);
448 SetLastError( RtlNtStatusToDosError(err
) );
451 if (!ret
) WARN("Unable to create file '%s' (GLE %ld)\n", filename
, GetLastError());
457 /***********************************************************************
460 * Same as FILE_CreateFile but for a device
461 * Returns 0 on failure.
463 HANDLE
FILE_CreateDevice( int client_id
, DWORD access
, LPSECURITY_ATTRIBUTES sa
)
466 SERVER_START_REQ( create_device
)
468 req
->access
= access
;
469 req
->inherit
= (sa
&& (sa
->nLength
>=sizeof(*sa
)) && sa
->bInheritHandle
);
472 wine_server_call_err( req
);
479 static HANDLE
FILE_OpenPipe(LPCWSTR name
, DWORD access
, LPSECURITY_ATTRIBUTES sa
)
484 if (name
&& (len
= strlenW(name
)) > MAX_PATH
)
486 SetLastError( ERROR_FILENAME_EXCED_RANGE
);
489 SERVER_START_REQ( open_named_pipe
)
491 req
->access
= access
;
492 req
->inherit
= (sa
&& (sa
->nLength
>=sizeof(*sa
)) && sa
->bInheritHandle
);
494 wine_server_add_data( req
, name
, len
* sizeof(WCHAR
) );
495 wine_server_call_err( req
);
499 TRACE("Returned %p\n",ret
);
503 /*************************************************************************
504 * CreateFileW [KERNEL32.@] Creates or opens a file or other object
506 * Creates or opens an object, and returns a handle that can be used to
507 * access that object.
511 * filename [in] pointer to filename to be accessed
512 * access [in] access mode requested
513 * sharing [in] share mode
514 * sa [in] pointer to security attributes
515 * creation [in] how to create the file
516 * attributes [in] attributes for newly created file
517 * template [in] handle to file with extended attributes to copy
520 * Success: Open handle to specified file
521 * Failure: INVALID_HANDLE_VALUE
524 * Should call SetLastError() on failure.
528 * Doesn't support character devices, template files, or a
529 * lot of the 'attributes' flags yet.
531 HANDLE WINAPI
CreateFileW( LPCWSTR filename
, DWORD access
, DWORD sharing
,
532 LPSECURITY_ATTRIBUTES sa
, DWORD creation
,
533 DWORD attributes
, HANDLE
template )
535 DOS_FULL_NAME full_name
;
537 static const WCHAR bkslashes_with_question_markW
[] = {'\\','\\','?','\\',0};
538 static const WCHAR bkslashes_with_dotW
[] = {'\\','\\','.','\\',0};
539 static const WCHAR bkslashesW
[] = {'\\','\\',0};
540 static const WCHAR coninW
[] = {'C','O','N','I','N','$',0};
541 static const WCHAR conoutW
[] = {'C','O','N','O','U','T','$',0};
545 SetLastError( ERROR_INVALID_PARAMETER
);
546 return INVALID_HANDLE_VALUE
;
548 TRACE("%s %s%s%s%s%s%s%s attributes 0x%lx\n", debugstr_w(filename
),
549 ((access
& GENERIC_READ
)==GENERIC_READ
)?"GENERIC_READ ":"",
550 ((access
& GENERIC_WRITE
)==GENERIC_WRITE
)?"GENERIC_WRITE ":"",
551 (!access
)?"QUERY_ACCESS ":"",
552 ((sharing
& FILE_SHARE_READ
)==FILE_SHARE_READ
)?"FILE_SHARE_READ ":"",
553 ((sharing
& FILE_SHARE_WRITE
)==FILE_SHARE_WRITE
)?"FILE_SHARE_WRITE ":"",
554 ((sharing
& FILE_SHARE_DELETE
)==FILE_SHARE_DELETE
)?"FILE_SHARE_DELETE ":"",
555 (creation
==CREATE_NEW
)?"CREATE_NEW":
556 (creation
==CREATE_ALWAYS
)?"CREATE_ALWAYS ":
557 (creation
==OPEN_EXISTING
)?"OPEN_EXISTING ":
558 (creation
==OPEN_ALWAYS
)?"OPEN_ALWAYS ":
559 (creation
==TRUNCATE_EXISTING
)?"TRUNCATE_EXISTING ":"", attributes
);
561 /* If the name starts with '\\?\', ignore the first 4 chars. */
562 if (!strncmpW(filename
, bkslashes_with_question_markW
, 4))
564 static const WCHAR uncW
[] = {'U','N','C','\\',0};
566 if (!strncmpiW(filename
, uncW
, 4))
568 FIXME("UNC name (%s) not supported.\n", debugstr_w(filename
) );
569 SetLastError( ERROR_PATH_NOT_FOUND
);
570 return INVALID_HANDLE_VALUE
;
574 if (!strncmpW(filename
, bkslashes_with_dotW
, 4))
576 static const WCHAR pipeW
[] = {'P','I','P','E','\\',0};
577 if(!strncmpiW(filename
+ 4, pipeW
, 5))
579 TRACE("Opening a pipe: %s\n", debugstr_w(filename
));
580 ret
= FILE_OpenPipe( filename
, access
, sa
);
583 else if (isalphaW(filename
[4]) && filename
[5] == ':' && filename
[6] == '\0')
585 ret
= FILE_CreateDevice( (toupperW(filename
[4]) - 'A') | 0x20000, access
, sa
);
588 else if (!DOSFS_GetDevice( filename
))
590 ret
= DEVICE_Open( filename
+4, access
, sa
);
594 filename
+=4; /* fall into DOSFS_Device case below */
597 /* If the name still starts with '\\', it's a UNC name. */
598 if (!strncmpW(filename
, bkslashesW
, 2))
600 ret
= SMB_CreateFileW(filename
, access
, sharing
, sa
, creation
, attributes
, template );
604 /* If the name contains a DOS wild card (* or ?), do no create a file */
605 if(strchrW(filename
, '*') || strchrW(filename
, '?'))
607 SetLastError(ERROR_BAD_PATHNAME
);
608 return INVALID_HANDLE_VALUE
;
611 /* Open a console for CONIN$ or CONOUT$ */
612 if (!strcmpiW(filename
, coninW
) || !strcmpiW(filename
, conoutW
))
614 ret
= OpenConsoleW(filename
, access
, sa
, creation
);
618 if (DOSFS_GetDevice( filename
))
620 TRACE("opening device %s\n", debugstr_w(filename
) );
622 if (!(ret
= DOSFS_OpenDevice( filename
, access
, attributes
, sa
)))
624 /* Do not silence this please. It is a critical error. -MM */
625 ERR("Couldn't open device %s!\n", debugstr_w(filename
));
626 SetLastError( ERROR_FILE_NOT_FOUND
);
631 /* check for filename, don't check for last entry if creating */
632 if (!DOSFS_GetFullName( filename
,
633 (creation
== OPEN_EXISTING
) ||
634 (creation
== TRUNCATE_EXISTING
),
636 WARN("Unable to get full filename from %s (GLE %ld)\n",
637 debugstr_w(filename
), GetLastError());
638 return INVALID_HANDLE_VALUE
;
641 ret
= FILE_CreateFile( full_name
.long_name
, access
, sharing
,
642 sa
, creation
, attributes
, template,
643 DRIVE_GetFlags(full_name
.drive
) & DRIVE_FAIL_READ_ONLY
,
644 GetDriveTypeW( full_name
.short_name
) );
646 if (!ret
) ret
= INVALID_HANDLE_VALUE
;
647 TRACE("returning %p\n", ret
);
653 /*************************************************************************
654 * CreateFileA (KERNEL32.@)
656 HANDLE WINAPI
CreateFileA( LPCSTR filename
, DWORD access
, DWORD sharing
,
657 LPSECURITY_ATTRIBUTES sa
, DWORD creation
,
658 DWORD attributes
, HANDLE
template)
660 UNICODE_STRING filenameW
;
661 HANDLE ret
= INVALID_HANDLE_VALUE
;
665 SetLastError( ERROR_INVALID_PARAMETER
);
666 return INVALID_HANDLE_VALUE
;
669 if (RtlCreateUnicodeStringFromAsciiz(&filenameW
, filename
))
671 ret
= CreateFileW(filenameW
.Buffer
, access
, sharing
, sa
, creation
,
672 attributes
, template);
673 RtlFreeUnicodeString(&filenameW
);
676 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
681 /***********************************************************************
684 * Fill a file information from a struct stat.
686 static void FILE_FillInfo( struct stat
*st
, BY_HANDLE_FILE_INFORMATION
*info
)
688 if (S_ISDIR(st
->st_mode
))
689 info
->dwFileAttributes
= FILE_ATTRIBUTE_DIRECTORY
;
691 info
->dwFileAttributes
= FILE_ATTRIBUTE_ARCHIVE
;
692 if (!(st
->st_mode
& S_IWUSR
))
693 info
->dwFileAttributes
|= FILE_ATTRIBUTE_READONLY
;
695 RtlSecondsSince1970ToTime( st
->st_mtime
, (LARGE_INTEGER
*)&info
->ftCreationTime
);
696 RtlSecondsSince1970ToTime( st
->st_mtime
, (LARGE_INTEGER
*)&info
->ftLastWriteTime
);
697 RtlSecondsSince1970ToTime( st
->st_atime
, (LARGE_INTEGER
*)&info
->ftLastAccessTime
);
699 info
->dwVolumeSerialNumber
= 0; /* FIXME */
700 info
->nFileSizeHigh
= 0;
701 info
->nFileSizeLow
= 0;
702 if (!S_ISDIR(st
->st_mode
)) {
703 info
->nFileSizeHigh
= st
->st_size
>> 32;
704 info
->nFileSizeLow
= st
->st_size
& 0xffffffff;
706 info
->nNumberOfLinks
= st
->st_nlink
;
707 info
->nFileIndexHigh
= 0;
708 info
->nFileIndexLow
= st
->st_ino
;
712 /***********************************************************************
713 * get_show_dot_files_option
715 static BOOL
get_show_dot_files_option(void)
717 static const WCHAR WineW
[] = {'M','a','c','h','i','n','e','\\',
718 'S','o','f','t','w','a','r','e','\\',
719 'W','i','n','e','\\','W','i','n','e','\\',
720 'C','o','n','f','i','g','\\','W','i','n','e',0};
721 static const WCHAR ShowDotFilesW
[] = {'S','h','o','w','D','o','t','F','i','l','e','s',0};
726 OBJECT_ATTRIBUTES attr
;
727 UNICODE_STRING nameW
;
730 attr
.Length
= sizeof(attr
);
731 attr
.RootDirectory
= 0;
732 attr
.ObjectName
= &nameW
;
734 attr
.SecurityDescriptor
= NULL
;
735 attr
.SecurityQualityOfService
= NULL
;
736 RtlInitUnicodeString( &nameW
, WineW
);
738 if (!NtOpenKey( &hkey
, KEY_ALL_ACCESS
, &attr
))
740 RtlInitUnicodeString( &nameW
, ShowDotFilesW
);
741 if (!NtQueryValueKey( hkey
, &nameW
, KeyValuePartialInformation
, tmp
, sizeof(tmp
), &dummy
))
743 WCHAR
*str
= (WCHAR
*)((KEY_VALUE_PARTIAL_INFORMATION
*)tmp
)->Data
;
744 ret
= IS_OPTION_TRUE( str
[0] );
752 /***********************************************************************
755 * Stat a Unix path name. Return TRUE if OK.
757 BOOL
FILE_Stat( LPCSTR unixName
, BY_HANDLE_FILE_INFORMATION
*info
, BOOL
*is_symlink_ptr
)
763 if (lstat( unixName
, &st
) == -1)
768 is_symlink
= S_ISLNK(st
.st_mode
);
771 /* do a "real" stat to find out
772 about the type of the symlink destination */
773 if (stat( unixName
, &st
) == -1)
780 /* fill in the information we gathered so far */
781 FILE_FillInfo( &st
, info
);
783 /* and now see if this is a hidden file, based on the name */
784 p
= strrchr( unixName
, '/');
785 p
= p
? p
+ 1 : unixName
;
786 if (*p
== '.' && *(p
+1) && (*(p
+1) != '.' || *(p
+2)))
788 static int show_dot_files
= -1;
789 if (show_dot_files
== -1)
790 show_dot_files
= get_show_dot_files_option();
792 info
->dwFileAttributes
|= FILE_ATTRIBUTE_HIDDEN
;
794 if (is_symlink_ptr
) *is_symlink_ptr
= is_symlink
;
799 /***********************************************************************
800 * GetFileInformationByHandle (KERNEL32.@)
802 DWORD WINAPI
GetFileInformationByHandle( HANDLE hFile
,
803 BY_HANDLE_FILE_INFORMATION
*info
)
808 TRACE("%p\n", hFile
);
810 SERVER_START_REQ( get_file_info
)
813 if ((ret
= !wine_server_call_err( req
)))
815 /* FIXME: which file types are supported ?
816 * Serial ports (FILE_TYPE_CHAR) are not,
817 * and MSDN also says that pipes are not supported.
818 * FILE_TYPE_REMOTE seems to be supported according to
819 * MSDN q234741.txt */
820 if ((reply
->type
== FILE_TYPE_DISK
) || (reply
->type
== FILE_TYPE_REMOTE
))
822 RtlSecondsSince1970ToTime( reply
->write_time
, (LARGE_INTEGER
*)&info
->ftCreationTime
);
823 RtlSecondsSince1970ToTime( reply
->write_time
, (LARGE_INTEGER
*)&info
->ftLastWriteTime
);
824 RtlSecondsSince1970ToTime( reply
->access_time
, (LARGE_INTEGER
*)&info
->ftLastAccessTime
);
825 info
->dwFileAttributes
= reply
->attr
;
826 info
->dwVolumeSerialNumber
= reply
->serial
;
827 info
->nFileSizeHigh
= reply
->size_high
;
828 info
->nFileSizeLow
= reply
->size_low
;
829 info
->nNumberOfLinks
= reply
->links
;
830 info
->nFileIndexHigh
= reply
->index_high
;
831 info
->nFileIndexLow
= reply
->index_low
;
835 SetLastError(ERROR_NOT_SUPPORTED
);
845 /**************************************************************************
846 * GetFileAttributesW (KERNEL32.@)
848 DWORD WINAPI
GetFileAttributesW( LPCWSTR name
)
850 DOS_FULL_NAME full_name
;
851 BY_HANDLE_FILE_INFORMATION info
;
855 SetLastError( ERROR_INVALID_PARAMETER
);
856 return INVALID_FILE_ATTRIBUTES
;
858 if (!DOSFS_GetFullName( name
, TRUE
, &full_name
) )
859 return INVALID_FILE_ATTRIBUTES
;
860 if (!FILE_Stat( full_name
.long_name
, &info
, NULL
))
861 return INVALID_FILE_ATTRIBUTES
;
862 return info
.dwFileAttributes
;
866 /**************************************************************************
867 * GetFileAttributesA (KERNEL32.@)
869 DWORD WINAPI
GetFileAttributesA( LPCSTR name
)
871 UNICODE_STRING nameW
;
872 DWORD ret
= INVALID_FILE_ATTRIBUTES
;
876 SetLastError( ERROR_INVALID_PARAMETER
);
877 return INVALID_FILE_ATTRIBUTES
;
880 if (RtlCreateUnicodeStringFromAsciiz(&nameW
, name
))
882 ret
= GetFileAttributesW(nameW
.Buffer
);
883 RtlFreeUnicodeString(&nameW
);
886 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
891 /**************************************************************************
892 * SetFileAttributesW (KERNEL32.@)
894 BOOL WINAPI
SetFileAttributesW(LPCWSTR lpFileName
, DWORD attributes
)
897 DOS_FULL_NAME full_name
;
901 SetLastError( ERROR_INVALID_PARAMETER
);
905 TRACE("(%s,%lx)\n", debugstr_w(lpFileName
), attributes
);
907 if (!DOSFS_GetFullName( lpFileName
, TRUE
, &full_name
))
910 if(stat(full_name
.long_name
,&buf
)==-1)
915 if (attributes
& FILE_ATTRIBUTE_READONLY
)
917 if(S_ISDIR(buf
.st_mode
))
919 WARN("FILE_ATTRIBUTE_READONLY ignored for directory.\n");
921 buf
.st_mode
&= ~0222; /* octal!, clear write permission bits */
922 attributes
&= ~FILE_ATTRIBUTE_READONLY
;
926 /* add write permission */
927 buf
.st_mode
|= (0600 | ((buf
.st_mode
& 044) >> 1)) & (~FILE_umask
);
929 if (attributes
& FILE_ATTRIBUTE_DIRECTORY
)
931 if (!S_ISDIR(buf
.st_mode
))
932 FIXME("SetFileAttributes expected the file %s to be a directory\n",
933 debugstr_w(lpFileName
));
934 attributes
&= ~FILE_ATTRIBUTE_DIRECTORY
;
936 attributes
&= ~(FILE_ATTRIBUTE_NORMAL
|FILE_ATTRIBUTE_ARCHIVE
|FILE_ATTRIBUTE_HIDDEN
|FILE_ATTRIBUTE_SYSTEM
);
938 FIXME("(%s):%lx attribute(s) not implemented.\n", debugstr_w(lpFileName
), attributes
);
939 if (-1==chmod(full_name
.long_name
,buf
.st_mode
))
941 if (GetDriveTypeW(lpFileName
) == DRIVE_CDROM
)
943 SetLastError( ERROR_ACCESS_DENIED
);
948 * FIXME: We don't return FALSE here because of differences between
949 * Linux and Windows privileges. Under Linux only the owner of
950 * the file is allowed to change file attributes. Under Windows,
951 * applications expect that if you can write to a file, you can also
952 * change its attributes (see GENERIC_WRITE). We could try to be
953 * clever here but that would break multi-user installations where
954 * users share read-only DLLs. This is because some installers like
955 * to change attributes of already installed DLLs.
957 FIXME("Couldn't set file attributes for existing file \"%s\".\n"
958 "Check permissions or set VFAT \"quiet\" mount flag\n", full_name
.long_name
);
964 /**************************************************************************
965 * SetFileAttributesA (KERNEL32.@)
967 BOOL WINAPI
SetFileAttributesA(LPCSTR lpFileName
, DWORD attributes
)
969 UNICODE_STRING filenameW
;
974 SetLastError( ERROR_INVALID_PARAMETER
);
978 if (RtlCreateUnicodeStringFromAsciiz(&filenameW
, lpFileName
))
980 ret
= SetFileAttributesW(filenameW
.Buffer
, attributes
);
981 RtlFreeUnicodeString(&filenameW
);
984 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
989 /******************************************************************************
990 * GetCompressedFileSizeA [KERNEL32.@]
992 DWORD WINAPI
GetCompressedFileSizeA(
994 LPDWORD lpFileSizeHigh
)
996 UNICODE_STRING filenameW
;
999 if (RtlCreateUnicodeStringFromAsciiz(&filenameW
, lpFileName
))
1001 ret
= GetCompressedFileSizeW(filenameW
.Buffer
, lpFileSizeHigh
);
1002 RtlFreeUnicodeString(&filenameW
);
1006 ret
= INVALID_FILE_SIZE
;
1007 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
1013 /******************************************************************************
1014 * GetCompressedFileSizeW [KERNEL32.@]
1017 * Success: Low-order doubleword of number of bytes
1018 * Failure: INVALID_FILE_SIZE
1020 DWORD WINAPI
GetCompressedFileSizeW(
1021 LPCWSTR lpFileName
, /* [in] Pointer to name of file */
1022 LPDWORD lpFileSizeHigh
) /* [out] Receives high-order doubleword of size */
1024 DOS_FULL_NAME full_name
;
1028 TRACE("(%s,%p)\n",debugstr_w(lpFileName
),lpFileSizeHigh
);
1030 if (!DOSFS_GetFullName( lpFileName
, TRUE
, &full_name
)) return INVALID_FILE_SIZE
;
1031 if (stat(full_name
.long_name
, &st
) != 0)
1034 return INVALID_FILE_SIZE
;
1036 #if HAVE_STRUCT_STAT_ST_BLOCKS
1037 /* blocks are 512 bytes long */
1038 if (lpFileSizeHigh
) *lpFileSizeHigh
= (st
.st_blocks
>> 23);
1039 low
= (DWORD
)(st
.st_blocks
<< 9);
1041 if (lpFileSizeHigh
) *lpFileSizeHigh
= (st
.st_size
>> 32);
1042 low
= (DWORD
)st
.st_size
;
1048 /***********************************************************************
1049 * GetFileTime (KERNEL32.@)
1051 BOOL WINAPI
GetFileTime( HANDLE hFile
, FILETIME
*lpCreationTime
,
1052 FILETIME
*lpLastAccessTime
,
1053 FILETIME
*lpLastWriteTime
)
1055 BY_HANDLE_FILE_INFORMATION info
;
1056 if (!GetFileInformationByHandle( hFile
, &info
)) return FALSE
;
1057 if (lpCreationTime
) *lpCreationTime
= info
.ftCreationTime
;
1058 if (lpLastAccessTime
) *lpLastAccessTime
= info
.ftLastAccessTime
;
1059 if (lpLastWriteTime
) *lpLastWriteTime
= info
.ftLastWriteTime
;
1064 /***********************************************************************
1065 * GetTempFileNameA (KERNEL32.@)
1067 UINT WINAPI
GetTempFileNameA( LPCSTR path
, LPCSTR prefix
, UINT unique
,
1070 UNICODE_STRING pathW
, prefixW
;
1071 WCHAR bufferW
[MAX_PATH
];
1074 if ( !path
|| !prefix
|| !buffer
)
1076 SetLastError( ERROR_INVALID_PARAMETER
);
1080 RtlCreateUnicodeStringFromAsciiz(&pathW
, path
);
1081 RtlCreateUnicodeStringFromAsciiz(&prefixW
, prefix
);
1083 ret
= GetTempFileNameW(pathW
.Buffer
, prefixW
.Buffer
, unique
, bufferW
);
1085 WideCharToMultiByte(CP_ACP
, 0, bufferW
, -1, buffer
, MAX_PATH
, NULL
, NULL
);
1087 RtlFreeUnicodeString(&pathW
);
1088 RtlFreeUnicodeString(&prefixW
);
1092 /***********************************************************************
1093 * GetTempFileNameW (KERNEL32.@)
1095 UINT WINAPI
GetTempFileNameW( LPCWSTR path
, LPCWSTR prefix
, UINT unique
,
1098 static const WCHAR formatW
[] = {'%','0','4','x','.','t','m','p',0};
1100 DOS_FULL_NAME full_name
;
1104 if ( !path
|| !prefix
|| !buffer
)
1106 SetLastError( ERROR_INVALID_PARAMETER
);
1110 strcpyW( buffer
, path
);
1111 p
= buffer
+ strlenW(buffer
);
1113 /* add a \, if there isn't one and path is more than just the drive letter ... */
1114 if ( !((strlenW(buffer
) == 2) && (buffer
[1] == ':'))
1115 && ((p
== buffer
) || (p
[-1] != '\\'))) *p
++ = '\\';
1117 for (i
= 3; (i
> 0) && (*prefix
); i
--) *p
++ = *prefix
++;
1121 if (unique
) sprintfW( p
, formatW
, unique
);
1124 /* get a "random" unique number and try to create the file */
1126 UINT num
= GetTickCount() & 0xffff;
1132 sprintfW( p
, formatW
, unique
);
1133 handle
= CreateFileW( buffer
, GENERIC_WRITE
, 0, NULL
,
1134 CREATE_NEW
, FILE_ATTRIBUTE_NORMAL
, 0 );
1135 if (handle
!= INVALID_HANDLE_VALUE
)
1136 { /* We created it */
1137 TRACE("created %s\n", debugstr_w(buffer
) );
1138 CloseHandle( handle
);
1141 if (GetLastError() != ERROR_FILE_EXISTS
&&
1142 GetLastError() != ERROR_SHARING_VIOLATION
)
1143 break; /* No need to go on */
1144 if (!(++unique
& 0xffff)) unique
= 1;
1145 } while (unique
!= num
);
1148 /* Get the full path name */
1150 if (DOSFS_GetFullName( buffer
, FALSE
, &full_name
))
1153 /* Check if we have write access in the directory */
1154 if ((slash
= strrchr( full_name
.long_name
, '/' ))) *slash
= '\0';
1155 if (access( full_name
.long_name
, W_OK
) == -1)
1156 WARN("returns %s, which doesn't seem to be writeable.\n",
1157 debugstr_w(buffer
) );
1159 TRACE("returning %s\n", debugstr_w(buffer
) );
1164 /***********************************************************************
1167 * Implementation of OpenFile16() and OpenFile32().
1169 static HFILE
FILE_DoOpenFile( LPCSTR name
, OFSTRUCT
*ofs
, UINT mode
, BOOL win32
)
1174 WORD filedatetime
[2];
1175 DOS_FULL_NAME full_name
;
1176 DWORD access
, sharing
;
1178 WCHAR buffer
[MAX_PATH
];
1181 if (!ofs
) return HFILE_ERROR
;
1183 TRACE("%s %s %s %s%s%s%s%s%s%s%s%s\n",name
,
1184 ((mode
& 0x3 )==OF_READ
)?"OF_READ":
1185 ((mode
& 0x3 )==OF_WRITE
)?"OF_WRITE":
1186 ((mode
& 0x3 )==OF_READWRITE
)?"OF_READWRITE":"unknown",
1187 ((mode
& 0x70 )==OF_SHARE_COMPAT
)?"OF_SHARE_COMPAT":
1188 ((mode
& 0x70 )==OF_SHARE_DENY_NONE
)?"OF_SHARE_DENY_NONE":
1189 ((mode
& 0x70 )==OF_SHARE_DENY_READ
)?"OF_SHARE_DENY_READ":
1190 ((mode
& 0x70 )==OF_SHARE_DENY_WRITE
)?"OF_SHARE_DENY_WRITE":
1191 ((mode
& 0x70 )==OF_SHARE_EXCLUSIVE
)?"OF_SHARE_EXCLUSIVE":"unknown",
1192 ((mode
& OF_PARSE
)==OF_PARSE
)?"OF_PARSE ":"",
1193 ((mode
& OF_DELETE
)==OF_DELETE
)?"OF_DELETE ":"",
1194 ((mode
& OF_VERIFY
)==OF_VERIFY
)?"OF_VERIFY ":"",
1195 ((mode
& OF_SEARCH
)==OF_SEARCH
)?"OF_SEARCH ":"",
1196 ((mode
& OF_CANCEL
)==OF_CANCEL
)?"OF_CANCEL ":"",
1197 ((mode
& OF_CREATE
)==OF_CREATE
)?"OF_CREATE ":"",
1198 ((mode
& OF_PROMPT
)==OF_PROMPT
)?"OF_PROMPT ":"",
1199 ((mode
& OF_EXIST
)==OF_EXIST
)?"OF_EXIST ":"",
1200 ((mode
& OF_REOPEN
)==OF_REOPEN
)?"OF_REOPEN ":""
1204 ofs
->cBytes
= sizeof(OFSTRUCT
);
1206 if (mode
& OF_REOPEN
) name
= ofs
->szPathName
;
1209 ERR("called with `name' set to NULL ! Please debug.\n");
1213 TRACE("%s %04x\n", name
, mode
);
1215 /* the watcom 10.6 IDE relies on a valid path returned in ofs->szPathName
1216 Are there any cases where getting the path here is wrong?
1217 Uwe Bonnes 1997 Apr 2 */
1218 if (!GetFullPathNameA( name
, sizeof(ofs
->szPathName
),
1219 ofs
->szPathName
, NULL
)) goto error
;
1220 FILE_ConvertOFMode( mode
, &access
, &sharing
);
1222 /* OF_PARSE simply fills the structure */
1224 if (mode
& OF_PARSE
)
1226 ofs
->fFixedDisk
= (GetDriveType16( ofs
->szPathName
[0]-'A' )
1227 != DRIVE_REMOVABLE
);
1228 TRACE("(%s): OF_PARSE, res = '%s'\n",
1229 name
, ofs
->szPathName
);
1233 /* OF_CREATE is completely different from all other options, so
1236 if (mode
& OF_CREATE
)
1238 if ((handle
= CreateFileA( name
, GENERIC_READ
| GENERIC_WRITE
,
1239 sharing
, NULL
, CREATE_ALWAYS
,
1240 FILE_ATTRIBUTE_NORMAL
, 0 ))== INVALID_HANDLE_VALUE
)
1245 MultiByteToWideChar(CP_ACP
, 0, name
, -1, buffer
, MAX_PATH
);
1248 /* If OF_SEARCH is set, ignore the given path */
1250 if ((mode
& OF_SEARCH
) && !(mode
& OF_REOPEN
))
1252 /* First try the file name as is */
1253 if (DOSFS_GetFullName( nameW
, TRUE
, &full_name
)) goto found
;
1254 /* Now remove the path */
1255 if (nameW
[0] && (nameW
[1] == ':')) nameW
+= 2;
1256 if ((p
= strrchrW( nameW
, '\\' ))) nameW
= p
+ 1;
1257 if ((p
= strrchrW( nameW
, '/' ))) nameW
= p
+ 1;
1258 if (!nameW
[0]) goto not_found
;
1261 /* Now look for the file */
1263 if (!DIR_SearchPath( NULL
, nameW
, NULL
, &full_name
, win32
)) goto not_found
;
1266 TRACE("found %s = %s\n",
1267 full_name
.long_name
, debugstr_w(full_name
.short_name
) );
1268 WideCharToMultiByte(CP_ACP
, 0, full_name
.short_name
, -1,
1269 ofs
->szPathName
, sizeof(ofs
->szPathName
), NULL
, NULL
);
1271 if (mode
& OF_DELETE
)
1273 handle
= FILE_CreateFile( full_name
.long_name
, GENERIC_READ
|GENERIC_WRITE
, 0,
1274 NULL
, OPEN_EXISTING
, 0, 0, TRUE
,
1275 GetDriveTypeW( full_name
.short_name
) );
1276 if (!handle
) goto error
;
1277 CloseHandle( handle
);
1278 if (unlink( full_name
.long_name
) == -1) goto not_found
;
1279 TRACE("(%s): OF_DELETE return = OK\n", name
);
1283 handle
= FILE_CreateFile( full_name
.long_name
, access
, sharing
,
1284 NULL
, OPEN_EXISTING
, 0, 0,
1285 DRIVE_GetFlags(full_name
.drive
) & DRIVE_FAIL_READ_ONLY
,
1286 GetDriveTypeW( full_name
.short_name
) );
1287 if (!handle
) goto not_found
;
1289 GetFileTime( handle
, NULL
, NULL
, &filetime
);
1290 FileTimeToDosDateTime( &filetime
, &filedatetime
[0], &filedatetime
[1] );
1291 if ((mode
& OF_VERIFY
) && (mode
& OF_REOPEN
))
1293 if (ofs
->Reserved1
!= filedatetime
[0] || ofs
->Reserved2
!= filedatetime
[1] )
1295 CloseHandle( handle
);
1296 WARN("(%s): OF_VERIFY failed\n", name
);
1297 /* FIXME: what error here? */
1298 SetLastError( ERROR_FILE_NOT_FOUND
);
1302 ofs
->Reserved1
= filedatetime
[0];
1303 ofs
->Reserved2
= filedatetime
[1];
1305 success
: /* We get here if the open was successful */
1306 TRACE("(%s): OK, return = %p\n", name
, handle
);
1309 hFileRet
= (HFILE
)handle
;
1310 if (mode
& OF_EXIST
) /* Return the handle, but close it first */
1311 CloseHandle( handle
);
1315 hFileRet
= Win32HandleToDosFileHandle( handle
);
1316 if (hFileRet
== HFILE_ERROR16
) goto error
;
1317 if (mode
& OF_EXIST
) /* Return the handle, but close it first */
1318 _lclose16( hFileRet
);
1322 not_found
: /* We get here if the file does not exist */
1323 WARN("'%s' not found or sharing violation\n", name
);
1324 SetLastError( ERROR_FILE_NOT_FOUND
);
1327 error
: /* We get here if there was an error opening the file */
1328 ofs
->nErrCode
= GetLastError();
1329 WARN("(%s): return = HFILE_ERROR error= %d\n",
1330 name
,ofs
->nErrCode
);
1335 /***********************************************************************
1336 * OpenFile (KERNEL.74)
1337 * OpenFileEx (KERNEL.360)
1339 HFILE16 WINAPI
OpenFile16( LPCSTR name
, OFSTRUCT
*ofs
, UINT16 mode
)
1341 return FILE_DoOpenFile( name
, ofs
, mode
, FALSE
);
1345 /***********************************************************************
1346 * OpenFile (KERNEL32.@)
1348 HFILE WINAPI
OpenFile( LPCSTR name
, OFSTRUCT
*ofs
, UINT mode
)
1350 return FILE_DoOpenFile( name
, ofs
, mode
, TRUE
);
1354 /***********************************************************************
1355 * FILE_InitProcessDosHandles
1357 * Allocates the default DOS handles for a process. Called either by
1358 * Win32HandleToDosFileHandle below or by the DOSVM stuff.
1360 static void FILE_InitProcessDosHandles( void )
1362 HANDLE cp
= GetCurrentProcess();
1363 DuplicateHandle(cp
, GetStdHandle(STD_INPUT_HANDLE
), cp
, &dos_handles
[0],
1364 0, TRUE
, DUPLICATE_SAME_ACCESS
);
1365 DuplicateHandle(cp
, GetStdHandle(STD_OUTPUT_HANDLE
), cp
, &dos_handles
[1],
1366 0, TRUE
, DUPLICATE_SAME_ACCESS
);
1367 DuplicateHandle(cp
, GetStdHandle(STD_ERROR_HANDLE
), cp
, &dos_handles
[2],
1368 0, TRUE
, DUPLICATE_SAME_ACCESS
);
1369 DuplicateHandle(cp
, GetStdHandle(STD_ERROR_HANDLE
), cp
, &dos_handles
[3],
1370 0, TRUE
, DUPLICATE_SAME_ACCESS
);
1371 DuplicateHandle(cp
, GetStdHandle(STD_ERROR_HANDLE
), cp
, &dos_handles
[4],
1372 0, TRUE
, DUPLICATE_SAME_ACCESS
);
1375 /***********************************************************************
1376 * Win32HandleToDosFileHandle (KERNEL32.21)
1378 * Allocate a DOS handle for a Win32 handle. The Win32 handle is no
1379 * longer valid after this function (even on failure).
1381 * Note: this is not exactly right, since on Win95 the Win32 handles
1382 * are on top of DOS handles and we do it the other way
1383 * around. Should be good enough though.
1385 HFILE WINAPI
Win32HandleToDosFileHandle( HANDLE handle
)
1389 if (!handle
|| (handle
== INVALID_HANDLE_VALUE
))
1392 for (i
= 5; i
< DOS_TABLE_SIZE
; i
++)
1393 if (!dos_handles
[i
])
1395 dos_handles
[i
] = handle
;
1396 TRACE("Got %d for h32 %p\n", i
, handle
);
1399 CloseHandle( handle
);
1400 SetLastError( ERROR_TOO_MANY_OPEN_FILES
);
1405 /***********************************************************************
1406 * DosFileHandleToWin32Handle (KERNEL32.20)
1408 * Return the Win32 handle for a DOS handle.
1410 * Note: this is not exactly right, since on Win95 the Win32 handles
1411 * are on top of DOS handles and we do it the other way
1412 * around. Should be good enough though.
1414 HANDLE WINAPI
DosFileHandleToWin32Handle( HFILE handle
)
1416 HFILE16 hfile
= (HFILE16
)handle
;
1417 if (hfile
< 5 && !dos_handles
[hfile
]) FILE_InitProcessDosHandles();
1418 if ((hfile
>= DOS_TABLE_SIZE
) || !dos_handles
[hfile
])
1420 SetLastError( ERROR_INVALID_HANDLE
);
1421 return INVALID_HANDLE_VALUE
;
1423 return dos_handles
[hfile
];
1427 /***********************************************************************
1428 * DisposeLZ32Handle (KERNEL32.22)
1430 * Note: this is not entirely correct, we should only close the
1431 * 32-bit handle and not the 16-bit one, but we cannot do
1432 * this because of the way our DOS handles are implemented.
1433 * It shouldn't break anything though.
1435 void WINAPI
DisposeLZ32Handle( HANDLE handle
)
1439 if (!handle
|| (handle
== INVALID_HANDLE_VALUE
)) return;
1441 for (i
= 5; i
< DOS_TABLE_SIZE
; i
++)
1442 if (dos_handles
[i
] == handle
)
1445 CloseHandle( handle
);
1451 /***********************************************************************
1454 * dup2() function for DOS handles.
1456 HFILE16
FILE_Dup2( HFILE16 hFile1
, HFILE16 hFile2
)
1460 if (hFile1
< 5 && !dos_handles
[hFile1
]) FILE_InitProcessDosHandles();
1462 if ((hFile1
>= DOS_TABLE_SIZE
) || (hFile2
>= DOS_TABLE_SIZE
) || !dos_handles
[hFile1
])
1464 SetLastError( ERROR_INVALID_HANDLE
);
1465 return HFILE_ERROR16
;
1467 if (!DuplicateHandle( GetCurrentProcess(), dos_handles
[hFile1
],
1468 GetCurrentProcess(), &new_handle
,
1469 0, FALSE
, DUPLICATE_SAME_ACCESS
))
1470 return HFILE_ERROR16
;
1471 if (dos_handles
[hFile2
]) CloseHandle( dos_handles
[hFile2
] );
1472 dos_handles
[hFile2
] = new_handle
;
1477 /***********************************************************************
1478 * _lclose (KERNEL.81)
1480 HFILE16 WINAPI
_lclose16( HFILE16 hFile
)
1482 if ((hFile
>= DOS_TABLE_SIZE
) || !dos_handles
[hFile
])
1484 SetLastError( ERROR_INVALID_HANDLE
);
1485 return HFILE_ERROR16
;
1487 TRACE("%d (handle32=%p)\n", hFile
, dos_handles
[hFile
] );
1488 CloseHandle( dos_handles
[hFile
] );
1489 dos_handles
[hFile
] = 0;
1494 /******************************************************************
1495 * FILE_ReadWriteApc (internal)
1499 static void WINAPI
FILE_ReadWriteApc(void* apc_user
, PIO_STATUS_BLOCK io_status
, ULONG len
)
1501 LPOVERLAPPED_COMPLETION_ROUTINE cr
= (LPOVERLAPPED_COMPLETION_ROUTINE
)apc_user
;
1503 cr(RtlNtStatusToDosError(io_status
->u
.Status
), len
, (LPOVERLAPPED
)io_status
);
1506 /***********************************************************************
1507 * ReadFileEx (KERNEL32.@)
1509 BOOL WINAPI
ReadFileEx(HANDLE hFile
, LPVOID buffer
, DWORD bytesToRead
,
1510 LPOVERLAPPED overlapped
,
1511 LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine
)
1513 LARGE_INTEGER offset
;
1515 PIO_STATUS_BLOCK io_status
;
1519 SetLastError(ERROR_INVALID_PARAMETER
);
1523 offset
.s
.LowPart
= overlapped
->Offset
;
1524 offset
.s
.HighPart
= overlapped
->OffsetHigh
;
1525 io_status
= (PIO_STATUS_BLOCK
)overlapped
;
1526 io_status
->u
.Status
= STATUS_PENDING
;
1528 status
= NtReadFile(hFile
, NULL
, FILE_ReadWriteApc
, lpCompletionRoutine
,
1529 io_status
, buffer
, bytesToRead
, &offset
, NULL
);
1533 SetLastError( RtlNtStatusToDosError(status
) );
1539 /***********************************************************************
1540 * ReadFile (KERNEL32.@)
1542 BOOL WINAPI
ReadFile( HANDLE hFile
, LPVOID buffer
, DWORD bytesToRead
,
1543 LPDWORD bytesRead
, LPOVERLAPPED overlapped
)
1545 LARGE_INTEGER offset
;
1546 PLARGE_INTEGER poffset
= NULL
;
1547 IO_STATUS_BLOCK iosb
;
1548 PIO_STATUS_BLOCK io_status
= &iosb
;
1552 TRACE("%p %p %ld %p %p\n", hFile
, buffer
, bytesToRead
,
1553 bytesRead
, overlapped
);
1555 if (bytesRead
) *bytesRead
= 0; /* Do this before anything else */
1556 if (!bytesToRead
) return TRUE
;
1558 if (IsBadReadPtr(buffer
, bytesToRead
))
1560 SetLastError(ERROR_WRITE_FAULT
); /* FIXME */
1563 if (is_console_handle(hFile
))
1564 return FILE_ReadConsole(hFile
, buffer
, bytesToRead
, bytesRead
, NULL
);
1566 if (overlapped
!= NULL
)
1568 offset
.s
.LowPart
= overlapped
->Offset
;
1569 offset
.s
.HighPart
= overlapped
->OffsetHigh
;
1571 hEvent
= overlapped
->hEvent
;
1572 io_status
= (PIO_STATUS_BLOCK
)overlapped
;
1574 io_status
->u
.Status
= STATUS_PENDING
;
1575 io_status
->Information
= 0;
1577 status
= NtReadFile(hFile
, hEvent
, NULL
, NULL
, io_status
, buffer
, bytesToRead
, poffset
, NULL
);
1579 if (status
!= STATUS_PENDING
&& bytesRead
)
1580 *bytesRead
= io_status
->Information
;
1582 if (status
&& status
!= STATUS_END_OF_FILE
)
1584 SetLastError( RtlNtStatusToDosError(status
) );
1591 /***********************************************************************
1592 * WriteFileEx (KERNEL32.@)
1594 BOOL WINAPI
WriteFileEx(HANDLE hFile
, LPCVOID buffer
, DWORD bytesToWrite
,
1595 LPOVERLAPPED overlapped
,
1596 LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine
)
1598 LARGE_INTEGER offset
;
1600 PIO_STATUS_BLOCK io_status
;
1602 TRACE("%p %p %ld %p %p\n",
1603 hFile
, buffer
, bytesToWrite
, overlapped
, lpCompletionRoutine
);
1605 if (overlapped
== NULL
)
1607 SetLastError(ERROR_INVALID_PARAMETER
);
1610 offset
.s
.LowPart
= overlapped
->Offset
;
1611 offset
.s
.HighPart
= overlapped
->OffsetHigh
;
1613 io_status
= (PIO_STATUS_BLOCK
)overlapped
;
1614 io_status
->u
.Status
= STATUS_PENDING
;
1616 status
= NtWriteFile(hFile
, NULL
, FILE_ReadWriteApc
, lpCompletionRoutine
,
1617 io_status
, buffer
, bytesToWrite
, &offset
, NULL
);
1619 if (status
) SetLastError( RtlNtStatusToDosError(status
) );
1623 /***********************************************************************
1624 * WriteFile (KERNEL32.@)
1626 BOOL WINAPI
WriteFile( HANDLE hFile
, LPCVOID buffer
, DWORD bytesToWrite
,
1627 LPDWORD bytesWritten
, LPOVERLAPPED overlapped
)
1629 HANDLE hEvent
= NULL
;
1630 LARGE_INTEGER offset
;
1631 PLARGE_INTEGER poffset
= NULL
;
1633 IO_STATUS_BLOCK iosb
;
1634 PIO_STATUS_BLOCK piosb
= &iosb
;
1636 TRACE("%p %p %ld %p %p\n",
1637 hFile
, buffer
, bytesToWrite
, bytesWritten
, overlapped
);
1639 if (is_console_handle(hFile
))
1640 return FILE_WriteConsole(hFile
, buffer
, bytesToWrite
, bytesWritten
, NULL
);
1642 if (IsBadReadPtr(buffer
, bytesToWrite
))
1644 SetLastError(ERROR_READ_FAULT
); /* FIXME */
1650 offset
.s
.LowPart
= overlapped
->Offset
;
1651 offset
.s
.HighPart
= overlapped
->OffsetHigh
;
1653 hEvent
= overlapped
->hEvent
;
1654 piosb
= (PIO_STATUS_BLOCK
)overlapped
;
1656 piosb
->u
.Status
= STATUS_PENDING
;
1657 piosb
->Information
= 0;
1659 status
= NtWriteFile(hFile
, hEvent
, NULL
, NULL
, piosb
,
1660 buffer
, bytesToWrite
, poffset
, NULL
);
1663 SetLastError( RtlNtStatusToDosError(status
) );
1666 if (bytesWritten
) *bytesWritten
= piosb
->Information
;
1672 /***********************************************************************
1673 * SetFilePointer (KERNEL32.@)
1675 DWORD WINAPI
SetFilePointer( HANDLE hFile
, LONG distance
, LONG
*highword
,
1678 DWORD ret
= INVALID_SET_FILE_POINTER
;
1680 TRACE("handle %p offset %ld high %ld origin %ld\n",
1681 hFile
, distance
, highword
?*highword
:0, method
);
1683 SERVER_START_REQ( set_file_pointer
)
1685 req
->handle
= hFile
;
1686 req
->low
= distance
;
1687 req
->high
= highword
? *highword
: (distance
>= 0) ? 0 : -1;
1688 /* FIXME: assumes 1:1 mapping between Windows and Unix seek constants */
1689 req
->whence
= method
;
1691 if (!wine_server_call_err( req
))
1693 ret
= reply
->new_low
;
1694 if (highword
) *highword
= reply
->new_high
;
1702 /*************************************************************************
1703 * SetHandleCount (KERNEL32.@)
1705 UINT WINAPI
SetHandleCount( UINT count
)
1707 return min( 256, count
);
1711 /**************************************************************************
1712 * SetEndOfFile (KERNEL32.@)
1714 BOOL WINAPI
SetEndOfFile( HANDLE hFile
)
1717 SERVER_START_REQ( truncate_file
)
1719 req
->handle
= hFile
;
1720 ret
= !wine_server_call_err( req
);
1727 /***********************************************************************
1728 * DeleteFileW (KERNEL32.@)
1730 BOOL WINAPI
DeleteFileW( LPCWSTR path
)
1732 DOS_FULL_NAME full_name
;
1735 TRACE("%s\n", debugstr_w(path
) );
1736 if (!path
|| !*path
)
1738 SetLastError(ERROR_PATH_NOT_FOUND
);
1741 if (DOSFS_GetDevice( path
))
1743 WARN("cannot remove DOS device %s!\n", debugstr_w(path
));
1744 SetLastError( ERROR_FILE_NOT_FOUND
);
1748 if (!DOSFS_GetFullName( path
, TRUE
, &full_name
)) return FALSE
;
1750 /* check if we are allowed to delete the source */
1751 hFile
= FILE_CreateFile( full_name
.long_name
, GENERIC_READ
|GENERIC_WRITE
, 0,
1752 NULL
, OPEN_EXISTING
, 0, 0, TRUE
,
1753 GetDriveTypeW( full_name
.short_name
) );
1754 if (!hFile
) return FALSE
;
1756 if (unlink( full_name
.long_name
) == -1)
1767 /***********************************************************************
1768 * DeleteFileA (KERNEL32.@)
1770 BOOL WINAPI
DeleteFileA( LPCSTR path
)
1772 UNICODE_STRING pathW
;
1777 SetLastError(ERROR_INVALID_PARAMETER
);
1781 if (RtlCreateUnicodeStringFromAsciiz(&pathW
, path
))
1783 ret
= DeleteFileW(pathW
.Buffer
);
1784 RtlFreeUnicodeString(&pathW
);
1787 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
1792 /***********************************************************************
1793 * GetFileType (KERNEL32.@)
1795 DWORD WINAPI
GetFileType( HANDLE hFile
)
1797 DWORD ret
= FILE_TYPE_UNKNOWN
;
1799 if (is_console_handle( hFile
))
1800 return FILE_TYPE_CHAR
;
1802 SERVER_START_REQ( get_file_info
)
1804 req
->handle
= hFile
;
1805 if (!wine_server_call_err( req
)) ret
= reply
->type
;
1812 /* check if a file name is for an executable file (.exe or .com) */
1813 inline static BOOL
is_executable( const char *name
)
1815 int len
= strlen(name
);
1817 if (len
< 4) return FALSE
;
1818 return (!strcasecmp( name
+ len
- 4, ".exe" ) ||
1819 !strcasecmp( name
+ len
- 4, ".com" ));
1823 /***********************************************************************
1824 * FILE_AddBootRenameEntry
1826 * Adds an entry to the registry that is loaded when windows boots and
1827 * checks if there are some files to be removed or renamed/moved.
1828 * <fn1> has to be valid and <fn2> may be NULL. If both pointers are
1829 * non-NULL then the file is moved, otherwise it is deleted. The
1830 * entry of the registrykey is always appended with two zero
1831 * terminated strings. If <fn2> is NULL then the second entry is
1832 * simply a single 0-byte. Otherwise the second filename goes
1833 * there. The entries are prepended with \??\ before the path and the
1834 * second filename gets also a '!' as the first character if
1835 * MOVEFILE_REPLACE_EXISTING is set. After the final string another
1836 * 0-byte follows to indicate the end of the strings.
1838 * \??\D:\test\file1[0]
1839 * !\??\D:\test\file1_renamed[0]
1840 * \??\D:\Test|delete[0]
1841 * [0] <- file is to be deleted, second string empty
1842 * \??\D:\test\file2[0]
1843 * !\??\D:\test\file2_renamed[0]
1844 * [0] <- indicates end of strings
1847 * \??\D:\test\file1[0]
1848 * !\??\D:\test\file1_renamed[0]
1849 * \??\D:\Test|delete[0]
1850 * [0] <- file is to be deleted, second string empty
1851 * [0] <- indicates end of strings
1854 static BOOL
FILE_AddBootRenameEntry( LPCWSTR fn1
, LPCWSTR fn2
, DWORD flags
)
1856 static const WCHAR PreString
[] = {'\\','?','?','\\',0};
1857 static const WCHAR ValueName
[] = {'P','e','n','d','i','n','g',
1858 'F','i','l','e','R','e','n','a','m','e',
1859 'O','p','e','r','a','t','i','o','n','s',0};
1860 static const WCHAR SessionW
[] = {'M','a','c','h','i','n','e','\\',
1861 'S','y','s','t','e','m','\\',
1862 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
1863 'C','o','n','t','r','o','l','\\',
1864 'S','e','s','s','i','o','n',' ','M','a','n','a','g','e','r',0};
1865 static const int info_size
= FIELD_OFFSET( KEY_VALUE_PARTIAL_INFORMATION
, Data
);
1867 OBJECT_ATTRIBUTES attr
;
1868 UNICODE_STRING nameW
;
1869 KEY_VALUE_PARTIAL_INFORMATION
*info
;
1872 DWORD len0
, len1
, len2
;
1874 BYTE
*Buffer
= NULL
;
1877 attr
.Length
= sizeof(attr
);
1878 attr
.RootDirectory
= 0;
1879 attr
.ObjectName
= &nameW
;
1880 attr
.Attributes
= 0;
1881 attr
.SecurityDescriptor
= NULL
;
1882 attr
.SecurityQualityOfService
= NULL
;
1883 RtlInitUnicodeString( &nameW
, SessionW
);
1885 if (NtCreateKey( &Reboot
, KEY_ALL_ACCESS
, &attr
, 0, NULL
, 0, NULL
) != STATUS_SUCCESS
)
1887 WARN("Error creating key for reboot managment [%s]\n",
1888 "SYSTEM\\CurrentControlSet\\Control\\Session Manager");
1892 len0
= strlenW(PreString
);
1893 len1
= strlenW(fn1
) + len0
+ 1;
1896 len2
= strlenW(fn2
) + len0
+ 1;
1897 if (flags
& MOVEFILE_REPLACE_EXISTING
) len2
++; /* Plus 1 because of the leading '!' */
1899 else len2
= 1; /* minimum is the 0 characters for the empty second string */
1901 /* convert characters to bytes */
1902 len0
*= sizeof(WCHAR
);
1903 len1
*= sizeof(WCHAR
);
1904 len2
*= sizeof(WCHAR
);
1906 RtlInitUnicodeString( &nameW
, ValueName
);
1908 /* First we check if the key exists and if so how many bytes it already contains. */
1909 if (NtQueryValueKey( Reboot
, &nameW
, KeyValuePartialInformation
,
1910 NULL
, 0, &DataSize
) == STATUS_BUFFER_OVERFLOW
)
1912 if (!(Buffer
= HeapAlloc( GetProcessHeap(), 0, DataSize
+ len1
+ len2
+ sizeof(WCHAR
) )))
1914 if (NtQueryValueKey( Reboot
, &nameW
, KeyValuePartialInformation
,
1915 Buffer
, DataSize
, &DataSize
)) goto Quit
;
1916 info
= (KEY_VALUE_PARTIAL_INFORMATION
*)Buffer
;
1917 if (info
->Type
!= REG_MULTI_SZ
) goto Quit
;
1918 if (DataSize
> sizeof(info
)) DataSize
-= sizeof(WCHAR
); /* remove terminating null (will be added back later) */
1922 DataSize
= info_size
;
1923 if (!(Buffer
= HeapAlloc( GetProcessHeap(), 0, DataSize
+ len1
+ len2
+ sizeof(WCHAR
) )))
1927 p
= (WCHAR
*)(Buffer
+ DataSize
);
1928 strcpyW( p
, PreString
);
1933 p
= (WCHAR
*)(Buffer
+ DataSize
);
1934 if (flags
& MOVEFILE_REPLACE_EXISTING
)
1936 strcpyW( p
, PreString
);
1942 p
= (WCHAR
*)(Buffer
+ DataSize
);
1944 DataSize
+= sizeof(WCHAR
);
1947 /* add final null */
1948 p
= (WCHAR
*)(Buffer
+ DataSize
);
1950 DataSize
+= sizeof(WCHAR
);
1952 rc
= !NtSetValueKey(Reboot
, &nameW
, 0, REG_MULTI_SZ
, Buffer
+ info_size
, DataSize
- info_size
);
1955 if (Reboot
) NtClose(Reboot
);
1956 if (Buffer
) HeapFree( GetProcessHeap(), 0, Buffer
);
1961 /**************************************************************************
1962 * MoveFileExW (KERNEL32.@)
1964 BOOL WINAPI
MoveFileExW( LPCWSTR fn1
, LPCWSTR fn2
, DWORD flag
)
1966 DOS_FULL_NAME full_name1
, full_name2
;
1968 DWORD attr
= INVALID_FILE_ATTRIBUTES
;
1970 TRACE("(%s,%s,%04lx)\n", debugstr_w(fn1
), debugstr_w(fn2
), flag
);
1972 /* FIXME: <Gerhard W. Gruber>sparhawk@gmx.at
1973 In case of W9x and lesser this function should return 120 (ERROR_CALL_NOT_IMPLEMENTED)
1974 to be really compatible. Most programs wont have any problems though. In case
1975 you encounter one, this is what you should return here. I don't know what's up
1976 with NT 3.5. Is this function available there or not?
1977 Does anybody really care about 3.5? :)
1980 /* Filename1 has to be always set to a valid path. Filename2 may be NULL
1981 if the source file has to be deleted.
1984 SetLastError(ERROR_INVALID_PARAMETER
);
1988 /* This function has to be run through in order to process the name properly.
1989 If the BOOTDELAY flag is set, the file doesn't need to exist though. At least
1990 that is the behaviour on NT 4.0. The operation accepts the filenames as
1991 they are given but it can't reply with a reasonable returncode. Success
1992 means in that case success for entering the values into the registry.
1994 if(!DOSFS_GetFullName( fn1
, TRUE
, &full_name1
))
1996 if(!(flag
& MOVEFILE_DELAY_UNTIL_REBOOT
))
2000 if (fn2
) /* !fn2 means delete fn1 */
2002 if (DOSFS_GetFullName( fn2
, TRUE
, &full_name2
))
2004 if(!(flag
& MOVEFILE_DELAY_UNTIL_REBOOT
))
2006 /* target exists, check if we may overwrite */
2007 if (!(flag
& MOVEFILE_REPLACE_EXISTING
))
2009 SetLastError( ERROR_FILE_EXISTS
);
2016 if (!DOSFS_GetFullName( fn2
, FALSE
, &full_name2
))
2018 if(!(flag
& MOVEFILE_DELAY_UNTIL_REBOOT
))
2023 /* Source name and target path are valid */
2025 if (flag
& MOVEFILE_DELAY_UNTIL_REBOOT
)
2027 return FILE_AddBootRenameEntry( fn1
, fn2
, flag
);
2030 attr
= GetFileAttributesW( fn1
);
2031 if ( attr
== INVALID_FILE_ATTRIBUTES
) return FALSE
;
2033 /* check if we are allowed to rename the source */
2034 hFile
= FILE_CreateFile( full_name1
.long_name
, 0, 0,
2035 NULL
, OPEN_EXISTING
, 0, 0, TRUE
,
2036 GetDriveTypeW( full_name1
.short_name
) );
2039 if (GetLastError() != ERROR_ACCESS_DENIED
) return FALSE
;
2040 if ( !(attr
& FILE_ATTRIBUTE_DIRECTORY
) ) return FALSE
;
2041 /* if it's a directory we can continue */
2043 else CloseHandle(hFile
);
2045 /* check, if we are allowed to delete the destination,
2046 ** (but the file not being there is fine) */
2047 hFile
= FILE_CreateFile( full_name2
.long_name
, GENERIC_READ
|GENERIC_WRITE
, 0,
2048 NULL
, OPEN_EXISTING
, 0, 0, TRUE
,
2049 GetDriveTypeW( full_name2
.short_name
) );
2050 if(!hFile
&& GetLastError() != ERROR_FILE_NOT_FOUND
) return FALSE
;
2053 if (full_name1
.drive
!= full_name2
.drive
)
2055 if (!(flag
& MOVEFILE_COPY_ALLOWED
))
2057 SetLastError( ERROR_NOT_SAME_DEVICE
);
2060 else if ( attr
& FILE_ATTRIBUTE_DIRECTORY
)
2062 /* Strange, but that's what Windows returns */
2063 SetLastError ( ERROR_ACCESS_DENIED
);
2067 if (rename( full_name1
.long_name
, full_name2
.long_name
) == -1)
2068 /* Try copy/delete unless it's a directory. */
2069 /* FIXME: This does not handle the (unlikely) case that the two locations
2070 are on the same Wine drive, but on different Unix file systems. */
2072 if ( attr
& FILE_ATTRIBUTE_DIRECTORY
)
2079 if ( ! CopyFileW( fn1
, fn2
, !(flag
& MOVEFILE_REPLACE_EXISTING
) ))
2081 if ( ! DeleteFileW ( fn1
) )
2085 if (is_executable( full_name1
.long_name
) != is_executable( full_name2
.long_name
))
2088 if (stat( full_name2
.long_name
, &fstat
) != -1)
2090 if (is_executable( full_name2
.long_name
))
2091 /* set executable bit where read bit is set */
2092 fstat
.st_mode
|= (fstat
.st_mode
& 0444) >> 2;
2094 fstat
.st_mode
&= ~0111;
2095 chmod( full_name2
.long_name
, fstat
.st_mode
);
2100 else /* fn2 == NULL means delete source */
2102 if (flag
& MOVEFILE_DELAY_UNTIL_REBOOT
)
2104 if (flag
& MOVEFILE_COPY_ALLOWED
) {
2105 WARN("Illegal flag\n");
2106 SetLastError( ERROR_GEN_FAILURE
);
2110 return FILE_AddBootRenameEntry( fn1
, NULL
, flag
);
2113 if (unlink( full_name1
.long_name
) == -1)
2118 return TRUE
; /* successfully deleted */
2122 /**************************************************************************
2123 * MoveFileExA (KERNEL32.@)
2125 BOOL WINAPI
MoveFileExA( LPCSTR fn1
, LPCSTR fn2
, DWORD flag
)
2127 UNICODE_STRING fn1W
, fn2W
;
2132 SetLastError(ERROR_INVALID_PARAMETER
);
2136 RtlCreateUnicodeStringFromAsciiz(&fn1W
, fn1
);
2137 if (fn2
) RtlCreateUnicodeStringFromAsciiz(&fn2W
, fn2
);
2138 else fn2W
.Buffer
= NULL
;
2140 ret
= MoveFileExW( fn1W
.Buffer
, fn2W
.Buffer
, flag
);
2142 RtlFreeUnicodeString(&fn1W
);
2143 RtlFreeUnicodeString(&fn2W
);
2148 /**************************************************************************
2149 * MoveFileW (KERNEL32.@)
2151 * Move file or directory
2153 BOOL WINAPI
MoveFileW( LPCWSTR fn1
, LPCWSTR fn2
)
2155 return MoveFileExW( fn1
, fn2
, MOVEFILE_COPY_ALLOWED
);
2159 /**************************************************************************
2160 * MoveFileA (KERNEL32.@)
2162 BOOL WINAPI
MoveFileA( LPCSTR fn1
, LPCSTR fn2
)
2164 return MoveFileExA( fn1
, fn2
, MOVEFILE_COPY_ALLOWED
);
2168 /**************************************************************************
2169 * CopyFileW (KERNEL32.@)
2171 BOOL WINAPI
CopyFileW( LPCWSTR source
, LPCWSTR dest
, BOOL fail_if_exists
)
2174 BY_HANDLE_FILE_INFORMATION info
;
2179 if (!source
|| !dest
)
2181 SetLastError(ERROR_INVALID_PARAMETER
);
2185 TRACE("%s -> %s\n", debugstr_w(source
), debugstr_w(dest
));
2187 if ((h1
= CreateFileW(source
, GENERIC_READ
, FILE_SHARE_READ
| FILE_SHARE_WRITE
,
2188 NULL
, OPEN_EXISTING
, 0, 0)) == INVALID_HANDLE_VALUE
)
2190 WARN("Unable to open source %s\n", debugstr_w(source
));
2194 if (!GetFileInformationByHandle( h1
, &info
))
2196 WARN("GetFileInformationByHandle returned error for %s\n", debugstr_w(source
));
2201 if ((h2
= CreateFileW( dest
, GENERIC_WRITE
, FILE_SHARE_READ
| FILE_SHARE_WRITE
, NULL
,
2202 fail_if_exists
? CREATE_NEW
: CREATE_ALWAYS
,
2203 info
.dwFileAttributes
, h1
)) == INVALID_HANDLE_VALUE
)
2205 WARN("Unable to open dest %s\n", debugstr_w(dest
));
2210 while (ReadFile( h1
, buffer
, sizeof(buffer
), &count
, NULL
) && count
)
2216 if (!WriteFile( h2
, p
, count
, &res
, NULL
) || !res
) goto done
;
2229 /**************************************************************************
2230 * CopyFileA (KERNEL32.@)
2232 BOOL WINAPI
CopyFileA( LPCSTR source
, LPCSTR dest
, BOOL fail_if_exists
)
2234 UNICODE_STRING sourceW
, destW
;
2237 if (!source
|| !dest
)
2239 SetLastError(ERROR_INVALID_PARAMETER
);
2243 RtlCreateUnicodeStringFromAsciiz(&sourceW
, source
);
2244 RtlCreateUnicodeStringFromAsciiz(&destW
, dest
);
2246 ret
= CopyFileW(sourceW
.Buffer
, destW
.Buffer
, fail_if_exists
);
2248 RtlFreeUnicodeString(&sourceW
);
2249 RtlFreeUnicodeString(&destW
);
2254 /**************************************************************************
2255 * CopyFileExW (KERNEL32.@)
2257 * This implementation ignores most of the extra parameters passed-in into
2258 * the "ex" version of the method and calls the CopyFile method.
2259 * It will have to be fixed eventually.
2261 BOOL WINAPI
CopyFileExW(LPCWSTR sourceFilename
, LPCWSTR destFilename
,
2262 LPPROGRESS_ROUTINE progressRoutine
, LPVOID appData
,
2263 LPBOOL cancelFlagPointer
, DWORD copyFlags
)
2266 * Interpret the only flag that CopyFile can interpret.
2268 return CopyFileW(sourceFilename
, destFilename
, (copyFlags
& COPY_FILE_FAIL_IF_EXISTS
) != 0);
2272 /**************************************************************************
2273 * CopyFileExA (KERNEL32.@)
2275 BOOL WINAPI
CopyFileExA(LPCSTR sourceFilename
, LPCSTR destFilename
,
2276 LPPROGRESS_ROUTINE progressRoutine
, LPVOID appData
,
2277 LPBOOL cancelFlagPointer
, DWORD copyFlags
)
2279 UNICODE_STRING sourceW
, destW
;
2282 if (!sourceFilename
|| !destFilename
)
2284 SetLastError(ERROR_INVALID_PARAMETER
);
2288 RtlCreateUnicodeStringFromAsciiz(&sourceW
, sourceFilename
);
2289 RtlCreateUnicodeStringFromAsciiz(&destW
, destFilename
);
2291 ret
= CopyFileExW(sourceW
.Buffer
, destW
.Buffer
, progressRoutine
, appData
,
2292 cancelFlagPointer
, copyFlags
);
2294 RtlFreeUnicodeString(&sourceW
);
2295 RtlFreeUnicodeString(&destW
);
2300 /***********************************************************************
2301 * SetFileTime (KERNEL32.@)
2303 BOOL WINAPI
SetFileTime( HANDLE hFile
,
2304 const FILETIME
*lpCreationTime
,
2305 const FILETIME
*lpLastAccessTime
,
2306 const FILETIME
*lpLastWriteTime
)
2309 SERVER_START_REQ( set_file_time
)
2311 req
->handle
= hFile
;
2312 if (lpLastAccessTime
)
2313 RtlTimeToSecondsSince1970( (PLARGE_INTEGER
) lpLastAccessTime
, (DWORD
*)&req
->access_time
);
2315 req
->access_time
= 0; /* FIXME */
2316 if (lpLastWriteTime
)
2317 RtlTimeToSecondsSince1970( (PLARGE_INTEGER
) lpLastWriteTime
, (DWORD
*)&req
->write_time
);
2319 req
->write_time
= 0; /* FIXME */
2320 ret
= !wine_server_call_err( req
);
2327 /**************************************************************************
2328 * GetFileAttributesExW (KERNEL32.@)
2330 BOOL WINAPI
GetFileAttributesExW(
2331 LPCWSTR lpFileName
, GET_FILEEX_INFO_LEVELS fInfoLevelId
,
2332 LPVOID lpFileInformation
)
2334 DOS_FULL_NAME full_name
;
2335 BY_HANDLE_FILE_INFORMATION info
;
2337 if (!lpFileName
|| !lpFileInformation
)
2339 SetLastError(ERROR_INVALID_PARAMETER
);
2343 if (fInfoLevelId
== GetFileExInfoStandard
) {
2344 LPWIN32_FILE_ATTRIBUTE_DATA lpFad
=
2345 (LPWIN32_FILE_ATTRIBUTE_DATA
) lpFileInformation
;
2346 if (!DOSFS_GetFullName( lpFileName
, TRUE
, &full_name
)) return FALSE
;
2347 if (!FILE_Stat( full_name
.long_name
, &info
, NULL
)) return FALSE
;
2349 lpFad
->dwFileAttributes
= info
.dwFileAttributes
;
2350 lpFad
->ftCreationTime
= info
.ftCreationTime
;
2351 lpFad
->ftLastAccessTime
= info
.ftLastAccessTime
;
2352 lpFad
->ftLastWriteTime
= info
.ftLastWriteTime
;
2353 lpFad
->nFileSizeHigh
= info
.nFileSizeHigh
;
2354 lpFad
->nFileSizeLow
= info
.nFileSizeLow
;
2357 FIXME("invalid info level %d!\n", fInfoLevelId
);
2365 /**************************************************************************
2366 * GetFileAttributesExA (KERNEL32.@)
2368 BOOL WINAPI
GetFileAttributesExA(
2369 LPCSTR filename
, GET_FILEEX_INFO_LEVELS fInfoLevelId
,
2370 LPVOID lpFileInformation
)
2372 UNICODE_STRING filenameW
;
2375 if (!filename
|| !lpFileInformation
)
2377 SetLastError(ERROR_INVALID_PARAMETER
);
2381 if (RtlCreateUnicodeStringFromAsciiz(&filenameW
, filename
))
2383 ret
= GetFileAttributesExW(filenameW
.Buffer
, fInfoLevelId
, lpFileInformation
);
2384 RtlFreeUnicodeString(&filenameW
);
2387 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);