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"
36 #ifdef HAVE_SYS_ERRNO_H
37 #include <sys/errno.h>
39 #include <sys/types.h>
41 #ifdef HAVE_SYS_MMAN_H
44 #ifdef HAVE_SYS_TIME_H
45 # include <sys/time.h>
47 #ifdef HAVE_SYS_POLL_H
48 # include <sys/poll.h>
58 #define NONAMELESSUNION
59 #define NONAMELESSSTRUCT
64 #include "wine/winbase16.h"
65 #include "wine/server.h"
72 #include "../kernel/kernel_private.h"
75 #include "wine/unicode.h"
76 #include "wine/debug.h"
78 WINE_DEFAULT_DEBUG_CHANNEL(file
);
80 #if defined(MAP_ANONYMOUS) && !defined(MAP_ANON)
81 #define MAP_ANON MAP_ANONYMOUS
84 HANDLE dos_handles
[DOS_TABLE_SIZE
];
87 /***********************************************************************
90 * Convert OF_* mode into flags for CreateFile.
92 void FILE_ConvertOFMode( INT mode
, DWORD
*access
, DWORD
*sharing
)
96 case OF_READ
: *access
= GENERIC_READ
; break;
97 case OF_WRITE
: *access
= GENERIC_WRITE
; break;
98 case OF_READWRITE
: *access
= GENERIC_READ
| GENERIC_WRITE
; break;
99 default: *access
= 0; break;
103 case OF_SHARE_EXCLUSIVE
: *sharing
= 0; break;
104 case OF_SHARE_DENY_WRITE
: *sharing
= FILE_SHARE_READ
; break;
105 case OF_SHARE_DENY_READ
: *sharing
= FILE_SHARE_WRITE
; break;
106 case OF_SHARE_DENY_NONE
:
107 case OF_SHARE_COMPAT
:
108 default: *sharing
= FILE_SHARE_READ
| FILE_SHARE_WRITE
; break;
113 /***********************************************************************
116 * locale-independent case conversion for file I/O
118 int FILE_strcasecmp( const char *str1
, const char *str2
)
121 for ( ; ; str1
++, str2
++)
122 if ((ret
= FILE_toupper(*str1
) - FILE_toupper(*str2
)) || !*str1
) break;
127 /***********************************************************************
130 * locale-independent case conversion for file I/O
132 int FILE_strncasecmp( const char *str1
, const char *str2
, int len
)
135 for ( ; len
> 0; len
--, str1
++, str2
++)
136 if ((ret
= FILE_toupper(*str1
) - FILE_toupper(*str2
)) || !*str1
) break;
141 /***********************************************************************
144 * Set the DOS error code from errno.
146 void FILE_SetDosError(void)
148 int save_errno
= errno
; /* errno gets overwritten by printf */
150 TRACE("errno = %d %s\n", errno
, strerror(errno
));
154 SetLastError( ERROR_SHARING_VIOLATION
);
157 SetLastError( ERROR_INVALID_HANDLE
);
160 SetLastError( ERROR_HANDLE_DISK_FULL
);
165 SetLastError( ERROR_ACCESS_DENIED
);
168 SetLastError( ERROR_LOCK_VIOLATION
);
171 SetLastError( ERROR_FILE_NOT_FOUND
);
174 SetLastError( ERROR_CANNOT_MAKE
);
178 SetLastError( ERROR_NO_MORE_FILES
);
181 SetLastError( ERROR_FILE_EXISTS
);
185 SetLastError( ERROR_SEEK
);
188 SetLastError( ERROR_DIR_NOT_EMPTY
);
191 SetLastError( ERROR_BAD_FORMAT
);
194 WARN("unknown file error: %s\n", strerror(save_errno
) );
195 SetLastError( ERROR_GEN_FAILURE
);
202 /***********************************************************************
203 * FILE_GetUnixHandleType
205 * Retrieve the Unix handle corresponding to a file handle.
206 * Returns -1 on failure.
208 static int FILE_GetUnixHandleType( HANDLE handle
, DWORD access
, enum fd_type
*type
, int *flags_ptr
)
210 int ret
, flags
, fd
= -1;
212 ret
= wine_server_handle_to_fd( handle
, access
, &fd
, type
, &flags
);
213 if (flags_ptr
) *flags_ptr
= flags
;
214 if (ret
) SetLastError( RtlNtStatusToDosError(ret
) );
215 else if (((access
& GENERIC_READ
) && (flags
& FD_FLAG_RECV_SHUTDOWN
)) ||
216 ((access
& GENERIC_WRITE
) && (flags
& FD_FLAG_SEND_SHUTDOWN
)))
219 SetLastError ( ERROR_PIPE_NOT_CONNECTED
);
225 /***********************************************************************
228 * Retrieve the Unix handle corresponding to a file handle.
229 * Returns -1 on failure.
231 int FILE_GetUnixHandle( HANDLE handle
, DWORD access
)
233 return FILE_GetUnixHandleType( handle
, access
, NULL
, NULL
);
236 /******************************************************************
237 * OpenConsoleW (KERNEL32.@)
240 * Open a handle to the current process console.
241 * Returns INVALID_HANDLE_VALUE on failure.
243 HANDLE WINAPI
OpenConsoleW(LPCWSTR name
, DWORD access
, LPSECURITY_ATTRIBUTES sa
,
246 static const WCHAR coninW
[] = {'C','O','N','I','N','$',0};
247 static const WCHAR conoutW
[] = {'C','O','N','O','U','T','$',0};
251 if (strcmpW(coninW
, name
) == 0)
253 else if (strcmpW(conoutW
, name
) == 0)
257 SetLastError(ERROR_INVALID_NAME
);
258 return INVALID_HANDLE_VALUE
;
260 if (creation
!= OPEN_EXISTING
)
262 SetLastError(ERROR_INVALID_PARAMETER
);
263 return INVALID_HANDLE_VALUE
;
266 SERVER_START_REQ( open_console
)
269 req
->access
= access
;
270 req
->share
= FILE_SHARE_READ
| FILE_SHARE_WRITE
;
271 req
->inherit
= (sa
&& (sa
->nLength
>=sizeof(*sa
)) && sa
->bInheritHandle
);
273 wine_server_call_err( req
);
277 return ret
? console_handle_map(ret
) : INVALID_HANDLE_VALUE
;
280 /******************************************************************
281 * VerifyConsoleIoHandle (KERNEL32.@)
285 BOOL WINAPI
VerifyConsoleIoHandle(HANDLE handle
)
289 if (!is_console_handle(handle
)) return FALSE
;
290 SERVER_START_REQ(get_console_mode
)
292 req
->handle
= console_handle_unmap(handle
);
293 ret
= !wine_server_call_err( req
);
299 /******************************************************************
300 * DuplicateConsoleHandle (KERNEL32.@)
304 HANDLE WINAPI
DuplicateConsoleHandle(HANDLE handle
, DWORD access
, BOOL inherit
,
309 if (!is_console_handle(handle
) ||
310 !DuplicateHandle(GetCurrentProcess(), console_handle_unmap(handle
),
311 GetCurrentProcess(), &ret
, access
, inherit
, options
))
312 return INVALID_HANDLE_VALUE
;
313 return console_handle_map(ret
);
316 /******************************************************************
317 * CloseConsoleHandle (KERNEL32.@)
321 BOOL WINAPI
CloseConsoleHandle(HANDLE handle
)
323 if (!is_console_handle(handle
))
325 SetLastError(ERROR_INVALID_PARAMETER
);
328 return CloseHandle(console_handle_unmap(handle
));
331 /******************************************************************
332 * GetConsoleInputWaitHandle (KERNEL32.@)
336 HANDLE WINAPI
GetConsoleInputWaitHandle(void)
338 static HANDLE console_wait_event
;
340 /* FIXME: this is not thread safe */
341 if (!console_wait_event
)
343 SERVER_START_REQ(get_console_wait_event
)
345 if (!wine_server_call_err( req
)) console_wait_event
= reply
->handle
;
349 return console_wait_event
;
354 /* FIXME: those routines defined as pointers are needed, because this file is
355 * currently compiled into NTDLL whereas it belongs to kernel32.
356 * this shall go away once all the DLL separation process is done
358 typedef BOOL (WINAPI
* pRW
)(HANDLE
, const void*, DWORD
, DWORD
*, void*);
360 static BOOL
FILE_ReadConsole(HANDLE hCon
, void* buf
, DWORD nb
, DWORD
* nr
, void* p
)
362 static HANDLE hKernel
/* = 0 */;
363 static pRW pReadConsole
/* = 0 */;
365 if ((!hKernel
&& !(hKernel
= LoadLibraryA("kernel32"))) ||
367 !(pReadConsole
= GetProcAddress(hKernel
, "ReadConsoleA"))))
372 return (pReadConsole
)(hCon
, buf
, nb
, nr
, p
);
375 static BOOL
FILE_WriteConsole(HANDLE hCon
, const void* buf
, DWORD nb
, DWORD
* nr
, void* p
)
377 static HANDLE hKernel
/* = 0 */;
378 static pRW pWriteConsole
/* = 0 */;
380 if ((!hKernel
&& !(hKernel
= LoadLibraryA("kernel32"))) ||
382 !(pWriteConsole
= GetProcAddress(hKernel
, "WriteConsoleA"))))
387 return (pWriteConsole
)(hCon
, buf
, nb
, nr
, p
);
391 /***********************************************************************
394 * Implementation of CreateFile. Takes a Unix path name.
395 * Returns 0 on failure.
397 HANDLE
FILE_CreateFile( LPCSTR filename
, DWORD access
, DWORD sharing
,
398 LPSECURITY_ATTRIBUTES sa
, DWORD creation
,
399 DWORD attributes
, HANDLE
template, BOOL fail_read_only
,
407 SERVER_START_REQ( create_file
)
409 req
->access
= access
;
410 req
->inherit
= (sa
&& (sa
->nLength
>=sizeof(*sa
)) && sa
->bInheritHandle
);
411 req
->sharing
= sharing
;
412 req
->create
= creation
;
413 req
->attrs
= attributes
;
414 req
->drive_type
= drive_type
;
415 wine_server_add_data( req
, filename
, strlen(filename
) );
417 err
= wine_server_call( req
);
422 /* If write access failed, retry without GENERIC_WRITE */
424 if (!ret
&& !fail_read_only
&& (access
& GENERIC_WRITE
))
426 if ((err
== STATUS_MEDIA_WRITE_PROTECTED
) || (err
== STATUS_ACCESS_DENIED
))
428 TRACE("Write access failed for file '%s', trying without "
429 "write access\n", filename
);
430 access
&= ~GENERIC_WRITE
;
437 /* In the case file creation was rejected due to CREATE_NEW flag
438 * was specified and file with that name already exists, correct
439 * last error is ERROR_FILE_EXISTS and not ERROR_ALREADY_EXISTS.
440 * Note: RtlNtStatusToDosError is not the subject to blame here.
442 if (err
== STATUS_OBJECT_NAME_COLLISION
)
443 SetLastError( ERROR_FILE_EXISTS
);
445 SetLastError( RtlNtStatusToDosError(err
) );
448 if (!ret
) WARN("Unable to create file '%s' (GLE %ld)\n", filename
, GetLastError());
454 /***********************************************************************
457 * Same as FILE_CreateFile but for a device
458 * Returns 0 on failure.
460 HANDLE
FILE_CreateDevice( int client_id
, DWORD access
, LPSECURITY_ATTRIBUTES sa
)
463 SERVER_START_REQ( create_device
)
465 req
->access
= access
;
466 req
->inherit
= (sa
&& (sa
->nLength
>=sizeof(*sa
)) && sa
->bInheritHandle
);
469 wine_server_call_err( req
);
476 static HANDLE
FILE_OpenPipe(LPCWSTR name
, DWORD access
, LPSECURITY_ATTRIBUTES sa
)
481 if (name
&& (len
= strlenW(name
)) > MAX_PATH
)
483 SetLastError( ERROR_FILENAME_EXCED_RANGE
);
486 SERVER_START_REQ( open_named_pipe
)
488 req
->access
= access
;
489 req
->inherit
= (sa
&& (sa
->nLength
>=sizeof(*sa
)) && sa
->bInheritHandle
);
491 wine_server_add_data( req
, name
, len
* sizeof(WCHAR
) );
492 wine_server_call_err( req
);
496 TRACE("Returned %p\n",ret
);
500 /*************************************************************************
501 * CreateFileW [KERNEL32.@] Creates or opens a file or other object
503 * Creates or opens an object, and returns a handle that can be used to
504 * access that object.
508 * filename [in] pointer to filename to be accessed
509 * access [in] access mode requested
510 * sharing [in] share mode
511 * sa [in] pointer to security attributes
512 * creation [in] how to create the file
513 * attributes [in] attributes for newly created file
514 * template [in] handle to file with extended attributes to copy
517 * Success: Open handle to specified file
518 * Failure: INVALID_HANDLE_VALUE
521 * Should call SetLastError() on failure.
525 * Doesn't support character devices, template files, or a
526 * lot of the 'attributes' flags yet.
528 HANDLE WINAPI
CreateFileW( LPCWSTR filename
, DWORD access
, DWORD sharing
,
529 LPSECURITY_ATTRIBUTES sa
, DWORD creation
,
530 DWORD attributes
, HANDLE
template )
532 DOS_FULL_NAME full_name
;
534 static const WCHAR bkslashes_with_question_markW
[] = {'\\','\\','?','\\',0};
535 static const WCHAR bkslashes_with_dotW
[] = {'\\','\\','.','\\',0};
536 static const WCHAR bkslashesW
[] = {'\\','\\',0};
537 static const WCHAR coninW
[] = {'C','O','N','I','N','$',0};
538 static const WCHAR conoutW
[] = {'C','O','N','O','U','T','$',0};
542 SetLastError( ERROR_INVALID_PARAMETER
);
543 return INVALID_HANDLE_VALUE
;
545 TRACE("%s %s%s%s%s%s%s%s attributes 0x%lx\n", debugstr_w(filename
),
546 ((access
& GENERIC_READ
)==GENERIC_READ
)?"GENERIC_READ ":"",
547 ((access
& GENERIC_WRITE
)==GENERIC_WRITE
)?"GENERIC_WRITE ":"",
548 (!access
)?"QUERY_ACCESS ":"",
549 ((sharing
& FILE_SHARE_READ
)==FILE_SHARE_READ
)?"FILE_SHARE_READ ":"",
550 ((sharing
& FILE_SHARE_WRITE
)==FILE_SHARE_WRITE
)?"FILE_SHARE_WRITE ":"",
551 ((sharing
& FILE_SHARE_DELETE
)==FILE_SHARE_DELETE
)?"FILE_SHARE_DELETE ":"",
552 (creation
==CREATE_NEW
)?"CREATE_NEW":
553 (creation
==CREATE_ALWAYS
)?"CREATE_ALWAYS ":
554 (creation
==OPEN_EXISTING
)?"OPEN_EXISTING ":
555 (creation
==OPEN_ALWAYS
)?"OPEN_ALWAYS ":
556 (creation
==TRUNCATE_EXISTING
)?"TRUNCATE_EXISTING ":"", attributes
);
558 /* If the name starts with '\\?\', ignore the first 4 chars. */
559 if (!strncmpW(filename
, bkslashes_with_question_markW
, 4))
561 static const WCHAR uncW
[] = {'U','N','C','\\',0};
563 if (!strncmpiW(filename
, uncW
, 4))
565 FIXME("UNC name (%s) not supported.\n", debugstr_w(filename
) );
566 SetLastError( ERROR_PATH_NOT_FOUND
);
567 return INVALID_HANDLE_VALUE
;
571 if (!strncmpW(filename
, bkslashes_with_dotW
, 4))
573 static const WCHAR pipeW
[] = {'P','I','P','E','\\',0};
574 if(!strncmpiW(filename
+ 4, pipeW
, 5))
576 TRACE("Opening a pipe: %s\n", debugstr_w(filename
));
577 ret
= FILE_OpenPipe( filename
, access
, sa
);
580 else if (isalphaW(filename
[4]) && filename
[5] == ':' && filename
[6] == '\0')
582 ret
= FILE_CreateDevice( (toupperW(filename
[4]) - 'A') | 0x20000, access
, sa
);
585 else if (!DOSFS_GetDevice( filename
))
587 ret
= DEVICE_Open( filename
+4, access
, sa
);
591 filename
+=4; /* fall into DOSFS_Device case below */
594 /* If the name still starts with '\\', it's a UNC name. */
595 if (!strncmpW(filename
, bkslashesW
, 2))
597 ret
= SMB_CreateFileW(filename
, access
, sharing
, sa
, creation
, attributes
, template );
601 /* If the name contains a DOS wild card (* or ?), do no create a file */
602 if(strchrW(filename
, '*') || strchrW(filename
, '?'))
604 SetLastError(ERROR_BAD_PATHNAME
);
605 return INVALID_HANDLE_VALUE
;
608 /* Open a console for CONIN$ or CONOUT$ */
609 if (!strcmpiW(filename
, coninW
) || !strcmpiW(filename
, conoutW
))
611 ret
= OpenConsoleW(filename
, access
, sa
, creation
);
615 if (DOSFS_GetDevice( filename
))
617 TRACE("opening device %s\n", debugstr_w(filename
) );
619 if (!(ret
= DOSFS_OpenDevice( filename
, access
, attributes
, sa
)))
621 /* Do not silence this please. It is a critical error. -MM */
622 ERR("Couldn't open device %s!\n", debugstr_w(filename
));
623 SetLastError( ERROR_FILE_NOT_FOUND
);
628 /* check for filename, don't check for last entry if creating */
629 if (!DOSFS_GetFullName( filename
,
630 (creation
== OPEN_EXISTING
) ||
631 (creation
== TRUNCATE_EXISTING
),
633 WARN("Unable to get full filename from %s (GLE %ld)\n",
634 debugstr_w(filename
), GetLastError());
635 return INVALID_HANDLE_VALUE
;
638 ret
= FILE_CreateFile( full_name
.long_name
, access
, sharing
,
639 sa
, creation
, attributes
, template,
640 DRIVE_GetFlags(full_name
.drive
) & DRIVE_FAIL_READ_ONLY
,
641 GetDriveTypeW( full_name
.short_name
) );
643 if (!ret
) ret
= INVALID_HANDLE_VALUE
;
644 TRACE("returning %p\n", ret
);
650 /*************************************************************************
651 * CreateFileA (KERNEL32.@)
653 HANDLE WINAPI
CreateFileA( LPCSTR filename
, DWORD access
, DWORD sharing
,
654 LPSECURITY_ATTRIBUTES sa
, DWORD creation
,
655 DWORD attributes
, HANDLE
template)
657 UNICODE_STRING filenameW
;
658 HANDLE ret
= INVALID_HANDLE_VALUE
;
662 SetLastError( ERROR_INVALID_PARAMETER
);
663 return INVALID_HANDLE_VALUE
;
666 if (RtlCreateUnicodeStringFromAsciiz(&filenameW
, filename
))
668 ret
= CreateFileW(filenameW
.Buffer
, access
, sharing
, sa
, creation
,
669 attributes
, template);
670 RtlFreeUnicodeString(&filenameW
);
673 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
678 /***********************************************************************
681 * Fill a file information from a struct stat.
683 static void FILE_FillInfo( struct stat
*st
, BY_HANDLE_FILE_INFORMATION
*info
)
685 if (S_ISDIR(st
->st_mode
))
686 info
->dwFileAttributes
= FILE_ATTRIBUTE_DIRECTORY
;
688 info
->dwFileAttributes
= FILE_ATTRIBUTE_ARCHIVE
;
689 if (!(st
->st_mode
& S_IWUSR
))
690 info
->dwFileAttributes
|= FILE_ATTRIBUTE_READONLY
;
692 RtlSecondsSince1970ToTime( st
->st_mtime
, (LARGE_INTEGER
*)&info
->ftCreationTime
);
693 RtlSecondsSince1970ToTime( st
->st_mtime
, (LARGE_INTEGER
*)&info
->ftLastWriteTime
);
694 RtlSecondsSince1970ToTime( st
->st_atime
, (LARGE_INTEGER
*)&info
->ftLastAccessTime
);
696 info
->dwVolumeSerialNumber
= 0; /* FIXME */
697 info
->nFileSizeHigh
= 0;
698 info
->nFileSizeLow
= 0;
699 if (!S_ISDIR(st
->st_mode
)) {
700 info
->nFileSizeHigh
= st
->st_size
>> 32;
701 info
->nFileSizeLow
= st
->st_size
& 0xffffffff;
703 info
->nNumberOfLinks
= st
->st_nlink
;
704 info
->nFileIndexHigh
= 0;
705 info
->nFileIndexLow
= st
->st_ino
;
709 /***********************************************************************
712 * Stat a Unix path name. Return TRUE if OK.
714 BOOL
FILE_Stat( LPCSTR unixName
, BY_HANDLE_FILE_INFORMATION
*info
, BOOL
*is_symlink_ptr
)
720 if (lstat( unixName
, &st
) == -1)
725 is_symlink
= S_ISLNK(st
.st_mode
);
728 /* do a "real" stat to find out
729 about the type of the symlink destination */
730 if (stat( unixName
, &st
) == -1)
737 /* fill in the information we gathered so far */
738 FILE_FillInfo( &st
, info
);
740 /* and now see if this is a hidden file, based on the name */
741 p
= strrchr( unixName
, '/');
742 p
= p
? p
+ 1 : unixName
;
743 if (*p
== '.' && *(p
+1) && (*(p
+1) != '.' || *(p
+2)))
745 static const WCHAR wineW
[] = {'w','i','n','e',0};
746 static const WCHAR ShowDotFilesW
[] = {'S','h','o','w','D','o','t','F','i','l','e','s',0};
747 static int show_dot_files
= -1;
748 if (show_dot_files
== -1)
749 show_dot_files
= PROFILE_GetWineIniBool(wineW
, ShowDotFilesW
, 0);
751 info
->dwFileAttributes
|= FILE_ATTRIBUTE_HIDDEN
;
753 if (is_symlink_ptr
) *is_symlink_ptr
= is_symlink
;
758 /***********************************************************************
759 * GetFileInformationByHandle (KERNEL32.@)
761 DWORD WINAPI
GetFileInformationByHandle( HANDLE hFile
,
762 BY_HANDLE_FILE_INFORMATION
*info
)
767 TRACE("%p\n", hFile
);
769 SERVER_START_REQ( get_file_info
)
772 if ((ret
= !wine_server_call_err( req
)))
774 /* FIXME: which file types are supported ?
775 * Serial ports (FILE_TYPE_CHAR) are not,
776 * and MSDN also says that pipes are not supported.
777 * FILE_TYPE_REMOTE seems to be supported according to
778 * MSDN q234741.txt */
779 if ((reply
->type
== FILE_TYPE_DISK
) || (reply
->type
== FILE_TYPE_REMOTE
))
781 RtlSecondsSince1970ToTime( reply
->write_time
, (LARGE_INTEGER
*)&info
->ftCreationTime
);
782 RtlSecondsSince1970ToTime( reply
->write_time
, (LARGE_INTEGER
*)&info
->ftLastWriteTime
);
783 RtlSecondsSince1970ToTime( reply
->access_time
, (LARGE_INTEGER
*)&info
->ftLastAccessTime
);
784 info
->dwFileAttributes
= reply
->attr
;
785 info
->dwVolumeSerialNumber
= reply
->serial
;
786 info
->nFileSizeHigh
= reply
->size_high
;
787 info
->nFileSizeLow
= reply
->size_low
;
788 info
->nNumberOfLinks
= reply
->links
;
789 info
->nFileIndexHigh
= reply
->index_high
;
790 info
->nFileIndexLow
= reply
->index_low
;
794 SetLastError(ERROR_NOT_SUPPORTED
);
804 /**************************************************************************
805 * GetFileAttributesW (KERNEL32.@)
807 DWORD WINAPI
GetFileAttributesW( LPCWSTR name
)
809 DOS_FULL_NAME full_name
;
810 BY_HANDLE_FILE_INFORMATION info
;
814 SetLastError( ERROR_INVALID_PARAMETER
);
817 if (!DOSFS_GetFullName( name
, TRUE
, &full_name
) )
819 if (!FILE_Stat( full_name
.long_name
, &info
, NULL
)) return -1;
820 return info
.dwFileAttributes
;
824 /**************************************************************************
825 * GetFileAttributesA (KERNEL32.@)
827 DWORD WINAPI
GetFileAttributesA( LPCSTR name
)
829 UNICODE_STRING nameW
;
830 DWORD ret
= (DWORD
)-1;
834 SetLastError( ERROR_INVALID_PARAMETER
);
838 if (RtlCreateUnicodeStringFromAsciiz(&nameW
, name
))
840 ret
= GetFileAttributesW(nameW
.Buffer
);
841 RtlFreeUnicodeString(&nameW
);
844 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
849 /**************************************************************************
850 * SetFileAttributesW (KERNEL32.@)
852 BOOL WINAPI
SetFileAttributesW(LPCWSTR lpFileName
, DWORD attributes
)
855 DOS_FULL_NAME full_name
;
859 SetLastError( ERROR_INVALID_PARAMETER
);
863 TRACE("(%s,%lx)\n", debugstr_w(lpFileName
), attributes
);
865 if (!DOSFS_GetFullName( lpFileName
, TRUE
, &full_name
))
868 if(stat(full_name
.long_name
,&buf
)==-1)
873 if (attributes
& FILE_ATTRIBUTE_READONLY
)
875 if(S_ISDIR(buf
.st_mode
))
877 WARN("FILE_ATTRIBUTE_READONLY ignored for directory.\n");
879 buf
.st_mode
&= ~0222; /* octal!, clear write permission bits */
880 attributes
&= ~FILE_ATTRIBUTE_READONLY
;
884 /* add write permission */
885 buf
.st_mode
|= (0600 | ((buf
.st_mode
& 044) >> 1)) & (~FILE_umask
);
887 if (attributes
& FILE_ATTRIBUTE_DIRECTORY
)
889 if (!S_ISDIR(buf
.st_mode
))
890 FIXME("SetFileAttributes expected the file %s to be a directory\n",
891 debugstr_w(lpFileName
));
892 attributes
&= ~FILE_ATTRIBUTE_DIRECTORY
;
894 attributes
&= ~(FILE_ATTRIBUTE_NORMAL
|FILE_ATTRIBUTE_ARCHIVE
|FILE_ATTRIBUTE_HIDDEN
|FILE_ATTRIBUTE_SYSTEM
);
896 FIXME("(%s):%lx attribute(s) not implemented.\n", debugstr_w(lpFileName
), attributes
);
897 if (-1==chmod(full_name
.long_name
,buf
.st_mode
))
899 if (GetDriveTypeW(lpFileName
) == DRIVE_CDROM
)
901 SetLastError( ERROR_ACCESS_DENIED
);
906 * FIXME: We don't return FALSE here because of differences between
907 * Linux and Windows privileges. Under Linux only the owner of
908 * the file is allowed to change file attributes. Under Windows,
909 * applications expect that if you can write to a file, you can also
910 * change its attributes (see GENERIC_WRITE). We could try to be
911 * clever here but that would break multi-user installations where
912 * users share read-only DLLs. This is because some installers like
913 * to change attributes of already installed DLLs.
915 FIXME("Couldn't set file attributes for existing file \"%s\".\n"
916 "Check permissions or set VFAT \"quiet\" mount flag\n", full_name
.long_name
);
922 /**************************************************************************
923 * SetFileAttributesA (KERNEL32.@)
925 BOOL WINAPI
SetFileAttributesA(LPCSTR lpFileName
, DWORD attributes
)
927 UNICODE_STRING filenameW
;
932 SetLastError( ERROR_INVALID_PARAMETER
);
936 if (RtlCreateUnicodeStringFromAsciiz(&filenameW
, lpFileName
))
938 ret
= SetFileAttributesW(filenameW
.Buffer
, attributes
);
939 RtlFreeUnicodeString(&filenameW
);
942 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
947 /***********************************************************************
948 * GetFileTime (KERNEL32.@)
950 BOOL WINAPI
GetFileTime( HANDLE hFile
, FILETIME
*lpCreationTime
,
951 FILETIME
*lpLastAccessTime
,
952 FILETIME
*lpLastWriteTime
)
954 BY_HANDLE_FILE_INFORMATION info
;
955 if (!GetFileInformationByHandle( hFile
, &info
)) return FALSE
;
956 if (lpCreationTime
) *lpCreationTime
= info
.ftCreationTime
;
957 if (lpLastAccessTime
) *lpLastAccessTime
= info
.ftLastAccessTime
;
958 if (lpLastWriteTime
) *lpLastWriteTime
= info
.ftLastWriteTime
;
963 /***********************************************************************
964 * FILE_GetTempFileName : utility for GetTempFileName
966 static UINT
FILE_GetTempFileName( LPCWSTR path
, LPCWSTR prefix
, UINT unique
,
969 static UINT unique_temp
;
970 DOS_FULL_NAME full_name
;
976 if ( !path
|| !prefix
|| !buffer
)
978 SetLastError( ERROR_INVALID_PARAMETER
);
982 if (!unique_temp
) unique_temp
= time(NULL
) & 0xffff;
983 num
= unique
? (unique
& 0xffff) : (unique_temp
++ & 0xffff);
985 strcpyW( buffer
, path
);
986 p
= buffer
+ strlenW(buffer
);
988 /* add a \, if there isn't one and path is more than just the drive letter ... */
989 if ( !((strlenW(buffer
) == 2) && (buffer
[1] == ':'))
990 && ((p
== buffer
) || (p
[-1] != '\\'))) *p
++ = '\\';
992 for (i
= 3; (i
> 0) && (*prefix
); i
--) *p
++ = *prefix
++;
994 sprintf( buf
, "%04x.tmp", num
);
995 MultiByteToWideChar(CP_ACP
, 0, buf
, -1, p
, 20);
997 /* Now try to create it */
1003 HANDLE handle
= CreateFileW( buffer
, GENERIC_WRITE
, 0, NULL
,
1004 CREATE_NEW
, FILE_ATTRIBUTE_NORMAL
, 0 );
1005 if (handle
!= INVALID_HANDLE_VALUE
)
1006 { /* We created it */
1007 TRACE("created %s\n", debugstr_w(buffer
) );
1008 CloseHandle( handle
);
1011 if (GetLastError() != ERROR_FILE_EXISTS
&&
1012 GetLastError() != ERROR_SHARING_VIOLATION
)
1013 break; /* No need to go on */
1015 sprintf( buf
, "%04x.tmp", num
);
1016 MultiByteToWideChar(CP_ACP
, 0, buf
, -1, p
, 20);
1017 } while (num
!= (unique
& 0xffff));
1020 /* Get the full path name */
1022 if (DOSFS_GetFullName( buffer
, FALSE
, &full_name
))
1025 /* Check if we have write access in the directory */
1026 if ((slash
= strrchr( full_name
.long_name
, '/' ))) *slash
= '\0';
1027 if (access( full_name
.long_name
, W_OK
) == -1)
1028 WARN("returns %s, which doesn't seem to be writeable.\n",
1029 debugstr_w(buffer
) );
1031 TRACE("returning %s\n", debugstr_w(buffer
) );
1032 return unique
? unique
: num
;
1036 /***********************************************************************
1037 * GetTempFileNameA (KERNEL32.@)
1039 UINT WINAPI
GetTempFileNameA( LPCSTR path
, LPCSTR prefix
, UINT unique
,
1042 UNICODE_STRING pathW
, prefixW
;
1043 WCHAR bufferW
[MAX_PATH
];
1046 if ( !path
|| !prefix
|| !buffer
)
1048 SetLastError( ERROR_INVALID_PARAMETER
);
1052 RtlCreateUnicodeStringFromAsciiz(&pathW
, path
);
1053 RtlCreateUnicodeStringFromAsciiz(&prefixW
, prefix
);
1055 ret
= GetTempFileNameW(pathW
.Buffer
, prefixW
.Buffer
, unique
, bufferW
);
1057 WideCharToMultiByte(CP_ACP
, 0, bufferW
, -1, buffer
, MAX_PATH
, NULL
, NULL
);
1059 RtlFreeUnicodeString(&pathW
);
1060 RtlFreeUnicodeString(&prefixW
);
1064 /***********************************************************************
1065 * GetTempFileNameW (KERNEL32.@)
1067 UINT WINAPI
GetTempFileNameW( LPCWSTR path
, LPCWSTR prefix
, UINT unique
,
1070 return FILE_GetTempFileName( path
, prefix
, unique
, buffer
);
1074 /***********************************************************************
1077 * Implementation of OpenFile16() and OpenFile32().
1079 static HFILE
FILE_DoOpenFile( LPCSTR name
, OFSTRUCT
*ofs
, UINT mode
, BOOL win32
)
1084 WORD filedatetime
[2];
1085 DOS_FULL_NAME full_name
;
1086 DWORD access
, sharing
;
1088 WCHAR buffer
[MAX_PATH
];
1091 if (!ofs
) return HFILE_ERROR
;
1093 TRACE("%s %s %s %s%s%s%s%s%s%s%s%s\n",name
,
1094 ((mode
& 0x3 )==OF_READ
)?"OF_READ":
1095 ((mode
& 0x3 )==OF_WRITE
)?"OF_WRITE":
1096 ((mode
& 0x3 )==OF_READWRITE
)?"OF_READWRITE":"unknown",
1097 ((mode
& 0x70 )==OF_SHARE_COMPAT
)?"OF_SHARE_COMPAT":
1098 ((mode
& 0x70 )==OF_SHARE_DENY_NONE
)?"OF_SHARE_DENY_NONE":
1099 ((mode
& 0x70 )==OF_SHARE_DENY_READ
)?"OF_SHARE_DENY_READ":
1100 ((mode
& 0x70 )==OF_SHARE_DENY_WRITE
)?"OF_SHARE_DENY_WRITE":
1101 ((mode
& 0x70 )==OF_SHARE_EXCLUSIVE
)?"OF_SHARE_EXCLUSIVE":"unknown",
1102 ((mode
& OF_PARSE
)==OF_PARSE
)?"OF_PARSE ":"",
1103 ((mode
& OF_DELETE
)==OF_DELETE
)?"OF_DELETE ":"",
1104 ((mode
& OF_VERIFY
)==OF_VERIFY
)?"OF_VERIFY ":"",
1105 ((mode
& OF_SEARCH
)==OF_SEARCH
)?"OF_SEARCH ":"",
1106 ((mode
& OF_CANCEL
)==OF_CANCEL
)?"OF_CANCEL ":"",
1107 ((mode
& OF_CREATE
)==OF_CREATE
)?"OF_CREATE ":"",
1108 ((mode
& OF_PROMPT
)==OF_PROMPT
)?"OF_PROMPT ":"",
1109 ((mode
& OF_EXIST
)==OF_EXIST
)?"OF_EXIST ":"",
1110 ((mode
& OF_REOPEN
)==OF_REOPEN
)?"OF_REOPEN ":""
1114 ofs
->cBytes
= sizeof(OFSTRUCT
);
1116 if (mode
& OF_REOPEN
) name
= ofs
->szPathName
;
1119 ERR("called with `name' set to NULL ! Please debug.\n");
1123 TRACE("%s %04x\n", name
, mode
);
1125 /* the watcom 10.6 IDE relies on a valid path returned in ofs->szPathName
1126 Are there any cases where getting the path here is wrong?
1127 Uwe Bonnes 1997 Apr 2 */
1128 if (!GetFullPathNameA( name
, sizeof(ofs
->szPathName
),
1129 ofs
->szPathName
, NULL
)) goto error
;
1130 FILE_ConvertOFMode( mode
, &access
, &sharing
);
1132 /* OF_PARSE simply fills the structure */
1134 if (mode
& OF_PARSE
)
1136 ofs
->fFixedDisk
= (GetDriveType16( ofs
->szPathName
[0]-'A' )
1137 != DRIVE_REMOVABLE
);
1138 TRACE("(%s): OF_PARSE, res = '%s'\n",
1139 name
, ofs
->szPathName
);
1143 /* OF_CREATE is completely different from all other options, so
1146 if (mode
& OF_CREATE
)
1148 if ((handle
= CreateFileA( name
, GENERIC_READ
| GENERIC_WRITE
,
1149 sharing
, NULL
, CREATE_ALWAYS
,
1150 FILE_ATTRIBUTE_NORMAL
, 0 ))== INVALID_HANDLE_VALUE
)
1155 MultiByteToWideChar(CP_ACP
, 0, name
, -1, buffer
, MAX_PATH
);
1158 /* If OF_SEARCH is set, ignore the given path */
1160 if ((mode
& OF_SEARCH
) && !(mode
& OF_REOPEN
))
1162 /* First try the file name as is */
1163 if (DOSFS_GetFullName( nameW
, TRUE
, &full_name
)) goto found
;
1164 /* Now remove the path */
1165 if (nameW
[0] && (nameW
[1] == ':')) nameW
+= 2;
1166 if ((p
= strrchrW( nameW
, '\\' ))) nameW
= p
+ 1;
1167 if ((p
= strrchrW( nameW
, '/' ))) nameW
= p
+ 1;
1168 if (!nameW
[0]) goto not_found
;
1171 /* Now look for the file */
1173 if (!DIR_SearchPath( NULL
, nameW
, NULL
, &full_name
, win32
)) goto not_found
;
1176 TRACE("found %s = %s\n",
1177 full_name
.long_name
, debugstr_w(full_name
.short_name
) );
1178 WideCharToMultiByte(CP_ACP
, 0, full_name
.short_name
, -1,
1179 ofs
->szPathName
, sizeof(ofs
->szPathName
), NULL
, NULL
);
1181 if (mode
& OF_SHARE_EXCLUSIVE
)
1182 /* Some InstallShield version uses OF_SHARE_EXCLUSIVE
1183 on the file <tempdir>/_ins0432._mp to determine how
1184 far installation has proceeded.
1185 _ins0432._mp is an executable and while running the
1186 application expects the open with OF_SHARE_ to fail*/
1188 As our loader closes the files after loading the executable,
1189 we can't find the running executable with FILE_InUse.
1190 The loader should keep the file open, as Windows does that, too.
1193 char *last
= strrchr(full_name
.long_name
,'/');
1195 last
= full_name
.long_name
- 1;
1196 if (GetModuleHandle16(last
+1))
1198 TRACE("Denying shared open for %s\n",full_name
.long_name
);
1203 if (mode
& OF_DELETE
)
1205 if (unlink( full_name
.long_name
) == -1) goto not_found
;
1206 TRACE("(%s): OF_DELETE return = OK\n", name
);
1210 handle
= FILE_CreateFile( full_name
.long_name
, access
, sharing
,
1211 NULL
, OPEN_EXISTING
, 0, 0,
1212 DRIVE_GetFlags(full_name
.drive
) & DRIVE_FAIL_READ_ONLY
,
1213 GetDriveTypeW( full_name
.short_name
) );
1214 if (!handle
) goto not_found
;
1216 GetFileTime( handle
, NULL
, NULL
, &filetime
);
1217 FileTimeToDosDateTime( &filetime
, &filedatetime
[0], &filedatetime
[1] );
1218 if ((mode
& OF_VERIFY
) && (mode
& OF_REOPEN
))
1220 if (ofs
->Reserved1
!= filedatetime
[0] || ofs
->Reserved2
!= filedatetime
[1] )
1222 CloseHandle( handle
);
1223 WARN("(%s): OF_VERIFY failed\n", name
);
1224 /* FIXME: what error here? */
1225 SetLastError( ERROR_FILE_NOT_FOUND
);
1229 ofs
->Reserved1
= filedatetime
[0];
1230 ofs
->Reserved2
= filedatetime
[1];
1232 success
: /* We get here if the open was successful */
1233 TRACE("(%s): OK, return = %p\n", name
, handle
);
1236 hFileRet
= (HFILE
)handle
;
1237 if (mode
& OF_EXIST
) /* Return the handle, but close it first */
1238 CloseHandle( handle
);
1242 hFileRet
= Win32HandleToDosFileHandle( handle
);
1243 if (hFileRet
== HFILE_ERROR16
) goto error
;
1244 if (mode
& OF_EXIST
) /* Return the handle, but close it first */
1245 _lclose16( hFileRet
);
1249 not_found
: /* We get here if the file does not exist */
1250 WARN("'%s' not found or sharing violation\n", name
);
1251 SetLastError( ERROR_FILE_NOT_FOUND
);
1254 error
: /* We get here if there was an error opening the file */
1255 ofs
->nErrCode
= GetLastError();
1256 WARN("(%s): return = HFILE_ERROR error= %d\n",
1257 name
,ofs
->nErrCode
);
1262 /***********************************************************************
1263 * OpenFile (KERNEL.74)
1264 * OpenFileEx (KERNEL.360)
1266 HFILE16 WINAPI
OpenFile16( LPCSTR name
, OFSTRUCT
*ofs
, UINT16 mode
)
1268 return FILE_DoOpenFile( name
, ofs
, mode
, FALSE
);
1272 /***********************************************************************
1273 * OpenFile (KERNEL32.@)
1275 HFILE WINAPI
OpenFile( LPCSTR name
, OFSTRUCT
*ofs
, UINT mode
)
1277 return FILE_DoOpenFile( name
, ofs
, mode
, TRUE
);
1281 /***********************************************************************
1282 * FILE_InitProcessDosHandles
1284 * Allocates the default DOS handles for a process. Called either by
1285 * Win32HandleToDosFileHandle below or by the DOSVM stuff.
1287 static void FILE_InitProcessDosHandles( void )
1289 HANDLE cp
= GetCurrentProcess();
1290 DuplicateHandle(cp
, GetStdHandle(STD_INPUT_HANDLE
), cp
, &dos_handles
[0],
1291 0, TRUE
, DUPLICATE_SAME_ACCESS
);
1292 DuplicateHandle(cp
, GetStdHandle(STD_OUTPUT_HANDLE
), cp
, &dos_handles
[1],
1293 0, TRUE
, DUPLICATE_SAME_ACCESS
);
1294 DuplicateHandle(cp
, GetStdHandle(STD_ERROR_HANDLE
), cp
, &dos_handles
[2],
1295 0, TRUE
, DUPLICATE_SAME_ACCESS
);
1296 DuplicateHandle(cp
, GetStdHandle(STD_ERROR_HANDLE
), cp
, &dos_handles
[3],
1297 0, TRUE
, DUPLICATE_SAME_ACCESS
);
1298 DuplicateHandle(cp
, GetStdHandle(STD_ERROR_HANDLE
), cp
, &dos_handles
[4],
1299 0, TRUE
, DUPLICATE_SAME_ACCESS
);
1302 /***********************************************************************
1303 * Win32HandleToDosFileHandle (KERNEL32.21)
1305 * Allocate a DOS handle for a Win32 handle. The Win32 handle is no
1306 * longer valid after this function (even on failure).
1308 * Note: this is not exactly right, since on Win95 the Win32 handles
1309 * are on top of DOS handles and we do it the other way
1310 * around. Should be good enough though.
1312 HFILE WINAPI
Win32HandleToDosFileHandle( HANDLE handle
)
1316 if (!handle
|| (handle
== INVALID_HANDLE_VALUE
))
1319 for (i
= 5; i
< DOS_TABLE_SIZE
; i
++)
1320 if (!dos_handles
[i
])
1322 dos_handles
[i
] = handle
;
1323 TRACE("Got %d for h32 %p\n", i
, handle
);
1326 CloseHandle( handle
);
1327 SetLastError( ERROR_TOO_MANY_OPEN_FILES
);
1332 /***********************************************************************
1333 * DosFileHandleToWin32Handle (KERNEL32.20)
1335 * Return the Win32 handle for a DOS handle.
1337 * Note: this is not exactly right, since on Win95 the Win32 handles
1338 * are on top of DOS handles and we do it the other way
1339 * around. Should be good enough though.
1341 HANDLE WINAPI
DosFileHandleToWin32Handle( HFILE handle
)
1343 HFILE16 hfile
= (HFILE16
)handle
;
1344 if (hfile
< 5 && !dos_handles
[hfile
]) FILE_InitProcessDosHandles();
1345 if ((hfile
>= DOS_TABLE_SIZE
) || !dos_handles
[hfile
])
1347 SetLastError( ERROR_INVALID_HANDLE
);
1348 return INVALID_HANDLE_VALUE
;
1350 return dos_handles
[hfile
];
1354 /***********************************************************************
1355 * DisposeLZ32Handle (KERNEL32.22)
1357 * Note: this is not entirely correct, we should only close the
1358 * 32-bit handle and not the 16-bit one, but we cannot do
1359 * this because of the way our DOS handles are implemented.
1360 * It shouldn't break anything though.
1362 void WINAPI
DisposeLZ32Handle( HANDLE handle
)
1366 if (!handle
|| (handle
== INVALID_HANDLE_VALUE
)) return;
1368 for (i
= 5; i
< DOS_TABLE_SIZE
; i
++)
1369 if (dos_handles
[i
] == handle
)
1372 CloseHandle( handle
);
1378 /***********************************************************************
1381 * dup2() function for DOS handles.
1383 HFILE16
FILE_Dup2( HFILE16 hFile1
, HFILE16 hFile2
)
1387 if (hFile1
< 5 && !dos_handles
[hFile1
]) FILE_InitProcessDosHandles();
1389 if ((hFile1
>= DOS_TABLE_SIZE
) || (hFile2
>= DOS_TABLE_SIZE
) || !dos_handles
[hFile1
])
1391 SetLastError( ERROR_INVALID_HANDLE
);
1392 return HFILE_ERROR16
;
1394 if (!DuplicateHandle( GetCurrentProcess(), dos_handles
[hFile1
],
1395 GetCurrentProcess(), &new_handle
,
1396 0, FALSE
, DUPLICATE_SAME_ACCESS
))
1397 return HFILE_ERROR16
;
1398 if (dos_handles
[hFile2
]) CloseHandle( dos_handles
[hFile2
] );
1399 dos_handles
[hFile2
] = new_handle
;
1404 /***********************************************************************
1405 * _lclose (KERNEL.81)
1407 HFILE16 WINAPI
_lclose16( HFILE16 hFile
)
1409 if ((hFile
>= DOS_TABLE_SIZE
) || !dos_handles
[hFile
])
1411 SetLastError( ERROR_INVALID_HANDLE
);
1412 return HFILE_ERROR16
;
1414 TRACE("%d (handle32=%p)\n", hFile
, dos_handles
[hFile
] );
1415 CloseHandle( dos_handles
[hFile
] );
1416 dos_handles
[hFile
] = 0;
1421 /******************************************************************
1422 * FILE_ReadWriteApc (internal)
1426 static void WINAPI
FILE_ReadWriteApc(void* apc_user
, PIO_STATUS_BLOCK io_status
, ULONG len
)
1428 LPOVERLAPPED_COMPLETION_ROUTINE cr
= (LPOVERLAPPED_COMPLETION_ROUTINE
)apc_user
;
1430 cr(RtlNtStatusToDosError(io_status
->u
.Status
), len
, (LPOVERLAPPED
)io_status
);
1433 /***********************************************************************
1434 * ReadFileEx (KERNEL32.@)
1436 BOOL WINAPI
ReadFileEx(HANDLE hFile
, LPVOID buffer
, DWORD bytesToRead
,
1437 LPOVERLAPPED overlapped
,
1438 LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine
)
1440 LARGE_INTEGER offset
;
1442 PIO_STATUS_BLOCK io_status
;
1446 SetLastError(ERROR_INVALID_PARAMETER
);
1450 offset
.s
.LowPart
= overlapped
->Offset
;
1451 offset
.s
.HighPart
= overlapped
->OffsetHigh
;
1452 io_status
= (PIO_STATUS_BLOCK
)overlapped
;
1453 io_status
->u
.Status
= STATUS_PENDING
;
1455 status
= NtReadFile(hFile
, NULL
, FILE_ReadWriteApc
, lpCompletionRoutine
,
1456 io_status
, buffer
, bytesToRead
, &offset
, NULL
);
1460 SetLastError( RtlNtStatusToDosError(status
) );
1466 /***********************************************************************
1467 * ReadFile (KERNEL32.@)
1469 BOOL WINAPI
ReadFile( HANDLE hFile
, LPVOID buffer
, DWORD bytesToRead
,
1470 LPDWORD bytesRead
, LPOVERLAPPED overlapped
)
1472 LARGE_INTEGER offset
;
1473 PLARGE_INTEGER poffset
= NULL
;
1474 IO_STATUS_BLOCK iosb
;
1475 PIO_STATUS_BLOCK io_status
= &iosb
;
1479 TRACE("%p %p %ld %p %p\n", hFile
, buffer
, bytesToRead
,
1480 bytesRead
, overlapped
);
1482 if (bytesRead
) *bytesRead
= 0; /* Do this before anything else */
1483 if (!bytesToRead
) return TRUE
;
1485 if (IsBadReadPtr(buffer
, bytesToRead
))
1487 SetLastError(ERROR_WRITE_FAULT
); /* FIXME */
1490 if (is_console_handle(hFile
))
1491 return FILE_ReadConsole(hFile
, buffer
, bytesToRead
, bytesRead
, NULL
);
1493 if (overlapped
!= NULL
)
1495 offset
.s
.LowPart
= overlapped
->Offset
;
1496 offset
.s
.HighPart
= overlapped
->OffsetHigh
;
1498 hEvent
= overlapped
->hEvent
;
1499 io_status
= (PIO_STATUS_BLOCK
)overlapped
;
1501 io_status
->u
.Status
= STATUS_PENDING
;
1502 io_status
->Information
= 0;
1504 status
= NtReadFile(hFile
, hEvent
, NULL
, NULL
, io_status
, buffer
, bytesToRead
, poffset
, NULL
);
1506 if (status
!= STATUS_PENDING
&& bytesRead
)
1507 *bytesRead
= io_status
->Information
;
1509 if (status
&& status
!= STATUS_END_OF_FILE
)
1511 SetLastError( RtlNtStatusToDosError(status
) );
1518 /***********************************************************************
1519 * WriteFileEx (KERNEL32.@)
1521 BOOL WINAPI
WriteFileEx(HANDLE hFile
, LPCVOID buffer
, DWORD bytesToWrite
,
1522 LPOVERLAPPED overlapped
,
1523 LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine
)
1525 LARGE_INTEGER offset
;
1527 PIO_STATUS_BLOCK io_status
;
1529 TRACE("%p %p %ld %p %p\n",
1530 hFile
, buffer
, bytesToWrite
, overlapped
, lpCompletionRoutine
);
1532 if (overlapped
== NULL
)
1534 SetLastError(ERROR_INVALID_PARAMETER
);
1537 offset
.s
.LowPart
= overlapped
->Offset
;
1538 offset
.s
.HighPart
= overlapped
->OffsetHigh
;
1540 io_status
= (PIO_STATUS_BLOCK
)overlapped
;
1541 io_status
->u
.Status
= STATUS_PENDING
;
1543 status
= NtWriteFile(hFile
, NULL
, FILE_ReadWriteApc
, lpCompletionRoutine
,
1544 io_status
, buffer
, bytesToWrite
, &offset
, NULL
);
1546 if (status
) SetLastError( RtlNtStatusToDosError(status
) );
1550 /***********************************************************************
1551 * WriteFile (KERNEL32.@)
1553 BOOL WINAPI
WriteFile( HANDLE hFile
, LPCVOID buffer
, DWORD bytesToWrite
,
1554 LPDWORD bytesWritten
, LPOVERLAPPED overlapped
)
1556 HANDLE hEvent
= NULL
;
1557 LARGE_INTEGER offset
;
1558 PLARGE_INTEGER poffset
= NULL
;
1560 IO_STATUS_BLOCK iosb
;
1561 PIO_STATUS_BLOCK piosb
= &iosb
;
1563 TRACE("%p %p %ld %p %p\n",
1564 hFile
, buffer
, bytesToWrite
, bytesWritten
, overlapped
);
1566 if (is_console_handle(hFile
))
1567 return FILE_WriteConsole(hFile
, buffer
, bytesToWrite
, bytesWritten
, NULL
);
1569 if (IsBadReadPtr(buffer
, bytesToWrite
))
1571 SetLastError(ERROR_READ_FAULT
); /* FIXME */
1577 offset
.s
.LowPart
= overlapped
->Offset
;
1578 offset
.s
.HighPart
= overlapped
->OffsetHigh
;
1580 hEvent
= overlapped
->hEvent
;
1581 piosb
= (PIO_STATUS_BLOCK
)overlapped
;
1583 piosb
->u
.Status
= STATUS_PENDING
;
1584 piosb
->Information
= 0;
1586 status
= NtWriteFile(hFile
, hEvent
, NULL
, NULL
, piosb
,
1587 buffer
, bytesToWrite
, poffset
, NULL
);
1590 SetLastError( RtlNtStatusToDosError(status
) );
1593 if (bytesWritten
) *bytesWritten
= piosb
->Information
;
1599 /***********************************************************************
1600 * SetFilePointer (KERNEL32.@)
1602 DWORD WINAPI
SetFilePointer( HANDLE hFile
, LONG distance
, LONG
*highword
,
1605 DWORD ret
= INVALID_SET_FILE_POINTER
;
1607 TRACE("handle %p offset %ld high %ld origin %ld\n",
1608 hFile
, distance
, highword
?*highword
:0, method
);
1610 SERVER_START_REQ( set_file_pointer
)
1612 req
->handle
= hFile
;
1613 req
->low
= distance
;
1614 req
->high
= highword
? *highword
: (distance
>= 0) ? 0 : -1;
1615 /* FIXME: assumes 1:1 mapping between Windows and Unix seek constants */
1616 req
->whence
= method
;
1618 if (!wine_server_call_err( req
))
1620 ret
= reply
->new_low
;
1621 if (highword
) *highword
= reply
->new_high
;
1629 /*************************************************************************
1630 * SetHandleCount (KERNEL32.@)
1632 UINT WINAPI
SetHandleCount( UINT count
)
1634 return min( 256, count
);
1638 /**************************************************************************
1639 * SetEndOfFile (KERNEL32.@)
1641 BOOL WINAPI
SetEndOfFile( HANDLE hFile
)
1644 SERVER_START_REQ( truncate_file
)
1646 req
->handle
= hFile
;
1647 ret
= !wine_server_call_err( req
);
1654 /***********************************************************************
1655 * DeleteFileW (KERNEL32.@)
1657 BOOL WINAPI
DeleteFileW( LPCWSTR path
)
1659 DOS_FULL_NAME full_name
;
1662 TRACE("%s\n", debugstr_w(path
) );
1663 if (!path
|| !*path
)
1665 SetLastError(ERROR_PATH_NOT_FOUND
);
1668 if (DOSFS_GetDevice( path
))
1670 WARN("cannot remove DOS device %s!\n", debugstr_w(path
));
1671 SetLastError( ERROR_FILE_NOT_FOUND
);
1675 if (!DOSFS_GetFullName( path
, TRUE
, &full_name
)) return FALSE
;
1677 /* check if we are allowed to delete the source */
1678 hFile
= FILE_CreateFile( full_name
.long_name
, GENERIC_READ
|GENERIC_WRITE
, 0,
1679 NULL
, OPEN_EXISTING
, 0, 0, TRUE
,
1680 GetDriveTypeW( full_name
.short_name
) );
1681 if (!hFile
) return FALSE
;
1683 if (unlink( full_name
.long_name
) == -1)
1694 /***********************************************************************
1695 * DeleteFileA (KERNEL32.@)
1697 BOOL WINAPI
DeleteFileA( LPCSTR path
)
1699 UNICODE_STRING pathW
;
1704 SetLastError(ERROR_INVALID_PARAMETER
);
1708 if (RtlCreateUnicodeStringFromAsciiz(&pathW
, path
))
1710 ret
= DeleteFileW(pathW
.Buffer
);
1711 RtlFreeUnicodeString(&pathW
);
1714 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
1719 /***********************************************************************
1720 * GetFileType (KERNEL32.@)
1722 DWORD WINAPI
GetFileType( HANDLE hFile
)
1724 DWORD ret
= FILE_TYPE_UNKNOWN
;
1726 if (is_console_handle( hFile
))
1727 return FILE_TYPE_CHAR
;
1729 SERVER_START_REQ( get_file_info
)
1731 req
->handle
= hFile
;
1732 if (!wine_server_call_err( req
)) ret
= reply
->type
;
1739 /* check if a file name is for an executable file (.exe or .com) */
1740 inline static BOOL
is_executable( const char *name
)
1742 int len
= strlen(name
);
1744 if (len
< 4) return FALSE
;
1745 return (!strcasecmp( name
+ len
- 4, ".exe" ) ||
1746 !strcasecmp( name
+ len
- 4, ".com" ));
1750 /***********************************************************************
1751 * FILE_AddBootRenameEntry
1753 * Adds an entry to the registry that is loaded when windows boots and
1754 * checks if there are some files to be removed or renamed/moved.
1755 * <fn1> has to be valid and <fn2> may be NULL. If both pointers are
1756 * non-NULL then the file is moved, otherwise it is deleted. The
1757 * entry of the registrykey is always appended with two zero
1758 * terminated strings. If <fn2> is NULL then the second entry is
1759 * simply a single 0-byte. Otherwise the second filename goes
1760 * there. The entries are prepended with \??\ before the path and the
1761 * second filename gets also a '!' as the first character if
1762 * MOVEFILE_REPLACE_EXISTING is set. After the final string another
1763 * 0-byte follows to indicate the end of the strings.
1765 * \??\D:\test\file1[0]
1766 * !\??\D:\test\file1_renamed[0]
1767 * \??\D:\Test|delete[0]
1768 * [0] <- file is to be deleted, second string empty
1769 * \??\D:\test\file2[0]
1770 * !\??\D:\test\file2_renamed[0]
1771 * [0] <- indicates end of strings
1774 * \??\D:\test\file1[0]
1775 * !\??\D:\test\file1_renamed[0]
1776 * \??\D:\Test|delete[0]
1777 * [0] <- file is to be deleted, second string empty
1778 * [0] <- indicates end of strings
1781 static BOOL
FILE_AddBootRenameEntry( LPCWSTR fn1
, LPCWSTR fn2
, DWORD flags
)
1783 static const WCHAR PreString
[] = {'\\','?','?','\\',0};
1784 static const WCHAR ValueName
[] = {'P','e','n','d','i','n','g',
1785 'F','i','l','e','R','e','n','a','m','e',
1786 'O','p','e','r','a','t','i','o','n','s',0};
1787 static const WCHAR SessionW
[] = {'M','a','c','h','i','n','e','\\',
1788 'S','y','s','t','e','m','\\',
1789 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
1790 'C','o','n','t','r','o','l','\\',
1791 'S','e','s','s','i','o','n',' ','M','a','n','a','g','e','r',0};
1792 static const int info_size
= FIELD_OFFSET( KEY_VALUE_PARTIAL_INFORMATION
, Data
);
1794 OBJECT_ATTRIBUTES attr
;
1795 UNICODE_STRING nameW
;
1796 KEY_VALUE_PARTIAL_INFORMATION
*info
;
1799 DWORD len0
, len1
, len2
;
1801 BYTE
*Buffer
= NULL
;
1804 attr
.Length
= sizeof(attr
);
1805 attr
.RootDirectory
= 0;
1806 attr
.ObjectName
= &nameW
;
1807 attr
.Attributes
= 0;
1808 attr
.SecurityDescriptor
= NULL
;
1809 attr
.SecurityQualityOfService
= NULL
;
1810 RtlInitUnicodeString( &nameW
, SessionW
);
1812 if (NtCreateKey( &Reboot
, KEY_ALL_ACCESS
, &attr
, 0, NULL
, 0, NULL
) != STATUS_SUCCESS
)
1814 WARN("Error creating key for reboot managment [%s]\n",
1815 "SYSTEM\\CurrentControlSet\\Control\\Session Manager");
1819 len0
= strlenW(PreString
);
1820 len1
= strlenW(fn1
) + len0
+ 1;
1823 len2
= strlenW(fn2
) + len0
+ 1;
1824 if (flags
& MOVEFILE_REPLACE_EXISTING
) len2
++; /* Plus 1 because of the leading '!' */
1826 else len2
= 1; /* minimum is the 0 characters for the empty second string */
1828 /* convert characters to bytes */
1829 len0
*= sizeof(WCHAR
);
1830 len1
*= sizeof(WCHAR
);
1831 len2
*= sizeof(WCHAR
);
1833 RtlInitUnicodeString( &nameW
, ValueName
);
1835 /* First we check if the key exists and if so how many bytes it already contains. */
1836 if (NtQueryValueKey( Reboot
, &nameW
, KeyValuePartialInformation
,
1837 NULL
, 0, &DataSize
) == STATUS_BUFFER_OVERFLOW
)
1839 if (!(Buffer
= HeapAlloc( GetProcessHeap(), 0, DataSize
+ len1
+ len2
+ sizeof(WCHAR
) )))
1841 if (NtQueryValueKey( Reboot
, &nameW
, KeyValuePartialInformation
,
1842 Buffer
, DataSize
, &DataSize
)) goto Quit
;
1843 info
= (KEY_VALUE_PARTIAL_INFORMATION
*)Buffer
;
1844 if (info
->Type
!= REG_MULTI_SZ
) goto Quit
;
1845 if (DataSize
> sizeof(info
)) DataSize
-= sizeof(WCHAR
); /* remove terminating null (will be added back later) */
1849 DataSize
= info_size
;
1850 if (!(Buffer
= HeapAlloc( GetProcessHeap(), 0, DataSize
+ len1
+ len2
+ sizeof(WCHAR
) )))
1854 p
= (WCHAR
*)(Buffer
+ DataSize
);
1855 strcpyW( p
, PreString
);
1860 p
= (WCHAR
*)(Buffer
+ DataSize
);
1861 if (flags
& MOVEFILE_REPLACE_EXISTING
)
1863 strcpyW( p
, PreString
);
1869 p
= (WCHAR
*)(Buffer
+ DataSize
);
1871 DataSize
+= sizeof(WCHAR
);
1874 /* add final null */
1875 p
= (WCHAR
*)(Buffer
+ DataSize
);
1877 DataSize
+= sizeof(WCHAR
);
1879 rc
= !NtSetValueKey(Reboot
, &nameW
, 0, REG_MULTI_SZ
, Buffer
+ info_size
, DataSize
- info_size
);
1882 if (Reboot
) NtClose(Reboot
);
1883 if (Buffer
) HeapFree( GetProcessHeap(), 0, Buffer
);
1888 /**************************************************************************
1889 * MoveFileExW (KERNEL32.@)
1891 BOOL WINAPI
MoveFileExW( LPCWSTR fn1
, LPCWSTR fn2
, DWORD flag
)
1893 DOS_FULL_NAME full_name1
, full_name2
;
1895 DWORD attr
= INVALID_FILE_ATTRIBUTES
;
1897 TRACE("(%s,%s,%04lx)\n", debugstr_w(fn1
), debugstr_w(fn2
), flag
);
1899 /* FIXME: <Gerhard W. Gruber>sparhawk@gmx.at
1900 In case of W9x and lesser this function should return 120 (ERROR_CALL_NOT_IMPLEMENTED)
1901 to be really compatible. Most programs wont have any problems though. In case
1902 you encounter one, this is what you should return here. I don't know what's up
1903 with NT 3.5. Is this function available there or not?
1904 Does anybody really care about 3.5? :)
1907 /* Filename1 has to be always set to a valid path. Filename2 may be NULL
1908 if the source file has to be deleted.
1911 SetLastError(ERROR_INVALID_PARAMETER
);
1915 /* This function has to be run through in order to process the name properly.
1916 If the BOOTDELAY flag is set, the file doesn't need to exist though. At least
1917 that is the behaviour on NT 4.0. The operation accepts the filenames as
1918 they are given but it can't reply with a reasonable returncode. Success
1919 means in that case success for entering the values into the registry.
1921 if(!DOSFS_GetFullName( fn1
, TRUE
, &full_name1
))
1923 if(!(flag
& MOVEFILE_DELAY_UNTIL_REBOOT
))
1927 if (fn2
) /* !fn2 means delete fn1 */
1929 if (DOSFS_GetFullName( fn2
, TRUE
, &full_name2
))
1931 if(!(flag
& MOVEFILE_DELAY_UNTIL_REBOOT
))
1933 /* target exists, check if we may overwrite */
1934 if (!(flag
& MOVEFILE_REPLACE_EXISTING
))
1936 SetLastError( ERROR_FILE_EXISTS
);
1943 if (!DOSFS_GetFullName( fn2
, FALSE
, &full_name2
))
1945 if(!(flag
& MOVEFILE_DELAY_UNTIL_REBOOT
))
1950 /* Source name and target path are valid */
1952 if (flag
& MOVEFILE_DELAY_UNTIL_REBOOT
)
1954 return FILE_AddBootRenameEntry( fn1
, fn2
, flag
);
1957 attr
= GetFileAttributesW( fn1
);
1958 if ( attr
== INVALID_FILE_ATTRIBUTES
) return FALSE
;
1960 /* check if we are allowed to rename the source */
1961 hFile
= FILE_CreateFile( full_name1
.long_name
, 0, 0,
1962 NULL
, OPEN_EXISTING
, 0, 0, TRUE
,
1963 GetDriveTypeW( full_name1
.short_name
) );
1966 if (GetLastError() != ERROR_ACCESS_DENIED
) return FALSE
;
1967 if ( !(attr
& FILE_ATTRIBUTE_DIRECTORY
) ) return FALSE
;
1968 /* if it's a directory we can continue */
1970 else CloseHandle(hFile
);
1972 /* check, if we are allowed to delete the destination,
1973 ** (but the file not being there is fine) */
1974 hFile
= FILE_CreateFile( full_name2
.long_name
, GENERIC_READ
|GENERIC_WRITE
, 0,
1975 NULL
, OPEN_EXISTING
, 0, 0, TRUE
,
1976 GetDriveTypeW( full_name2
.short_name
) );
1977 if(!hFile
&& GetLastError() != ERROR_FILE_NOT_FOUND
) return FALSE
;
1980 if (full_name1
.drive
!= full_name2
.drive
)
1982 if (!(flag
& MOVEFILE_COPY_ALLOWED
))
1984 SetLastError( ERROR_NOT_SAME_DEVICE
);
1987 else if ( attr
& FILE_ATTRIBUTE_DIRECTORY
)
1989 /* Strange, but that's what Windows returns */
1990 SetLastError ( ERROR_ACCESS_DENIED
);
1994 if (rename( full_name1
.long_name
, full_name2
.long_name
) == -1)
1995 /* Try copy/delete unless it's a directory. */
1996 /* FIXME: This does not handle the (unlikely) case that the two locations
1997 are on the same Wine drive, but on different Unix file systems. */
1999 if ( attr
& FILE_ATTRIBUTE_DIRECTORY
)
2006 if ( ! CopyFileW( fn1
, fn2
, !(flag
& MOVEFILE_REPLACE_EXISTING
) ))
2008 if ( ! DeleteFileW ( fn1
) )
2012 if (is_executable( full_name1
.long_name
) != is_executable( full_name2
.long_name
))
2015 if (stat( full_name2
.long_name
, &fstat
) != -1)
2017 if (is_executable( full_name2
.long_name
))
2018 /* set executable bit where read bit is set */
2019 fstat
.st_mode
|= (fstat
.st_mode
& 0444) >> 2;
2021 fstat
.st_mode
&= ~0111;
2022 chmod( full_name2
.long_name
, fstat
.st_mode
);
2027 else /* fn2 == NULL means delete source */
2029 if (flag
& MOVEFILE_DELAY_UNTIL_REBOOT
)
2031 if (flag
& MOVEFILE_COPY_ALLOWED
) {
2032 WARN("Illegal flag\n");
2033 SetLastError( ERROR_GEN_FAILURE
);
2037 return FILE_AddBootRenameEntry( fn1
, NULL
, flag
);
2040 if (unlink( full_name1
.long_name
) == -1)
2045 return TRUE
; /* successfully deleted */
2049 /**************************************************************************
2050 * MoveFileExA (KERNEL32.@)
2052 BOOL WINAPI
MoveFileExA( LPCSTR fn1
, LPCSTR fn2
, DWORD flag
)
2054 UNICODE_STRING fn1W
, fn2W
;
2059 SetLastError(ERROR_INVALID_PARAMETER
);
2063 RtlCreateUnicodeStringFromAsciiz(&fn1W
, fn1
);
2064 if (fn2
) RtlCreateUnicodeStringFromAsciiz(&fn2W
, fn2
);
2065 else fn2W
.Buffer
= NULL
;
2067 ret
= MoveFileExW( fn1W
.Buffer
, fn2W
.Buffer
, flag
);
2069 RtlFreeUnicodeString(&fn1W
);
2070 RtlFreeUnicodeString(&fn2W
);
2075 /**************************************************************************
2076 * MoveFileW (KERNEL32.@)
2078 * Move file or directory
2080 BOOL WINAPI
MoveFileW( LPCWSTR fn1
, LPCWSTR fn2
)
2082 return MoveFileExW( fn1
, fn2
, MOVEFILE_COPY_ALLOWED
);
2086 /**************************************************************************
2087 * MoveFileA (KERNEL32.@)
2089 BOOL WINAPI
MoveFileA( LPCSTR fn1
, LPCSTR fn2
)
2091 return MoveFileExA( fn1
, fn2
, MOVEFILE_COPY_ALLOWED
);
2095 /**************************************************************************
2096 * CopyFileW (KERNEL32.@)
2098 BOOL WINAPI
CopyFileW( LPCWSTR source
, LPCWSTR dest
, BOOL fail_if_exists
)
2101 BY_HANDLE_FILE_INFORMATION info
;
2106 if (!source
|| !dest
)
2108 SetLastError(ERROR_INVALID_PARAMETER
);
2112 TRACE("%s -> %s\n", debugstr_w(source
), debugstr_w(dest
));
2114 if ((h1
= CreateFileW(source
, GENERIC_READ
, FILE_SHARE_READ
| FILE_SHARE_WRITE
,
2115 NULL
, OPEN_EXISTING
, 0, 0)) == INVALID_HANDLE_VALUE
)
2117 WARN("Unable to open source %s\n", debugstr_w(source
));
2121 if (!GetFileInformationByHandle( h1
, &info
))
2123 WARN("GetFileInformationByHandle returned error for %s\n", debugstr_w(source
));
2128 if ((h2
= CreateFileW( dest
, GENERIC_WRITE
, FILE_SHARE_READ
| FILE_SHARE_WRITE
, NULL
,
2129 fail_if_exists
? CREATE_NEW
: CREATE_ALWAYS
,
2130 info
.dwFileAttributes
, h1
)) == INVALID_HANDLE_VALUE
)
2132 WARN("Unable to open dest %s\n", debugstr_w(dest
));
2137 while (ReadFile( h1
, buffer
, sizeof(buffer
), &count
, NULL
) && count
)
2143 if (!WriteFile( h2
, p
, count
, &res
, NULL
) || !res
) goto done
;
2156 /**************************************************************************
2157 * CopyFileA (KERNEL32.@)
2159 BOOL WINAPI
CopyFileA( LPCSTR source
, LPCSTR dest
, BOOL fail_if_exists
)
2161 UNICODE_STRING sourceW
, destW
;
2164 if (!source
|| !dest
)
2166 SetLastError(ERROR_INVALID_PARAMETER
);
2170 RtlCreateUnicodeStringFromAsciiz(&sourceW
, source
);
2171 RtlCreateUnicodeStringFromAsciiz(&destW
, dest
);
2173 ret
= CopyFileW(sourceW
.Buffer
, destW
.Buffer
, fail_if_exists
);
2175 RtlFreeUnicodeString(&sourceW
);
2176 RtlFreeUnicodeString(&destW
);
2181 /**************************************************************************
2182 * CopyFileExW (KERNEL32.@)
2184 * This implementation ignores most of the extra parameters passed-in into
2185 * the "ex" version of the method and calls the CopyFile method.
2186 * It will have to be fixed eventually.
2188 BOOL WINAPI
CopyFileExW(LPCWSTR sourceFilename
, LPCWSTR destFilename
,
2189 LPPROGRESS_ROUTINE progressRoutine
, LPVOID appData
,
2190 LPBOOL cancelFlagPointer
, DWORD copyFlags
)
2193 * Interpret the only flag that CopyFile can interpret.
2195 return CopyFileW(sourceFilename
, destFilename
, (copyFlags
& COPY_FILE_FAIL_IF_EXISTS
) != 0);
2199 /**************************************************************************
2200 * CopyFileExA (KERNEL32.@)
2202 BOOL WINAPI
CopyFileExA(LPCSTR sourceFilename
, LPCSTR destFilename
,
2203 LPPROGRESS_ROUTINE progressRoutine
, LPVOID appData
,
2204 LPBOOL cancelFlagPointer
, DWORD copyFlags
)
2206 UNICODE_STRING sourceW
, destW
;
2209 if (!sourceFilename
|| !destFilename
)
2211 SetLastError(ERROR_INVALID_PARAMETER
);
2215 RtlCreateUnicodeStringFromAsciiz(&sourceW
, sourceFilename
);
2216 RtlCreateUnicodeStringFromAsciiz(&destW
, destFilename
);
2218 ret
= CopyFileExW(sourceW
.Buffer
, destW
.Buffer
, progressRoutine
, appData
,
2219 cancelFlagPointer
, copyFlags
);
2221 RtlFreeUnicodeString(&sourceW
);
2222 RtlFreeUnicodeString(&destW
);
2227 /***********************************************************************
2228 * SetFileTime (KERNEL32.@)
2230 BOOL WINAPI
SetFileTime( HANDLE hFile
,
2231 const FILETIME
*lpCreationTime
,
2232 const FILETIME
*lpLastAccessTime
,
2233 const FILETIME
*lpLastWriteTime
)
2236 SERVER_START_REQ( set_file_time
)
2238 req
->handle
= hFile
;
2239 if (lpLastAccessTime
)
2240 RtlTimeToSecondsSince1970( (PLARGE_INTEGER
) lpLastAccessTime
, (DWORD
*)&req
->access_time
);
2242 req
->access_time
= 0; /* FIXME */
2243 if (lpLastWriteTime
)
2244 RtlTimeToSecondsSince1970( (PLARGE_INTEGER
) lpLastWriteTime
, (DWORD
*)&req
->write_time
);
2246 req
->write_time
= 0; /* FIXME */
2247 ret
= !wine_server_call_err( req
);
2254 /**************************************************************************
2255 * GetFileAttributesExW (KERNEL32.@)
2257 BOOL WINAPI
GetFileAttributesExW(
2258 LPCWSTR lpFileName
, GET_FILEEX_INFO_LEVELS fInfoLevelId
,
2259 LPVOID lpFileInformation
)
2261 DOS_FULL_NAME full_name
;
2262 BY_HANDLE_FILE_INFORMATION info
;
2264 if (!lpFileName
|| !lpFileInformation
)
2266 SetLastError(ERROR_INVALID_PARAMETER
);
2270 if (fInfoLevelId
== GetFileExInfoStandard
) {
2271 LPWIN32_FILE_ATTRIBUTE_DATA lpFad
=
2272 (LPWIN32_FILE_ATTRIBUTE_DATA
) lpFileInformation
;
2273 if (!DOSFS_GetFullName( lpFileName
, TRUE
, &full_name
)) return FALSE
;
2274 if (!FILE_Stat( full_name
.long_name
, &info
, NULL
)) return FALSE
;
2276 lpFad
->dwFileAttributes
= info
.dwFileAttributes
;
2277 lpFad
->ftCreationTime
= info
.ftCreationTime
;
2278 lpFad
->ftLastAccessTime
= info
.ftLastAccessTime
;
2279 lpFad
->ftLastWriteTime
= info
.ftLastWriteTime
;
2280 lpFad
->nFileSizeHigh
= info
.nFileSizeHigh
;
2281 lpFad
->nFileSizeLow
= info
.nFileSizeLow
;
2284 FIXME("invalid info level %d!\n", fInfoLevelId
);
2292 /**************************************************************************
2293 * GetFileAttributesExA (KERNEL32.@)
2295 BOOL WINAPI
GetFileAttributesExA(
2296 LPCSTR filename
, GET_FILEEX_INFO_LEVELS fInfoLevelId
,
2297 LPVOID lpFileInformation
)
2299 UNICODE_STRING filenameW
;
2302 if (!filename
|| !lpFileInformation
)
2304 SetLastError(ERROR_INVALID_PARAMETER
);
2308 if (RtlCreateUnicodeStringFromAsciiz(&filenameW
, filename
))
2310 ret
= GetFileAttributesExW(filenameW
.Buffer
, fInfoLevelId
, lpFileInformation
);
2311 RtlFreeUnicodeString(&filenameW
);
2314 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);