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
53 #include "wine/winbase16.h"
54 #include "wine/server.h"
64 #include "wine/debug.h"
66 WINE_DEFAULT_DEBUG_CHANNEL(file
);
68 #if defined(MAP_ANONYMOUS) && !defined(MAP_ANON)
69 #define MAP_ANON MAP_ANONYMOUS
72 /* Size of per-process table of DOS handles */
73 #define DOS_TABLE_SIZE 256
75 /* Macro to derive file offset from OVERLAPPED struct */
76 #define OVERLAPPED_OFFSET(overlapped) ((off_t) (overlapped)->Offset + ((off_t) (overlapped)->OffsetHigh << 32))
78 static HANDLE dos_handles
[DOS_TABLE_SIZE
];
82 extern HANDLE WINAPI
FILE_SmbOpen(LPCSTR name
);
84 /***********************************************************************
85 * Asynchronous file I/O *
87 static DWORD
fileio_get_async_status (const async_private
*ovp
);
88 static DWORD
fileio_get_async_count (const async_private
*ovp
);
89 static void fileio_set_async_status (async_private
*ovp
, const DWORD status
);
90 static void CALLBACK
fileio_call_completion_func (ULONG_PTR data
);
91 static void fileio_async_cleanup (async_private
*ovp
);
93 static async_ops fileio_async_ops
=
95 fileio_get_async_status
, /* get_status */
96 fileio_set_async_status
, /* set_status */
97 fileio_get_async_count
, /* get_count */
98 fileio_call_completion_func
, /* call_completion */
99 fileio_async_cleanup
/* cleanup */
102 static async_ops fileio_nocomp_async_ops
=
104 fileio_get_async_status
, /* get_status */
105 fileio_set_async_status
, /* set_status */
106 fileio_get_async_count
, /* get_count */
107 NULL
, /* call_completion */
108 fileio_async_cleanup
/* cleanup */
111 typedef struct async_fileio
113 struct async_private async
;
114 LPOVERLAPPED lpOverlapped
;
115 LPOVERLAPPED_COMPLETION_ROUTINE completion_func
;
118 enum fd_type fd_type
;
121 static DWORD
fileio_get_async_status (const struct async_private
*ovp
)
123 return ((async_fileio
*) ovp
)->lpOverlapped
->Internal
;
126 static void fileio_set_async_status (async_private
*ovp
, const DWORD status
)
128 ((async_fileio
*) ovp
)->lpOverlapped
->Internal
= status
;
131 static DWORD
fileio_get_async_count (const struct async_private
*ovp
)
133 async_fileio
*fileio
= (async_fileio
*) ovp
;
134 DWORD ret
= fileio
->count
- fileio
->lpOverlapped
->InternalHigh
;
135 return (ret
< 0 ? 0 : ret
);
138 static void CALLBACK
fileio_call_completion_func (ULONG_PTR data
)
140 async_fileio
*ovp
= (async_fileio
*) data
;
141 TRACE ("data: %p\n", ovp
);
143 ovp
->completion_func( ovp
->lpOverlapped
->Internal
,
144 ovp
->lpOverlapped
->InternalHigh
,
147 fileio_async_cleanup ( &ovp
->async
);
150 static void fileio_async_cleanup ( struct async_private
*ovp
)
152 HeapFree ( GetProcessHeap(), 0, ovp
);
155 /***********************************************************************
158 * Convert OF_* mode into flags for CreateFile.
160 static void FILE_ConvertOFMode( INT mode
, DWORD
*access
, DWORD
*sharing
)
164 case OF_READ
: *access
= GENERIC_READ
; break;
165 case OF_WRITE
: *access
= GENERIC_WRITE
; break;
166 case OF_READWRITE
: *access
= GENERIC_READ
| GENERIC_WRITE
; break;
167 default: *access
= 0; break;
171 case OF_SHARE_EXCLUSIVE
: *sharing
= 0; break;
172 case OF_SHARE_DENY_WRITE
: *sharing
= FILE_SHARE_READ
; break;
173 case OF_SHARE_DENY_READ
: *sharing
= FILE_SHARE_WRITE
; break;
174 case OF_SHARE_DENY_NONE
:
175 case OF_SHARE_COMPAT
:
176 default: *sharing
= FILE_SHARE_READ
| FILE_SHARE_WRITE
; break;
181 /***********************************************************************
184 * locale-independent case conversion for file I/O
186 int FILE_strcasecmp( const char *str1
, const char *str2
)
190 int ret
= FILE_toupper(*str1
) - FILE_toupper(*str2
);
191 if (ret
|| !*str1
) return ret
;
198 /***********************************************************************
201 * locale-independent case conversion for file I/O
203 int FILE_strncasecmp( const char *str1
, const char *str2
, int len
)
206 for ( ; len
> 0; len
--, str1
++, str2
++)
207 if ((ret
= FILE_toupper(*str1
) - FILE_toupper(*str2
)) || !*str1
) break;
212 /***********************************************************************
213 * FILE_GetNtStatus(void)
215 * Retrieve the Nt Status code from errno.
216 * Try to be consistent with FILE_SetDosError().
218 DWORD
FILE_GetNtStatus(void)
222 TRACE ( "errno = %d\n", errno
);
225 case EAGAIN
: nt
= STATUS_SHARING_VIOLATION
; break;
226 case EBADF
: nt
= STATUS_INVALID_HANDLE
; break;
227 case ENOSPC
: nt
= STATUS_DISK_FULL
; break;
230 case EACCES
: nt
= STATUS_ACCESS_DENIED
; break;
231 case ENOENT
: nt
= STATUS_SHARING_VIOLATION
; break;
232 case EISDIR
: nt
= STATUS_FILE_IS_A_DIRECTORY
; break;
234 case ENFILE
: nt
= STATUS_NO_MORE_FILES
; break;
236 case ENOTEMPTY
: nt
= STATUS_DIRECTORY_NOT_EMPTY
; break;
237 case EPIPE
: nt
= STATUS_PIPE_BROKEN
; break;
238 case ENOEXEC
: /* ?? */
239 case ESPIPE
: /* ?? */
240 case EEXIST
: /* ?? */
242 FIXME ( "Converting errno %d to STATUS_UNSUCCESSFUL\n", err
);
243 nt
= STATUS_UNSUCCESSFUL
;
248 /***********************************************************************
251 * Set the DOS error code from errno.
253 void FILE_SetDosError(void)
255 int save_errno
= errno
; /* errno gets overwritten by printf */
257 TRACE("errno = %d %s\n", errno
, strerror(errno
));
261 SetLastError( ERROR_SHARING_VIOLATION
);
264 SetLastError( ERROR_INVALID_HANDLE
);
267 SetLastError( ERROR_HANDLE_DISK_FULL
);
272 SetLastError( ERROR_ACCESS_DENIED
);
275 SetLastError( ERROR_LOCK_VIOLATION
);
278 SetLastError( ERROR_FILE_NOT_FOUND
);
281 SetLastError( ERROR_CANNOT_MAKE
);
285 SetLastError( ERROR_NO_MORE_FILES
);
288 SetLastError( ERROR_FILE_EXISTS
);
292 SetLastError( ERROR_SEEK
);
295 SetLastError( ERROR_DIR_NOT_EMPTY
);
298 SetLastError( ERROR_BAD_FORMAT
);
301 WARN("unknown file error: %s\n", strerror(save_errno
) );
302 SetLastError( ERROR_GEN_FAILURE
);
309 /***********************************************************************
310 * FILE_GetUnixHandleType
312 * Retrieve the Unix handle corresponding to a file handle.
313 * Returns -1 on failure.
315 static int FILE_GetUnixHandleType( HANDLE handle
, DWORD access
, enum fd_type
*type
, int *flags_ptr
)
317 int ret
, flags
, fd
= -1;
319 ret
= wine_server_handle_to_fd( handle
, access
, &fd
, type
, &flags
);
320 if (flags_ptr
) *flags_ptr
= flags
;
321 if (ret
) SetLastError( RtlNtStatusToDosError(ret
) );
322 else if (((access
& GENERIC_READ
) && (flags
& FD_FLAG_RECV_SHUTDOWN
)) ||
323 ((access
& GENERIC_WRITE
) && (flags
& FD_FLAG_SEND_SHUTDOWN
)))
326 SetLastError ( ERROR_PIPE_NOT_CONNECTED
);
332 /***********************************************************************
335 * Retrieve the Unix handle corresponding to a file handle.
336 * Returns -1 on failure.
338 int FILE_GetUnixHandle( HANDLE handle
, DWORD access
)
340 return FILE_GetUnixHandleType( handle
, access
, NULL
, NULL
);
343 /*************************************************************************
346 * Open a handle to the current process console.
347 * Returns 0 on failure.
349 static HANDLE
FILE_OpenConsole( BOOL output
, DWORD access
, DWORD sharing
, LPSECURITY_ATTRIBUTES sa
)
353 SERVER_START_REQ( open_console
)
356 req
->access
= access
;
357 req
->share
= sharing
;
358 req
->inherit
= (sa
&& (sa
->nLength
>=sizeof(*sa
)) && sa
->bInheritHandle
);
360 wine_server_call_err( req
);
368 /***********************************************************************
371 * Implementation of CreateFile. Takes a Unix path name.
372 * Returns 0 on failure.
374 HANDLE
FILE_CreateFile( LPCSTR filename
, DWORD access
, DWORD sharing
,
375 LPSECURITY_ATTRIBUTES sa
, DWORD creation
,
376 DWORD attributes
, HANDLE
template, BOOL fail_read_only
,
384 SERVER_START_REQ( create_file
)
386 req
->access
= access
;
387 req
->inherit
= (sa
&& (sa
->nLength
>=sizeof(*sa
)) && sa
->bInheritHandle
);
388 req
->sharing
= sharing
;
389 req
->create
= creation
;
390 req
->attrs
= attributes
;
391 req
->drive_type
= drive_type
;
392 wine_server_add_data( req
, filename
, strlen(filename
) );
394 err
= wine_server_call( req
);
399 /* If write access failed, retry without GENERIC_WRITE */
401 if (!ret
&& !fail_read_only
&& (access
& GENERIC_WRITE
))
403 if ((err
== STATUS_MEDIA_WRITE_PROTECTED
) || (err
== STATUS_ACCESS_DENIED
))
405 TRACE("Write access failed for file '%s', trying without "
406 "write access\n", filename
);
407 access
&= ~GENERIC_WRITE
;
412 if (err
) SetLastError( RtlNtStatusToDosError(err
) );
414 if (!ret
) WARN("Unable to create file '%s' (GLE %ld)\n", filename
, GetLastError());
420 /***********************************************************************
423 * Same as FILE_CreateFile but for a device
424 * Returns 0 on failure.
426 HANDLE
FILE_CreateDevice( int client_id
, DWORD access
, LPSECURITY_ATTRIBUTES sa
)
429 SERVER_START_REQ( create_device
)
431 req
->access
= access
;
432 req
->inherit
= (sa
&& (sa
->nLength
>=sizeof(*sa
)) && sa
->bInheritHandle
);
435 wine_server_call_err( req
);
442 static HANDLE
FILE_OpenPipe(LPCSTR name
, DWORD access
)
444 WCHAR buffer
[MAX_PATH
];
448 if (name
&& !(len
= MultiByteToWideChar( CP_ACP
, 0, name
, strlen(name
), buffer
, MAX_PATH
)))
450 SetLastError( ERROR_FILENAME_EXCED_RANGE
);
453 SERVER_START_REQ( open_named_pipe
)
455 req
->access
= access
;
457 wine_server_add_data( req
, buffer
, len
* sizeof(WCHAR
) );
458 wine_server_call_err( req
);
462 TRACE("Returned %d\n",ret
);
466 /*************************************************************************
467 * CreateFileA [KERNEL32.@] Creates or opens a file or other object
469 * Creates or opens an object, and returns a handle that can be used to
470 * access that object.
474 * filename [in] pointer to filename to be accessed
475 * access [in] access mode requested
476 * sharing [in] share mode
477 * sa [in] pointer to security attributes
478 * creation [in] how to create the file
479 * attributes [in] attributes for newly created file
480 * template [in] handle to file with extended attributes to copy
483 * Success: Open handle to specified file
484 * Failure: INVALID_HANDLE_VALUE
487 * Should call SetLastError() on failure.
491 * Doesn't support character devices, template files, or a
492 * lot of the 'attributes' flags yet.
494 HANDLE WINAPI
CreateFileA( LPCSTR filename
, DWORD access
, DWORD sharing
,
495 LPSECURITY_ATTRIBUTES sa
, DWORD creation
,
496 DWORD attributes
, HANDLE
template )
498 DOS_FULL_NAME full_name
;
503 SetLastError( ERROR_INVALID_PARAMETER
);
504 return INVALID_HANDLE_VALUE
;
506 TRACE("%s %s%s%s%s%s%s%s\n",filename
,
507 ((access
& GENERIC_READ
)==GENERIC_READ
)?"GENERIC_READ ":"",
508 ((access
& GENERIC_WRITE
)==GENERIC_WRITE
)?"GENERIC_WRITE ":"",
509 (!access
)?"QUERY_ACCESS ":"",
510 ((sharing
& FILE_SHARE_READ
)==FILE_SHARE_READ
)?"FILE_SHARE_READ ":"",
511 ((sharing
& FILE_SHARE_WRITE
)==FILE_SHARE_WRITE
)?"FILE_SHARE_WRITE ":"",
512 ((sharing
& FILE_SHARE_DELETE
)==FILE_SHARE_DELETE
)?"FILE_SHARE_DELETE ":"",
513 (creation
==CREATE_NEW
)?"CREATE_NEW":
514 (creation
==CREATE_ALWAYS
)?"CREATE_ALWAYS ":
515 (creation
==OPEN_EXISTING
)?"OPEN_EXISTING ":
516 (creation
==OPEN_ALWAYS
)?"OPEN_ALWAYS ":
517 (creation
==TRUNCATE_EXISTING
)?"TRUNCATE_EXISTING ":"");
519 /* If the name starts with '\\?\', ignore the first 4 chars. */
520 if (!strncmp(filename
, "\\\\?\\", 4))
523 if (!strncmp(filename
, "UNC\\", 4))
525 FIXME("UNC name (%s) not supported.\n", filename
);
526 SetLastError( ERROR_PATH_NOT_FOUND
);
527 return INVALID_HANDLE_VALUE
;
531 if (!strncmp(filename
, "\\\\.\\", 4)) {
532 if(!strncasecmp(&filename
[4],"pipe\\",5))
534 TRACE("Opening a pipe: %s\n",filename
);
535 ret
= FILE_OpenPipe(filename
,access
);
538 else if (isalpha(filename
[4]) && filename
[5] == ':' && filename
[6] == '\0')
540 ret
= FILE_CreateDevice( (toupper(filename
[4]) - 'A') | 0x20000, access
, sa
);
543 else if (!DOSFS_GetDevice( filename
))
545 ret
= DEVICE_Open( filename
+4, access
, sa
);
549 filename
+=4; /* fall into DOSFS_Device case below */
552 /* If the name still starts with '\\', it's a UNC name. */
553 if (!strncmp(filename
, "\\\\", 2))
555 ret
= SMB_CreateFileA(filename
, access
, sharing
, sa
, creation
, attributes
, template );
559 /* If the name contains a DOS wild card (* or ?), do no create a file */
560 if(strchr(filename
,'*') || strchr(filename
,'?'))
561 return INVALID_HANDLE_VALUE
;
563 /* Open a console for CONIN$ or CONOUT$ */
564 if (!strcasecmp(filename
, "CONIN$"))
566 ret
= FILE_OpenConsole( FALSE
, access
, sharing
, sa
);
569 if (!strcasecmp(filename
, "CONOUT$"))
571 ret
= FILE_OpenConsole( TRUE
, access
, sharing
, sa
);
575 if (DOSFS_GetDevice( filename
))
577 TRACE("opening device '%s'\n", filename
);
579 if (!(ret
= DOSFS_OpenDevice( filename
, access
, attributes
, sa
)))
581 /* Do not silence this please. It is a critical error. -MM */
582 ERR("Couldn't open device '%s'!\n",filename
);
583 SetLastError( ERROR_FILE_NOT_FOUND
);
588 /* check for filename, don't check for last entry if creating */
589 if (!DOSFS_GetFullName( filename
,
590 (creation
== OPEN_EXISTING
) ||
591 (creation
== TRUNCATE_EXISTING
),
593 WARN("Unable to get full filename from '%s' (GLE %ld)\n",
594 filename
, GetLastError());
595 return INVALID_HANDLE_VALUE
;
598 ret
= FILE_CreateFile( full_name
.long_name
, access
, sharing
,
599 sa
, creation
, attributes
, template,
600 DRIVE_GetFlags(full_name
.drive
) & DRIVE_FAIL_READ_ONLY
,
601 GetDriveTypeA( full_name
.short_name
) );
603 if (!ret
) ret
= INVALID_HANDLE_VALUE
;
609 /*************************************************************************
610 * CreateFileW (KERNEL32.@)
612 HANDLE WINAPI
CreateFileW( LPCWSTR filename
, DWORD access
, DWORD sharing
,
613 LPSECURITY_ATTRIBUTES sa
, DWORD creation
,
614 DWORD attributes
, HANDLE
template)
616 LPSTR afn
= HEAP_strdupWtoA( GetProcessHeap(), 0, filename
);
617 HANDLE res
= CreateFileA( afn
, access
, sharing
, sa
, creation
, attributes
, template );
618 HeapFree( GetProcessHeap(), 0, afn
);
623 /***********************************************************************
626 * Fill a file information from a struct stat.
628 static void FILE_FillInfo( struct stat
*st
, BY_HANDLE_FILE_INFORMATION
*info
)
630 if (S_ISDIR(st
->st_mode
))
631 info
->dwFileAttributes
= FILE_ATTRIBUTE_DIRECTORY
;
633 info
->dwFileAttributes
= FILE_ATTRIBUTE_ARCHIVE
;
634 if (!(st
->st_mode
& S_IWUSR
))
635 info
->dwFileAttributes
|= FILE_ATTRIBUTE_READONLY
;
637 RtlSecondsSince1970ToTime( st
->st_mtime
, &info
->ftCreationTime
);
638 RtlSecondsSince1970ToTime( st
->st_mtime
, &info
->ftLastWriteTime
);
639 RtlSecondsSince1970ToTime( st
->st_atime
, &info
->ftLastAccessTime
);
641 info
->dwVolumeSerialNumber
= 0; /* FIXME */
642 info
->nFileSizeHigh
= 0;
643 info
->nFileSizeLow
= 0;
644 if (!S_ISDIR(st
->st_mode
)) {
645 info
->nFileSizeHigh
= st
->st_size
>> 32;
646 info
->nFileSizeLow
= st
->st_size
& 0xffffffff;
648 info
->nNumberOfLinks
= st
->st_nlink
;
649 info
->nFileIndexHigh
= 0;
650 info
->nFileIndexLow
= st
->st_ino
;
654 /***********************************************************************
657 * Stat a Unix path name. Return TRUE if OK.
659 BOOL
FILE_Stat( LPCSTR unixName
, BY_HANDLE_FILE_INFORMATION
*info
)
663 if (lstat( unixName
, &st
) == -1)
668 if (!S_ISLNK(st
.st_mode
)) FILE_FillInfo( &st
, info
);
671 /* do a "real" stat to find out
672 about the type of the symlink destination */
673 if (stat( unixName
, &st
) == -1)
678 FILE_FillInfo( &st
, info
);
679 info
->dwFileAttributes
|= FILE_ATTRIBUTE_SYMLINK
;
685 /***********************************************************************
686 * GetFileInformationByHandle (KERNEL32.@)
688 DWORD WINAPI
GetFileInformationByHandle( HANDLE hFile
,
689 BY_HANDLE_FILE_INFORMATION
*info
)
694 SERVER_START_REQ( get_file_info
)
697 if ((ret
= !wine_server_call_err( req
)))
699 /* FIXME: which file types are supported ?
700 * Serial ports (FILE_TYPE_CHAR) are not,
701 * and MSDN also says that pipes are not supported.
702 * FILE_TYPE_REMOTE seems to be supported according to
703 * MSDN q234741.txt */
704 if ((reply
->type
== FILE_TYPE_DISK
) || (reply
->type
== FILE_TYPE_REMOTE
))
706 RtlSecondsSince1970ToTime( reply
->write_time
, &info
->ftCreationTime
);
707 RtlSecondsSince1970ToTime( reply
->write_time
, &info
->ftLastWriteTime
);
708 RtlSecondsSince1970ToTime( reply
->access_time
, &info
->ftLastAccessTime
);
709 info
->dwFileAttributes
= reply
->attr
;
710 info
->dwVolumeSerialNumber
= reply
->serial
;
711 info
->nFileSizeHigh
= reply
->size_high
;
712 info
->nFileSizeLow
= reply
->size_low
;
713 info
->nNumberOfLinks
= reply
->links
;
714 info
->nFileIndexHigh
= reply
->index_high
;
715 info
->nFileIndexLow
= reply
->index_low
;
719 SetLastError(ERROR_NOT_SUPPORTED
);
729 /**************************************************************************
730 * GetFileAttributes (KERNEL.420)
732 DWORD WINAPI
GetFileAttributes16( LPCSTR name
)
734 return GetFileAttributesA( name
);
738 /**************************************************************************
739 * GetFileAttributesA (KERNEL32.@)
741 DWORD WINAPI
GetFileAttributesA( LPCSTR name
)
743 DOS_FULL_NAME full_name
;
744 BY_HANDLE_FILE_INFORMATION info
;
748 SetLastError( ERROR_INVALID_PARAMETER
);
751 if (!DOSFS_GetFullName( name
, TRUE
, &full_name
) )
753 if (!FILE_Stat( full_name
.long_name
, &info
)) return -1;
754 return info
.dwFileAttributes
;
758 /**************************************************************************
759 * GetFileAttributesW (KERNEL32.@)
761 DWORD WINAPI
GetFileAttributesW( LPCWSTR name
)
763 LPSTR nameA
= HEAP_strdupWtoA( GetProcessHeap(), 0, name
);
764 DWORD res
= GetFileAttributesA( nameA
);
765 HeapFree( GetProcessHeap(), 0, nameA
);
770 /**************************************************************************
771 * SetFileAttributes (KERNEL.421)
773 BOOL16 WINAPI
SetFileAttributes16( LPCSTR lpFileName
, DWORD attributes
)
775 return SetFileAttributesA( lpFileName
, attributes
);
779 /**************************************************************************
780 * SetFileAttributesA (KERNEL32.@)
782 BOOL WINAPI
SetFileAttributesA(LPCSTR lpFileName
, DWORD attributes
)
785 DOS_FULL_NAME full_name
;
787 if (!DOSFS_GetFullName( lpFileName
, TRUE
, &full_name
))
790 TRACE("(%s,%lx)\n",lpFileName
,attributes
);
791 if(stat(full_name
.long_name
,&buf
)==-1)
796 if (attributes
& FILE_ATTRIBUTE_READONLY
)
798 if(S_ISDIR(buf
.st_mode
))
800 WARN("FILE_ATTRIBUTE_READONLY ignored for directory.\n");
802 buf
.st_mode
&= ~0222; /* octal!, clear write permission bits */
803 attributes
&= ~FILE_ATTRIBUTE_READONLY
;
807 /* add write permission */
808 buf
.st_mode
|= (0600 | ((buf
.st_mode
& 044) >> 1)) & (~FILE_umask
);
810 if (attributes
& FILE_ATTRIBUTE_DIRECTORY
)
812 if (!S_ISDIR(buf
.st_mode
))
813 FIXME("SetFileAttributes expected the file '%s' to be a directory\n",
815 attributes
&= ~FILE_ATTRIBUTE_DIRECTORY
;
817 attributes
&= ~(FILE_ATTRIBUTE_NORMAL
|FILE_ATTRIBUTE_ARCHIVE
|FILE_ATTRIBUTE_HIDDEN
|FILE_ATTRIBUTE_SYSTEM
);
819 FIXME("(%s):%lx attribute(s) not implemented.\n", lpFileName
,attributes
);
820 if (-1==chmod(full_name
.long_name
,buf
.st_mode
))
822 if(GetDriveTypeA(lpFileName
) == DRIVE_CDROM
) {
823 SetLastError( ERROR_ACCESS_DENIED
);
828 * FIXME: We don't return FALSE here because of differences between
829 * Linux and Windows privileges. Under Linux only the owner of
830 * the file is allowed to change file attributes. Under Windows,
831 * applications expect that if you can write to a file, you can also
832 * change its attributes (see GENERIC_WRITE). We could try to be
833 * clever here but that would break multi-user installations where
834 * users share read-only DLLs. This is because some installers like
835 * to change attributes of already installed DLLs.
837 FIXME("Couldn't set file attributes for existing file \"%s\".\n"
838 "Check permissions or set VFAT \"quiet\" mount flag\n", full_name
.long_name
);
844 /**************************************************************************
845 * SetFileAttributesW (KERNEL32.@)
847 BOOL WINAPI
SetFileAttributesW(LPCWSTR lpFileName
, DWORD attributes
)
850 DWORD len
= WideCharToMultiByte( CP_ACP
, 0, lpFileName
, -1, NULL
, 0, NULL
, NULL
);
851 LPSTR afn
= HeapAlloc( GetProcessHeap(), 0, len
);
853 WideCharToMultiByte( CP_ACP
, 0, lpFileName
, -1, afn
, len
, NULL
, NULL
);
854 res
= SetFileAttributesA( afn
, attributes
);
855 HeapFree( GetProcessHeap(), 0, afn
);
860 /***********************************************************************
861 * GetFileSize (KERNEL32.@)
863 DWORD WINAPI
GetFileSize( HANDLE hFile
, LPDWORD filesizehigh
)
865 BY_HANDLE_FILE_INFORMATION info
;
866 if (!GetFileInformationByHandle( hFile
, &info
)) return -1;
867 if (filesizehigh
) *filesizehigh
= info
.nFileSizeHigh
;
868 return info
.nFileSizeLow
;
872 /***********************************************************************
873 * GetFileTime (KERNEL32.@)
875 BOOL WINAPI
GetFileTime( HANDLE hFile
, FILETIME
*lpCreationTime
,
876 FILETIME
*lpLastAccessTime
,
877 FILETIME
*lpLastWriteTime
)
879 BY_HANDLE_FILE_INFORMATION info
;
880 if (!GetFileInformationByHandle( hFile
, &info
)) return FALSE
;
881 if (lpCreationTime
) *lpCreationTime
= info
.ftCreationTime
;
882 if (lpLastAccessTime
) *lpLastAccessTime
= info
.ftLastAccessTime
;
883 if (lpLastWriteTime
) *lpLastWriteTime
= info
.ftLastWriteTime
;
887 /***********************************************************************
888 * CompareFileTime (KERNEL32.@)
890 INT WINAPI
CompareFileTime( LPFILETIME x
, LPFILETIME y
)
892 if (!x
|| !y
) return -1;
894 if (x
->dwHighDateTime
> y
->dwHighDateTime
)
896 if (x
->dwHighDateTime
< y
->dwHighDateTime
)
898 if (x
->dwLowDateTime
> y
->dwLowDateTime
)
900 if (x
->dwLowDateTime
< y
->dwLowDateTime
)
905 /***********************************************************************
906 * FILE_GetTempFileName : utility for GetTempFileName
908 static UINT
FILE_GetTempFileName( LPCSTR path
, LPCSTR prefix
, UINT unique
,
909 LPSTR buffer
, BOOL isWin16
)
911 static UINT unique_temp
;
912 DOS_FULL_NAME full_name
;
917 if ( !path
|| !prefix
|| !buffer
) return 0;
919 if (!unique_temp
) unique_temp
= time(NULL
) & 0xffff;
920 num
= unique
? (unique
& 0xffff) : (unique_temp
++ & 0xffff);
922 strcpy( buffer
, path
);
923 p
= buffer
+ strlen(buffer
);
925 /* add a \, if there isn't one and path is more than just the drive letter ... */
926 if ( !((strlen(buffer
) == 2) && (buffer
[1] == ':'))
927 && ((p
== buffer
) || (p
[-1] != '\\'))) *p
++ = '\\';
929 if (isWin16
) *p
++ = '~';
930 for (i
= 3; (i
> 0) && (*prefix
); i
--) *p
++ = *prefix
++;
931 sprintf( p
, "%04x.tmp", num
);
933 /* Now try to create it */
939 HFILE handle
= CreateFileA( buffer
, GENERIC_WRITE
, 0, NULL
,
940 CREATE_NEW
, FILE_ATTRIBUTE_NORMAL
, 0 );
941 if (handle
!= INVALID_HANDLE_VALUE
)
942 { /* We created it */
943 TRACE("created %s\n",
945 CloseHandle( handle
);
948 if (GetLastError() != ERROR_FILE_EXISTS
)
949 break; /* No need to go on */
951 sprintf( p
, "%04x.tmp", num
);
952 } while (num
!= (unique
& 0xffff));
955 /* Get the full path name */
957 if (DOSFS_GetFullName( buffer
, FALSE
, &full_name
))
959 /* Check if we have write access in the directory */
960 if ((p
= strrchr( full_name
.long_name
, '/' ))) *p
= '\0';
961 if (access( full_name
.long_name
, W_OK
) == -1)
962 WARN("returns '%s', which doesn't seem to be writeable.\n",
965 TRACE("returning %s\n", buffer
);
966 return unique
? unique
: num
;
970 /***********************************************************************
971 * GetTempFileNameA (KERNEL32.@)
973 UINT WINAPI
GetTempFileNameA( LPCSTR path
, LPCSTR prefix
, UINT unique
,
976 return FILE_GetTempFileName(path
, prefix
, unique
, buffer
, FALSE
);
979 /***********************************************************************
980 * GetTempFileNameW (KERNEL32.@)
982 UINT WINAPI
GetTempFileNameW( LPCWSTR path
, LPCWSTR prefix
, UINT unique
,
990 patha
= HEAP_strdupWtoA( GetProcessHeap(), 0, path
);
991 prefixa
= HEAP_strdupWtoA( GetProcessHeap(), 0, prefix
);
992 ret
= FILE_GetTempFileName( patha
, prefixa
, unique
, buffera
, FALSE
);
993 MultiByteToWideChar( CP_ACP
, 0, buffera
, -1, buffer
, MAX_PATH
);
994 HeapFree( GetProcessHeap(), 0, patha
);
995 HeapFree( GetProcessHeap(), 0, prefixa
);
1000 /***********************************************************************
1001 * GetTempFileName (KERNEL.97)
1003 UINT16 WINAPI
GetTempFileName16( BYTE drive
, LPCSTR prefix
, UINT16 unique
,
1008 if (!(drive
& ~TF_FORCEDRIVE
)) /* drive 0 means current default drive */
1009 drive
|= DRIVE_GetCurrentDrive() + 'A';
1011 if ((drive
& TF_FORCEDRIVE
) &&
1012 !DRIVE_IsValid( toupper(drive
& ~TF_FORCEDRIVE
) - 'A' ))
1014 drive
&= ~TF_FORCEDRIVE
;
1015 WARN("invalid drive %d specified\n", drive
);
1018 if (drive
& TF_FORCEDRIVE
)
1019 sprintf(temppath
,"%c:", drive
& ~TF_FORCEDRIVE
);
1021 GetTempPathA( 132, temppath
);
1022 return (UINT16
)FILE_GetTempFileName( temppath
, prefix
, unique
, buffer
, TRUE
);
1025 /***********************************************************************
1028 * Implementation of OpenFile16() and OpenFile32().
1030 static HFILE
FILE_DoOpenFile( LPCSTR name
, OFSTRUCT
*ofs
, UINT mode
,
1035 WORD filedatetime
[2];
1036 DOS_FULL_NAME full_name
;
1037 DWORD access
, sharing
;
1040 if (!ofs
) return HFILE_ERROR
;
1042 TRACE("%s %s %s %s%s%s%s%s%s%s%s%s\n",name
,
1043 ((mode
& 0x3 )==OF_READ
)?"OF_READ":
1044 ((mode
& 0x3 )==OF_WRITE
)?"OF_WRITE":
1045 ((mode
& 0x3 )==OF_READWRITE
)?"OF_READWRITE":"unknown",
1046 ((mode
& 0x70 )==OF_SHARE_COMPAT
)?"OF_SHARE_COMPAT":
1047 ((mode
& 0x70 )==OF_SHARE_DENY_NONE
)?"OF_SHARE_DENY_NONE":
1048 ((mode
& 0x70 )==OF_SHARE_DENY_READ
)?"OF_SHARE_DENY_READ":
1049 ((mode
& 0x70 )==OF_SHARE_DENY_WRITE
)?"OF_SHARE_DENY_WRITE":
1050 ((mode
& 0x70 )==OF_SHARE_EXCLUSIVE
)?"OF_SHARE_EXCLUSIVE":"unknown",
1051 ((mode
& OF_PARSE
)==OF_PARSE
)?"OF_PARSE ":"",
1052 ((mode
& OF_DELETE
)==OF_DELETE
)?"OF_DELETE ":"",
1053 ((mode
& OF_VERIFY
)==OF_VERIFY
)?"OF_VERIFY ":"",
1054 ((mode
& OF_SEARCH
)==OF_SEARCH
)?"OF_SEARCH ":"",
1055 ((mode
& OF_CANCEL
)==OF_CANCEL
)?"OF_CANCEL ":"",
1056 ((mode
& OF_CREATE
)==OF_CREATE
)?"OF_CREATE ":"",
1057 ((mode
& OF_PROMPT
)==OF_PROMPT
)?"OF_PROMPT ":"",
1058 ((mode
& OF_EXIST
)==OF_EXIST
)?"OF_EXIST ":"",
1059 ((mode
& OF_REOPEN
)==OF_REOPEN
)?"OF_REOPEN ":""
1063 ofs
->cBytes
= sizeof(OFSTRUCT
);
1065 if (mode
& OF_REOPEN
) name
= ofs
->szPathName
;
1068 ERR("called with `name' set to NULL ! Please debug.\n");
1072 TRACE("%s %04x\n", name
, mode
);
1074 /* the watcom 10.6 IDE relies on a valid path returned in ofs->szPathName
1075 Are there any cases where getting the path here is wrong?
1076 Uwe Bonnes 1997 Apr 2 */
1077 if (!GetFullPathNameA( name
, sizeof(ofs
->szPathName
),
1078 ofs
->szPathName
, NULL
)) goto error
;
1079 FILE_ConvertOFMode( mode
, &access
, &sharing
);
1081 /* OF_PARSE simply fills the structure */
1083 if (mode
& OF_PARSE
)
1085 ofs
->fFixedDisk
= (GetDriveType16( ofs
->szPathName
[0]-'A' )
1086 != DRIVE_REMOVABLE
);
1087 TRACE("(%s): OF_PARSE, res = '%s'\n",
1088 name
, ofs
->szPathName
);
1092 /* OF_CREATE is completely different from all other options, so
1095 if (mode
& OF_CREATE
)
1097 if ((hFileRet
= CreateFileA( name
, GENERIC_READ
| GENERIC_WRITE
,
1098 sharing
, NULL
, CREATE_ALWAYS
,
1099 FILE_ATTRIBUTE_NORMAL
, 0 ))== INVALID_HANDLE_VALUE
)
1104 /* If OF_SEARCH is set, ignore the given path */
1106 if ((mode
& OF_SEARCH
) && !(mode
& OF_REOPEN
))
1108 /* First try the file name as is */
1109 if (DOSFS_GetFullName( name
, TRUE
, &full_name
)) goto found
;
1110 /* Now remove the path */
1111 if (name
[0] && (name
[1] == ':')) name
+= 2;
1112 if ((p
= strrchr( name
, '\\' ))) name
= p
+ 1;
1113 if ((p
= strrchr( name
, '/' ))) name
= p
+ 1;
1114 if (!name
[0]) goto not_found
;
1117 /* Now look for the file */
1119 if (!DIR_SearchPath( NULL
, name
, NULL
, &full_name
, win32
)) goto not_found
;
1122 TRACE("found %s = %s\n",
1123 full_name
.long_name
, full_name
.short_name
);
1124 lstrcpynA( ofs
->szPathName
, full_name
.short_name
,
1125 sizeof(ofs
->szPathName
) );
1127 if (mode
& OF_SHARE_EXCLUSIVE
)
1128 /* Some InstallShield version uses OF_SHARE_EXCLUSIVE
1129 on the file <tempdir>/_ins0432._mp to determine how
1130 far installation has proceeded.
1131 _ins0432._mp is an executable and while running the
1132 application expects the open with OF_SHARE_ to fail*/
1134 As our loader closes the files after loading the executable,
1135 we can't find the running executable with FILE_InUse.
1136 The loader should keep the file open, as Windows does that, too.
1139 char *last
= strrchr(full_name
.long_name
,'/');
1141 last
= full_name
.long_name
- 1;
1142 if (GetModuleHandle16(last
+1))
1144 TRACE("Denying shared open for %s\n",full_name
.long_name
);
1149 if (mode
& OF_DELETE
)
1151 if (unlink( full_name
.long_name
) == -1) goto not_found
;
1152 TRACE("(%s): OF_DELETE return = OK\n", name
);
1156 hFileRet
= FILE_CreateFile( full_name
.long_name
, access
, sharing
,
1157 NULL
, OPEN_EXISTING
, 0, 0,
1158 DRIVE_GetFlags(full_name
.drive
) & DRIVE_FAIL_READ_ONLY
,
1159 GetDriveTypeA( full_name
.short_name
) );
1160 if (!hFileRet
) goto not_found
;
1162 GetFileTime( hFileRet
, NULL
, NULL
, &filetime
);
1163 FileTimeToDosDateTime( &filetime
, &filedatetime
[0], &filedatetime
[1] );
1164 if ((mode
& OF_VERIFY
) && (mode
& OF_REOPEN
))
1166 if (memcmp( ofs
->reserved
, filedatetime
, sizeof(ofs
->reserved
) ))
1168 CloseHandle( hFileRet
);
1169 WARN("(%s): OF_VERIFY failed\n", name
);
1170 /* FIXME: what error here? */
1171 SetLastError( ERROR_FILE_NOT_FOUND
);
1175 memcpy( ofs
->reserved
, filedatetime
, sizeof(ofs
->reserved
) );
1177 success
: /* We get here if the open was successful */
1178 TRACE("(%s): OK, return = %d\n", name
, hFileRet
);
1181 if (mode
& OF_EXIST
) /* Return the handle, but close it first */
1182 CloseHandle( hFileRet
);
1186 hFileRet
= Win32HandleToDosFileHandle( hFileRet
);
1187 if (hFileRet
== HFILE_ERROR16
) goto error
;
1188 if (mode
& OF_EXIST
) /* Return the handle, but close it first */
1189 _lclose16( hFileRet
);
1193 not_found
: /* We get here if the file does not exist */
1194 WARN("'%s' not found or sharing violation\n", name
);
1195 SetLastError( ERROR_FILE_NOT_FOUND
);
1198 error
: /* We get here if there was an error opening the file */
1199 ofs
->nErrCode
= GetLastError();
1200 WARN("(%s): return = HFILE_ERROR error= %d\n",
1201 name
,ofs
->nErrCode
);
1206 /***********************************************************************
1207 * OpenFile (KERNEL.74)
1208 * OpenFileEx (KERNEL.360)
1210 HFILE16 WINAPI
OpenFile16( LPCSTR name
, OFSTRUCT
*ofs
, UINT16 mode
)
1212 return FILE_DoOpenFile( name
, ofs
, mode
, FALSE
);
1216 /***********************************************************************
1217 * OpenFile (KERNEL32.@)
1219 HFILE WINAPI
OpenFile( LPCSTR name
, OFSTRUCT
*ofs
, UINT mode
)
1221 return FILE_DoOpenFile( name
, ofs
, mode
, TRUE
);
1225 /***********************************************************************
1226 * FILE_InitProcessDosHandles
1228 * Allocates the default DOS handles for a process. Called either by
1229 * Win32HandleToDosFileHandle below or by the DOSVM stuff.
1231 static void FILE_InitProcessDosHandles( void )
1233 dos_handles
[0] = GetStdHandle(STD_INPUT_HANDLE
);
1234 dos_handles
[1] = GetStdHandle(STD_OUTPUT_HANDLE
);
1235 dos_handles
[2] = GetStdHandle(STD_ERROR_HANDLE
);
1236 dos_handles
[3] = GetStdHandle(STD_ERROR_HANDLE
);
1237 dos_handles
[4] = GetStdHandle(STD_ERROR_HANDLE
);
1240 /***********************************************************************
1241 * Win32HandleToDosFileHandle (KERNEL32.21)
1243 * Allocate a DOS handle for a Win32 handle. The Win32 handle is no
1244 * longer valid after this function (even on failure).
1246 * Note: this is not exactly right, since on Win95 the Win32 handles
1247 * are on top of DOS handles and we do it the other way
1248 * around. Should be good enough though.
1250 HFILE WINAPI
Win32HandleToDosFileHandle( HANDLE handle
)
1254 if (!handle
|| (handle
== INVALID_HANDLE_VALUE
))
1257 for (i
= 5; i
< DOS_TABLE_SIZE
; i
++)
1258 if (!dos_handles
[i
])
1260 dos_handles
[i
] = handle
;
1261 TRACE("Got %d for h32 %d\n", i
, handle
);
1264 CloseHandle( handle
);
1265 SetLastError( ERROR_TOO_MANY_OPEN_FILES
);
1270 /***********************************************************************
1271 * DosFileHandleToWin32Handle (KERNEL32.20)
1273 * Return the Win32 handle for a DOS handle.
1275 * Note: this is not exactly right, since on Win95 the Win32 handles
1276 * are on top of DOS handles and we do it the other way
1277 * around. Should be good enough though.
1279 HANDLE WINAPI
DosFileHandleToWin32Handle( HFILE handle
)
1281 HFILE16 hfile
= (HFILE16
)handle
;
1282 if (hfile
< 5 && !dos_handles
[hfile
]) FILE_InitProcessDosHandles();
1283 if ((hfile
>= DOS_TABLE_SIZE
) || !dos_handles
[hfile
])
1285 SetLastError( ERROR_INVALID_HANDLE
);
1286 return INVALID_HANDLE_VALUE
;
1288 return dos_handles
[hfile
];
1292 /***********************************************************************
1293 * DisposeLZ32Handle (KERNEL32.22)
1295 * Note: this is not entirely correct, we should only close the
1296 * 32-bit handle and not the 16-bit one, but we cannot do
1297 * this because of the way our DOS handles are implemented.
1298 * It shouldn't break anything though.
1300 void WINAPI
DisposeLZ32Handle( HANDLE handle
)
1304 if (!handle
|| (handle
== INVALID_HANDLE_VALUE
)) return;
1306 for (i
= 5; i
< DOS_TABLE_SIZE
; i
++)
1307 if (dos_handles
[i
] == handle
)
1310 CloseHandle( handle
);
1316 /***********************************************************************
1319 * dup2() function for DOS handles.
1321 HFILE16
FILE_Dup2( HFILE16 hFile1
, HFILE16 hFile2
)
1325 if (hFile1
< 5 && !dos_handles
[hFile1
]) FILE_InitProcessDosHandles();
1327 if ((hFile1
>= DOS_TABLE_SIZE
) || (hFile2
>= DOS_TABLE_SIZE
) || !dos_handles
[hFile1
])
1329 SetLastError( ERROR_INVALID_HANDLE
);
1330 return HFILE_ERROR16
;
1334 FIXME("stdio handle closed, need proper conversion\n" );
1335 SetLastError( ERROR_INVALID_HANDLE
);
1336 return HFILE_ERROR16
;
1338 if (!DuplicateHandle( GetCurrentProcess(), dos_handles
[hFile1
],
1339 GetCurrentProcess(), &new_handle
,
1340 0, FALSE
, DUPLICATE_SAME_ACCESS
))
1341 return HFILE_ERROR16
;
1342 if (dos_handles
[hFile2
]) CloseHandle( dos_handles
[hFile2
] );
1343 dos_handles
[hFile2
] = new_handle
;
1348 /***********************************************************************
1349 * _lclose (KERNEL.81)
1351 HFILE16 WINAPI
_lclose16( HFILE16 hFile
)
1355 FIXME("stdio handle closed, need proper conversion\n" );
1356 SetLastError( ERROR_INVALID_HANDLE
);
1357 return HFILE_ERROR16
;
1359 if ((hFile
>= DOS_TABLE_SIZE
) || !dos_handles
[hFile
])
1361 SetLastError( ERROR_INVALID_HANDLE
);
1362 return HFILE_ERROR16
;
1364 TRACE("%d (handle32=%d)\n", hFile
, dos_handles
[hFile
] );
1365 CloseHandle( dos_handles
[hFile
] );
1366 dos_handles
[hFile
] = 0;
1371 /***********************************************************************
1372 * _lclose (KERNEL32.@)
1374 HFILE WINAPI
_lclose( HFILE hFile
)
1376 TRACE("handle %d\n", hFile
);
1377 return CloseHandle( hFile
) ? 0 : HFILE_ERROR
;
1380 /***********************************************************************
1381 * GetOverlappedResult (KERNEL32.@)
1383 * Check the result of an Asynchronous data transfer from a file.
1389 * If successful (and relevant) lpTransferred will hold the number of
1390 * bytes transferred during the async operation.
1394 * Currently only works for WaitCommEvent, ReadFile, WriteFile
1395 * with communications ports.
1398 BOOL WINAPI
GetOverlappedResult(
1399 HANDLE hFile
, /* [in] handle of file to check on */
1400 LPOVERLAPPED lpOverlapped
, /* [in/out] pointer to overlapped */
1401 LPDWORD lpTransferred
, /* [in/out] number of bytes transferred */
1402 BOOL bWait
/* [in] wait for the transfer to complete ? */
1406 TRACE("(%d %p %p %x)\n", hFile
, lpOverlapped
, lpTransferred
, bWait
);
1408 if(lpOverlapped
==NULL
)
1410 ERR("lpOverlapped was null\n");
1413 if(!lpOverlapped
->hEvent
)
1415 ERR("lpOverlapped->hEvent was null\n");
1420 TRACE("waiting on %p\n",lpOverlapped
);
1421 r
= WaitForSingleObjectEx(lpOverlapped
->hEvent
, bWait
?INFINITE
:0, TRUE
);
1422 TRACE("wait on %p returned %ld\n",lpOverlapped
,r
);
1423 } while (r
==STATUS_USER_APC
);
1426 *lpTransferred
= lpOverlapped
->InternalHigh
;
1428 SetLastError ( lpOverlapped
->Internal
== STATUS_PENDING
?
1429 ERROR_IO_INCOMPLETE
: RtlNtStatusToDosError ( lpOverlapped
->Internal
) );
1431 return (r
==WAIT_OBJECT_0
);
1434 /***********************************************************************
1435 * CancelIo (KERNEL32.@)
1437 BOOL WINAPI
CancelIo(HANDLE handle
)
1439 async_private
*ovp
,*t
;
1441 TRACE("handle = %x\n",handle
);
1443 for (ovp
= NtCurrentTeb()->pending_list
; ovp
; ovp
= t
)
1446 if ( ovp
->handle
== handle
)
1447 cancel_async ( ovp
);
1449 WaitForMultipleObjectsEx(0,NULL
,FALSE
,1,TRUE
);
1453 /***********************************************************************
1454 * FILE_AsyncReadService (INTERNAL)
1456 * This function is called while the client is waiting on the
1457 * server, so we can't make any server calls here.
1459 static void FILE_AsyncReadService(async_private
*ovp
)
1461 async_fileio
*fileio
= (async_fileio
*) ovp
;
1462 LPOVERLAPPED lpOverlapped
= fileio
->lpOverlapped
;
1464 int already
= lpOverlapped
->InternalHigh
;
1466 TRACE("%p %p\n", lpOverlapped
, fileio
->buffer
);
1468 /* check to see if the data is ready (non-blocking) */
1470 if ( fileio
->fd_type
== FD_TYPE_SOCKET
)
1471 result
= read (ovp
->fd
, &fileio
->buffer
[already
], fileio
->count
- already
);
1474 result
= pread (ovp
->fd
, &fileio
->buffer
[already
], fileio
->count
- already
,
1475 OVERLAPPED_OFFSET (lpOverlapped
) + already
);
1476 if ((result
< 0) && (errno
== ESPIPE
))
1477 result
= read (ovp
->fd
, &fileio
->buffer
[already
], fileio
->count
- already
);
1480 if ( (result
<0) && ((errno
== EAGAIN
) || (errno
== EINTR
)))
1482 TRACE("Deferred read %d\n",errno
);
1487 /* check to see if the transfer is complete */
1490 r
= FILE_GetNtStatus ();
1494 lpOverlapped
->InternalHigh
+= result
;
1495 TRACE("read %d more bytes %ld/%d so far\n",result
,lpOverlapped
->InternalHigh
,fileio
->count
);
1497 if(lpOverlapped
->InternalHigh
>= fileio
->count
|| fileio
->fd_type
== FD_TYPE_SOCKET
)
1503 lpOverlapped
->Internal
= r
;
1506 /***********************************************************************
1507 * FILE_ReadFileEx (INTERNAL)
1509 static BOOL
FILE_ReadFileEx(HANDLE hFile
, LPVOID buffer
, DWORD bytesToRead
,
1510 LPOVERLAPPED overlapped
,
1511 LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine
,
1519 TRACE("file %d to buf %p num %ld %p func %p\n",
1520 hFile
, buffer
, bytesToRead
, overlapped
, lpCompletionRoutine
);
1522 /* check that there is an overlapped struct */
1523 if (overlapped
==NULL
)
1525 SetLastError(ERROR_INVALID_PARAMETER
);
1529 fd
= FILE_GetUnixHandleType ( hFile
, GENERIC_READ
, &type
, &flags
);
1532 WARN ( "Couldn't get FD\n" );
1536 ovp
= (async_fileio
*) HeapAlloc(GetProcessHeap(), 0, sizeof (async_fileio
));
1539 TRACE("HeapAlloc Failed\n");
1540 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
1544 ovp
->async
.ops
= ( lpCompletionRoutine
? &fileio_async_ops
: &fileio_nocomp_async_ops
);
1545 ovp
->async
.handle
= hFile
;
1547 ovp
->async
.type
= ASYNC_TYPE_READ
;
1548 ovp
->async
.func
= FILE_AsyncReadService
;
1549 ovp
->async
.event
= hEvent
;
1550 ovp
->lpOverlapped
= overlapped
;
1551 ovp
->count
= bytesToRead
;
1552 ovp
->completion_func
= lpCompletionRoutine
;
1553 ovp
->buffer
= buffer
;
1554 ovp
->fd_type
= type
;
1556 return !register_new_async (&ovp
->async
);
1564 /***********************************************************************
1565 * ReadFileEx (KERNEL32.@)
1567 BOOL WINAPI
ReadFileEx(HANDLE hFile
, LPVOID buffer
, DWORD bytesToRead
,
1568 LPOVERLAPPED overlapped
,
1569 LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine
)
1571 overlapped
->InternalHigh
= 0;
1572 return FILE_ReadFileEx(hFile
,buffer
,bytesToRead
,overlapped
,lpCompletionRoutine
, INVALID_HANDLE_VALUE
);
1575 static BOOL
FILE_TimeoutRead(HANDLE hFile
, LPVOID buffer
, DWORD bytesToRead
, LPDWORD bytesRead
)
1580 TRACE("%d %p %ld %p\n", hFile
, buffer
, bytesToRead
, bytesRead
);
1582 ZeroMemory(&ov
, sizeof (OVERLAPPED
));
1583 if(STATUS_SUCCESS
==NtCreateEvent(&ov
.hEvent
, SYNCHRONIZE
, NULL
, 0, 0))
1585 if(FILE_ReadFileEx(hFile
, buffer
, bytesToRead
, &ov
, NULL
, ov
.hEvent
))
1587 r
= GetOverlappedResult(hFile
, &ov
, bytesRead
, TRUE
);
1590 CloseHandle(ov
.hEvent
);
1594 /***********************************************************************
1595 * ReadFile (KERNEL32.@)
1597 BOOL WINAPI
ReadFile( HANDLE hFile
, LPVOID buffer
, DWORD bytesToRead
,
1598 LPDWORD bytesRead
, LPOVERLAPPED overlapped
)
1600 int unix_handle
, result
, flags
;
1603 TRACE("%d %p %ld %p %p\n", hFile
, buffer
, bytesToRead
,
1604 bytesRead
, overlapped
);
1606 if (bytesRead
) *bytesRead
= 0; /* Do this before anything else */
1607 if (!bytesToRead
) return TRUE
;
1609 unix_handle
= FILE_GetUnixHandleType( hFile
, GENERIC_READ
, &type
, &flags
);
1611 if (flags
& FD_FLAG_OVERLAPPED
)
1613 if (unix_handle
== -1) return FALSE
;
1614 if ( (overlapped
==NULL
) || NtResetEvent( overlapped
->hEvent
, NULL
) )
1616 TRACE("Overlapped not specified or invalid event flag\n");
1618 SetLastError(ERROR_INVALID_PARAMETER
);
1623 overlapped
->InternalHigh
= 0;
1625 if(!FILE_ReadFileEx(hFile
, buffer
, bytesToRead
, overlapped
, NULL
, overlapped
->hEvent
))
1628 if ( !GetOverlappedResult (hFile
, overlapped
, bytesRead
, FALSE
) )
1630 if ( GetLastError() == ERROR_IO_INCOMPLETE
)
1631 SetLastError ( ERROR_IO_PENDING
);
1637 if (flags
& FD_FLAG_TIMEOUT
)
1640 return FILE_TimeoutRead(hFile
, buffer
, bytesToRead
, bytesRead
);
1645 return SMB_ReadFile(hFile
, buffer
, bytesToRead
, bytesRead
, NULL
);
1646 case FD_TYPE_CONSOLE
:
1647 return ReadConsoleA(hFile
, buffer
, bytesToRead
, bytesRead
, NULL
);
1650 /* normal unix files */
1651 if (unix_handle
== -1)
1656 SetLastError(ERROR_INVALID_PARAMETER
);
1662 /* code for synchronous reads */
1663 while ((result
= read( unix_handle
, buffer
, bytesToRead
)) == -1)
1665 if ((errno
== EAGAIN
) || (errno
== EINTR
)) continue;
1666 if ((errno
== EFAULT
) && !IsBadWritePtr( buffer
, bytesToRead
)) continue;
1670 close( unix_handle
);
1671 if (result
== -1) return FALSE
;
1672 if (bytesRead
) *bytesRead
= result
;
1677 /***********************************************************************
1678 * FILE_AsyncWriteService (INTERNAL)
1680 * This function is called while the client is waiting on the
1681 * server, so we can't make any server calls here.
1683 static void FILE_AsyncWriteService(struct async_private
*ovp
)
1685 async_fileio
*fileio
= (async_fileio
*) ovp
;
1686 LPOVERLAPPED lpOverlapped
= fileio
->lpOverlapped
;
1688 int already
= lpOverlapped
->InternalHigh
;
1690 TRACE("(%p %p)\n",lpOverlapped
,fileio
->buffer
);
1692 /* write some data (non-blocking) */
1694 if ( fileio
->fd_type
== FD_TYPE_SOCKET
)
1695 result
= write(ovp
->fd
, &fileio
->buffer
[already
], fileio
->count
- already
);
1698 result
= pwrite(ovp
->fd
, &fileio
->buffer
[already
], fileio
->count
- already
,
1699 OVERLAPPED_OFFSET (lpOverlapped
) + already
);
1700 if ((result
< 0) && (errno
== ESPIPE
))
1701 result
= write(ovp
->fd
, &fileio
->buffer
[already
], fileio
->count
- already
);
1704 if ( (result
<0) && ((errno
== EAGAIN
) || (errno
== EINTR
)))
1710 /* check to see if the transfer is complete */
1713 r
= FILE_GetNtStatus ();
1717 lpOverlapped
->InternalHigh
+= result
;
1719 TRACE("wrote %d more bytes %ld/%d so far\n",result
,lpOverlapped
->InternalHigh
,fileio
->count
);
1721 if(lpOverlapped
->InternalHigh
< fileio
->count
)
1727 lpOverlapped
->Internal
= r
;
1730 /***********************************************************************
1733 static BOOL
FILE_WriteFileEx(HANDLE hFile
, LPCVOID buffer
, DWORD bytesToWrite
,
1734 LPOVERLAPPED overlapped
,
1735 LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine
,
1743 TRACE("file %d to buf %p num %ld %p func %p handle %d\n",
1744 hFile
, buffer
, bytesToWrite
, overlapped
, lpCompletionRoutine
, hEvent
);
1746 if (overlapped
== NULL
)
1748 SetLastError(ERROR_INVALID_PARAMETER
);
1752 fd
= FILE_GetUnixHandleType ( hFile
, GENERIC_WRITE
, &type
, &flags
);
1755 TRACE( "Couldn't get FD\n" );
1759 ovp
= (async_fileio
*) HeapAlloc(GetProcessHeap(), 0, sizeof (async_fileio
));
1762 TRACE("HeapAlloc Failed\n");
1763 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
1767 ovp
->async
.ops
= ( lpCompletionRoutine
? &fileio_async_ops
: &fileio_nocomp_async_ops
);
1768 ovp
->async
.handle
= hFile
;
1770 ovp
->async
.type
= ASYNC_TYPE_WRITE
;
1771 ovp
->async
.func
= FILE_AsyncWriteService
;
1772 ovp
->lpOverlapped
= overlapped
;
1773 ovp
->async
.event
= hEvent
;
1774 ovp
->buffer
= (LPVOID
) buffer
;
1775 ovp
->count
= bytesToWrite
;
1776 ovp
->completion_func
= lpCompletionRoutine
;
1777 ovp
->fd_type
= type
;
1779 return !register_new_async (&ovp
->async
);
1786 /***********************************************************************
1787 * WriteFileEx (KERNEL32.@)
1789 BOOL WINAPI
WriteFileEx(HANDLE hFile
, LPCVOID buffer
, DWORD bytesToWrite
,
1790 LPOVERLAPPED overlapped
,
1791 LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine
)
1793 overlapped
->InternalHigh
= 0;
1795 return FILE_WriteFileEx(hFile
, buffer
, bytesToWrite
, overlapped
, lpCompletionRoutine
, INVALID_HANDLE_VALUE
);
1798 /***********************************************************************
1799 * WriteFile (KERNEL32.@)
1801 BOOL WINAPI
WriteFile( HANDLE hFile
, LPCVOID buffer
, DWORD bytesToWrite
,
1802 LPDWORD bytesWritten
, LPOVERLAPPED overlapped
)
1804 int unix_handle
, result
, flags
;
1807 TRACE("%d %p %ld %p %p\n", hFile
, buffer
, bytesToWrite
,
1808 bytesWritten
, overlapped
);
1810 if (bytesWritten
) *bytesWritten
= 0; /* Do this before anything else */
1811 if (!bytesToWrite
) return TRUE
;
1813 unix_handle
= FILE_GetUnixHandleType( hFile
, GENERIC_WRITE
, &type
, &flags
);
1815 if (flags
& FD_FLAG_OVERLAPPED
)
1817 if (unix_handle
== -1) return FALSE
;
1818 if ( (overlapped
==NULL
) || NtResetEvent( overlapped
->hEvent
, NULL
) )
1820 TRACE("Overlapped not specified or invalid event flag\n");
1822 SetLastError(ERROR_INVALID_PARAMETER
);
1827 overlapped
->InternalHigh
= 0;
1829 if(!FILE_WriteFileEx(hFile
, buffer
, bytesToWrite
, overlapped
, NULL
, overlapped
->hEvent
))
1832 if ( !GetOverlappedResult (hFile
, overlapped
, bytesWritten
, FALSE
) )
1834 if ( GetLastError() == ERROR_IO_INCOMPLETE
)
1835 SetLastError ( ERROR_IO_PENDING
);
1844 case FD_TYPE_CONSOLE
:
1845 TRACE("%d %s %ld %p %p\n", hFile
, debugstr_an(buffer
, bytesToWrite
), bytesToWrite
,
1846 bytesWritten
, overlapped
);
1847 return WriteConsoleA(hFile
, buffer
, bytesToWrite
, bytesWritten
, NULL
);
1849 if (unix_handle
== -1)
1853 /* synchronous file write */
1854 while ((result
= write( unix_handle
, buffer
, bytesToWrite
)) == -1)
1856 if ((errno
== EAGAIN
) || (errno
== EINTR
)) continue;
1857 if ((errno
== EFAULT
) && !IsBadReadPtr( buffer
, bytesToWrite
)) continue;
1858 if (errno
== ENOSPC
)
1859 SetLastError( ERROR_DISK_FULL
);
1864 close( unix_handle
);
1865 if (result
== -1) return FALSE
;
1866 if (bytesWritten
) *bytesWritten
= result
;
1871 /***********************************************************************
1872 * _hread (KERNEL.349)
1874 LONG WINAPI
WIN16_hread( HFILE16 hFile
, SEGPTR buffer
, LONG count
)
1878 TRACE("%d %08lx %ld\n",
1879 hFile
, (DWORD
)buffer
, count
);
1881 /* Some programs pass a count larger than the allocated buffer */
1882 maxlen
= GetSelectorLimit16( SELECTOROF(buffer
) ) - OFFSETOF(buffer
) + 1;
1883 if (count
> maxlen
) count
= maxlen
;
1884 return _lread(DosFileHandleToWin32Handle(hFile
), MapSL(buffer
), count
);
1888 /***********************************************************************
1889 * _lread (KERNEL.82)
1891 UINT16 WINAPI
WIN16_lread( HFILE16 hFile
, SEGPTR buffer
, UINT16 count
)
1893 return (UINT16
)WIN16_hread( hFile
, buffer
, (LONG
)count
);
1897 /***********************************************************************
1898 * _lread (KERNEL32.@)
1900 UINT WINAPI
_lread( HFILE handle
, LPVOID buffer
, UINT count
)
1903 if (!ReadFile( handle
, buffer
, count
, &result
, NULL
)) return -1;
1908 /***********************************************************************
1909 * _lread16 (KERNEL.82)
1911 UINT16 WINAPI
_lread16( HFILE16 hFile
, LPVOID buffer
, UINT16 count
)
1913 return (UINT16
)_lread(DosFileHandleToWin32Handle(hFile
), buffer
, (LONG
)count
);
1917 /***********************************************************************
1918 * _lcreat (KERNEL.83)
1920 HFILE16 WINAPI
_lcreat16( LPCSTR path
, INT16 attr
)
1922 return Win32HandleToDosFileHandle( _lcreat( path
, attr
) );
1926 /***********************************************************************
1927 * _lcreat (KERNEL32.@)
1929 HFILE WINAPI
_lcreat( LPCSTR path
, INT attr
)
1931 /* Mask off all flags not explicitly allowed by the doc */
1932 attr
&= FILE_ATTRIBUTE_READONLY
| FILE_ATTRIBUTE_HIDDEN
| FILE_ATTRIBUTE_SYSTEM
;
1933 TRACE("%s %02x\n", path
, attr
);
1934 return CreateFileA( path
, GENERIC_READ
| GENERIC_WRITE
,
1935 FILE_SHARE_READ
| FILE_SHARE_WRITE
, NULL
,
1936 CREATE_ALWAYS
, attr
, 0 );
1940 /***********************************************************************
1941 * SetFilePointer (KERNEL32.@)
1943 DWORD WINAPI
SetFilePointer( HANDLE hFile
, LONG distance
, LONG
*highword
,
1946 DWORD ret
= 0xffffffff;
1948 TRACE("handle %d offset %ld high %ld origin %ld\n",
1949 hFile
, distance
, highword
?*highword
:0, method
);
1951 SERVER_START_REQ( set_file_pointer
)
1953 req
->handle
= hFile
;
1954 req
->low
= distance
;
1955 req
->high
= highword
? *highword
: (distance
>= 0) ? 0 : -1;
1956 /* FIXME: assumes 1:1 mapping between Windows and Unix seek constants */
1957 req
->whence
= method
;
1959 if (!wine_server_call_err( req
))
1961 ret
= reply
->new_low
;
1962 if (highword
) *highword
= reply
->new_high
;
1970 /***********************************************************************
1971 * _llseek (KERNEL.84)
1974 * Seeking before the start of the file should be allowed for _llseek16,
1975 * but cause subsequent I/O operations to fail (cf. interrupt list)
1978 LONG WINAPI
_llseek16( HFILE16 hFile
, LONG lOffset
, INT16 nOrigin
)
1980 return SetFilePointer( DosFileHandleToWin32Handle(hFile
), lOffset
, NULL
, nOrigin
);
1984 /***********************************************************************
1985 * _llseek (KERNEL32.@)
1987 LONG WINAPI
_llseek( HFILE hFile
, LONG lOffset
, INT nOrigin
)
1989 return SetFilePointer( hFile
, lOffset
, NULL
, nOrigin
);
1993 /***********************************************************************
1994 * _lopen (KERNEL.85)
1996 HFILE16 WINAPI
_lopen16( LPCSTR path
, INT16 mode
)
1998 return Win32HandleToDosFileHandle( _lopen( path
, mode
) );
2002 /***********************************************************************
2003 * _lopen (KERNEL32.@)
2005 HFILE WINAPI
_lopen( LPCSTR path
, INT mode
)
2007 DWORD access
, sharing
;
2009 TRACE("('%s',%04x)\n", path
, mode
);
2010 FILE_ConvertOFMode( mode
, &access
, &sharing
);
2011 return CreateFileA( path
, access
, sharing
, NULL
, OPEN_EXISTING
, 0, 0 );
2015 /***********************************************************************
2016 * _lwrite (KERNEL.86)
2018 UINT16 WINAPI
_lwrite16( HFILE16 hFile
, LPCSTR buffer
, UINT16 count
)
2020 return (UINT16
)_hwrite( DosFileHandleToWin32Handle(hFile
), buffer
, (LONG
)count
);
2023 /***********************************************************************
2024 * _lwrite (KERNEL32.@)
2026 UINT WINAPI
_lwrite( HFILE hFile
, LPCSTR buffer
, UINT count
)
2028 return (UINT
)_hwrite( hFile
, buffer
, (LONG
)count
);
2032 /***********************************************************************
2033 * _hread16 (KERNEL.349)
2035 LONG WINAPI
_hread16( HFILE16 hFile
, LPVOID buffer
, LONG count
)
2037 return _lread( DosFileHandleToWin32Handle(hFile
), buffer
, count
);
2041 /***********************************************************************
2042 * _hread (KERNEL32.@)
2044 LONG WINAPI
_hread( HFILE hFile
, LPVOID buffer
, LONG count
)
2046 return _lread( hFile
, buffer
, count
);
2050 /***********************************************************************
2051 * _hwrite (KERNEL.350)
2053 LONG WINAPI
_hwrite16( HFILE16 hFile
, LPCSTR buffer
, LONG count
)
2055 return _hwrite( DosFileHandleToWin32Handle(hFile
), buffer
, count
);
2059 /***********************************************************************
2060 * _hwrite (KERNEL32.@)
2062 * experimentation yields that _lwrite:
2063 * o truncates the file at the current position with
2065 * o returns 0 on a 0 length write
2066 * o works with console handles
2069 LONG WINAPI
_hwrite( HFILE handle
, LPCSTR buffer
, LONG count
)
2073 TRACE("%d %p %ld\n", handle
, buffer
, count
);
2077 /* Expand or truncate at current position */
2078 if (!SetEndOfFile( handle
)) return HFILE_ERROR
;
2081 if (!WriteFile( handle
, buffer
, count
, &result
, NULL
))
2087 /***********************************************************************
2088 * SetHandleCount (KERNEL.199)
2090 UINT16 WINAPI
SetHandleCount16( UINT16 count
)
2092 return SetHandleCount( count
);
2096 /*************************************************************************
2097 * SetHandleCount (KERNEL32.@)
2099 UINT WINAPI
SetHandleCount( UINT count
)
2101 return min( 256, count
);
2105 /***********************************************************************
2106 * FlushFileBuffers (KERNEL32.@)
2108 BOOL WINAPI
FlushFileBuffers( HANDLE hFile
)
2111 SERVER_START_REQ( flush_file
)
2113 req
->handle
= hFile
;
2114 ret
= !wine_server_call_err( req
);
2121 /**************************************************************************
2122 * SetEndOfFile (KERNEL32.@)
2124 BOOL WINAPI
SetEndOfFile( HANDLE hFile
)
2127 SERVER_START_REQ( truncate_file
)
2129 req
->handle
= hFile
;
2130 ret
= !wine_server_call_err( req
);
2137 /***********************************************************************
2138 * DeleteFile (KERNEL.146)
2140 BOOL16 WINAPI
DeleteFile16( LPCSTR path
)
2142 return DeleteFileA( path
);
2146 /***********************************************************************
2147 * DeleteFileA (KERNEL32.@)
2149 BOOL WINAPI
DeleteFileA( LPCSTR path
)
2151 DOS_FULL_NAME full_name
;
2156 SetLastError(ERROR_INVALID_PARAMETER
);
2159 TRACE("'%s'\n", path
);
2163 ERR("Empty path passed\n");
2166 if (DOSFS_GetDevice( path
))
2168 WARN("cannot remove DOS device '%s'!\n", path
);
2169 SetLastError( ERROR_FILE_NOT_FOUND
);
2173 if (!DOSFS_GetFullName( path
, TRUE
, &full_name
)) return FALSE
;
2175 /* check if we are allowed to delete the source */
2176 hFile
= FILE_CreateFile( full_name
.long_name
, GENERIC_READ
|GENERIC_WRITE
, 0,
2177 NULL
, OPEN_EXISTING
, 0, 0, TRUE
,
2178 GetDriveTypeA( full_name
.short_name
) );
2179 if (!hFile
) return FALSE
;
2181 if (unlink( full_name
.long_name
) == -1)
2192 /***********************************************************************
2193 * DeleteFileW (KERNEL32.@)
2195 BOOL WINAPI
DeleteFileW( LPCWSTR path
)
2197 LPSTR xpath
= HEAP_strdupWtoA( GetProcessHeap(), 0, path
);
2198 BOOL ret
= DeleteFileA( xpath
);
2199 HeapFree( GetProcessHeap(), 0, xpath
);
2204 /***********************************************************************
2205 * GetFileType (KERNEL32.@)
2207 DWORD WINAPI
GetFileType( HANDLE hFile
)
2209 DWORD ret
= FILE_TYPE_UNKNOWN
;
2210 SERVER_START_REQ( get_file_info
)
2212 req
->handle
= hFile
;
2213 if (!wine_server_call_err( req
)) ret
= reply
->type
;
2220 /* check if a file name is for an executable file (.exe or .com) */
2221 inline static BOOL
is_executable( const char *name
)
2223 int len
= strlen(name
);
2225 if (len
< 4) return FALSE
;
2226 return (!strcasecmp( name
+ len
- 4, ".exe" ) ||
2227 !strcasecmp( name
+ len
- 4, ".com" ));
2231 /***********************************************************************
2232 * FILE_AddBootRenameEntry
2234 * Adds an entry to the registry that is loaded when windows boots and
2235 * checks if there are some files to be removed or renamed/moved.
2236 * <fn1> has to be valid and <fn2> may be NULL. If both pointers are
2237 * non-NULL then the file is moved, otherwise it is deleted. The
2238 * entry of the registrykey is always appended with two zero
2239 * terminated strings. If <fn2> is NULL then the second entry is
2240 * simply a single 0-byte. Otherwise the second filename goes
2241 * there. The entries are prepended with \??\ before the path and the
2242 * second filename gets also a '!' as the first character if
2243 * MOVEFILE_REPLACE_EXISTING is set. After the final string another
2244 * 0-byte follows to indicate the end of the strings.
2246 * \??\D:\test\file1[0]
2247 * !\??\D:\test\file1_renamed[0]
2248 * \??\D:\Test|delete[0]
2249 * [0] <- file is to be deleted, second string empty
2250 * \??\D:\test\file2[0]
2251 * !\??\D:\test\file2_renamed[0]
2252 * [0] <- indicates end of strings
2255 * \??\D:\test\file1[0]
2256 * !\??\D:\test\file1_renamed[0]
2257 * \??\D:\Test|delete[0]
2258 * [0] <- file is to be deleted, second string empty
2259 * [0] <- indicates end of strings
2262 static BOOL
FILE_AddBootRenameEntry( const char *fn1
, const char *fn2
, DWORD flags
)
2264 static const char PreString
[] = "\\??\\";
2265 static const char ValueName
[] = "PendingFileRenameOperations";
2269 DWORD Type
, len1
, len2
, l
;
2271 BYTE
*Buffer
= NULL
;
2273 if(RegCreateKeyA(HKEY_LOCAL_MACHINE
, "SYSTEM\\CurrentControlSet\\Control\\Session Manager",
2274 &Reboot
) != ERROR_SUCCESS
)
2276 WARN("Error creating key for reboot managment [%s]\n",
2277 "SYSTEM\\CurrentControlSet\\Control\\Session Manager");
2281 l
= strlen(PreString
);
2282 len1
= strlen(fn1
) + l
+ 1;
2285 len2
= strlen(fn2
) + l
+ 1;
2286 if (flags
& MOVEFILE_REPLACE_EXISTING
) len2
++; /* Plus 1 because of the leading '!' */
2288 else len2
= 1; /* minimum is the 0 byte for the empty second string */
2290 /* First we check if the key exists and if so how many bytes it already contains. */
2291 if (RegQueryValueExA(Reboot
, ValueName
, NULL
, &Type
, NULL
, &DataSize
) == ERROR_SUCCESS
)
2293 if (Type
!= REG_MULTI_SZ
) goto Quit
;
2294 if (!(Buffer
= HeapAlloc( GetProcessHeap(), 0, DataSize
+ len1
+ len2
+ 1 ))) goto Quit
;
2295 if (RegQueryValueExA(Reboot
, ValueName
, NULL
, &Type
, Buffer
, &DataSize
) != ERROR_SUCCESS
)
2297 if (DataSize
) DataSize
--; /* remove terminating null (will be added back later) */
2301 if (!(Buffer
= HeapAlloc( GetProcessHeap(), 0, len1
+ len2
+ 1 ))) goto Quit
;
2304 sprintf( Buffer
+ DataSize
, "%s%s", PreString
, fn1
);
2308 sprintf( Buffer
+ DataSize
, "%s%s%s",
2309 (flags
& MOVEFILE_REPLACE_EXISTING
) ? "!" : "", PreString
, fn2
);
2312 else Buffer
[DataSize
++] = 0;
2314 Buffer
[DataSize
++] = 0; /* add final null */
2315 rc
= !RegSetValueExA( Reboot
, ValueName
, 0, REG_MULTI_SZ
, Buffer
, DataSize
);
2318 if (Reboot
) RegCloseKey(Reboot
);
2319 if (Buffer
) HeapFree( GetProcessHeap(), 0, Buffer
);
2324 /**************************************************************************
2325 * MoveFileExA (KERNEL32.@)
2327 BOOL WINAPI
MoveFileExA( LPCSTR fn1
, LPCSTR fn2
, DWORD flag
)
2329 DOS_FULL_NAME full_name1
, full_name2
;
2332 TRACE("(%s,%s,%04lx)\n", fn1
, fn2
, flag
);
2334 /* FIXME: <Gerhard W. Gruber>sparhawk@gmx.at
2335 In case of W9x and lesser this function should return 120 (ERROR_CALL_NOT_IMPLEMENTED)
2336 to be really compatible. Most programs wont have any problems though. In case
2337 you encounter one, this is what you should return here. I don't know what's up
2338 with NT 3.5. Is this function available there or not?
2339 Does anybody really care about 3.5? :)
2342 /* Filename1 has to be always set to a valid path. Filename2 may be NULL
2343 if the source file has to be deleted.
2346 SetLastError(ERROR_INVALID_PARAMETER
);
2350 /* This function has to be run through in order to process the name properly.
2351 If the BOOTDELAY flag is set, the file doesn't need to exist though. At least
2352 that is the behaviour on NT 4.0. The operation accepts the filenames as
2353 they are given but it can't reply with a reasonable returncode. Success
2354 means in that case success for entering the values into the registry.
2356 if(!DOSFS_GetFullName( fn1
, TRUE
, &full_name1
))
2358 if(!(flag
& MOVEFILE_DELAY_UNTIL_REBOOT
))
2362 if (fn2
) /* !fn2 means delete fn1 */
2364 if (DOSFS_GetFullName( fn2
, TRUE
, &full_name2
))
2366 if(!(flag
& MOVEFILE_DELAY_UNTIL_REBOOT
))
2368 /* target exists, check if we may overwrite */
2369 if (!(flag
& MOVEFILE_REPLACE_EXISTING
))
2371 /* FIXME: Use right error code */
2372 SetLastError( ERROR_ACCESS_DENIED
);
2379 if (!DOSFS_GetFullName( fn2
, FALSE
, &full_name2
))
2381 if(!(flag
& MOVEFILE_DELAY_UNTIL_REBOOT
))
2386 /* Source name and target path are valid */
2388 if (flag
& MOVEFILE_DELAY_UNTIL_REBOOT
)
2390 /* FIXME: (bon@elektron.ikp.physik.th-darmstadt.de 970706)
2391 Perhaps we should queue these command and execute it
2392 when exiting... What about using on_exit(2)
2394 FIXME("Please move existing file '%s' to file '%s' when Wine has finished\n",
2396 return FILE_AddBootRenameEntry( fn1
, fn2
, flag
);
2399 /* check if we are allowed to delete the source */
2400 hFile
= FILE_CreateFile( full_name1
.long_name
, GENERIC_READ
|GENERIC_WRITE
, 0,
2401 NULL
, OPEN_EXISTING
, 0, 0, TRUE
,
2402 GetDriveTypeA( full_name1
.short_name
) );
2403 if (!hFile
) return FALSE
;
2406 /* check, if we are allowed to delete the destination,
2407 ** (but the file not being there is fine) */
2408 hFile
= FILE_CreateFile( full_name2
.long_name
, GENERIC_READ
|GENERIC_WRITE
, 0,
2409 NULL
, OPEN_EXISTING
, 0, 0, TRUE
,
2410 GetDriveTypeA( full_name2
.short_name
) );
2411 if(!hFile
&& GetLastError() != ERROR_FILE_NOT_FOUND
) return FALSE
;
2414 if (full_name1
.drive
!= full_name2
.drive
)
2416 /* use copy, if allowed */
2417 if (!(flag
& MOVEFILE_COPY_ALLOWED
))
2419 /* FIXME: Use right error code */
2420 SetLastError( ERROR_FILE_EXISTS
);
2423 return CopyFileA( fn1
, fn2
, !(flag
& MOVEFILE_REPLACE_EXISTING
) );
2425 if (rename( full_name1
.long_name
, full_name2
.long_name
) == -1)
2430 if (is_executable( full_name1
.long_name
) != is_executable( full_name2
.long_name
))
2433 if (stat( full_name2
.long_name
, &fstat
) != -1)
2435 if (is_executable( full_name2
.long_name
))
2436 /* set executable bit where read bit is set */
2437 fstat
.st_mode
|= (fstat
.st_mode
& 0444) >> 2;
2439 fstat
.st_mode
&= ~0111;
2440 chmod( full_name2
.long_name
, fstat
.st_mode
);
2445 else /* fn2 == NULL means delete source */
2447 if (flag
& MOVEFILE_DELAY_UNTIL_REBOOT
)
2449 if (flag
& MOVEFILE_COPY_ALLOWED
) {
2450 WARN("Illegal flag\n");
2451 SetLastError( ERROR_GEN_FAILURE
);
2454 /* FIXME: (bon@elektron.ikp.physik.th-darmstadt.de 970706)
2455 Perhaps we should queue these command and execute it
2456 when exiting... What about using on_exit(2)
2458 FIXME("Please delete file '%s' when Wine has finished\n", fn1
);
2459 return FILE_AddBootRenameEntry( fn1
, NULL
, flag
);
2462 if (unlink( full_name1
.long_name
) == -1)
2467 return TRUE
; /* successfully deleted */
2471 /**************************************************************************
2472 * MoveFileExW (KERNEL32.@)
2474 BOOL WINAPI
MoveFileExW( LPCWSTR fn1
, LPCWSTR fn2
, DWORD flag
)
2476 LPSTR afn1
= HEAP_strdupWtoA( GetProcessHeap(), 0, fn1
);
2477 LPSTR afn2
= HEAP_strdupWtoA( GetProcessHeap(), 0, fn2
);
2478 BOOL res
= MoveFileExA( afn1
, afn2
, flag
);
2479 HeapFree( GetProcessHeap(), 0, afn1
);
2480 HeapFree( GetProcessHeap(), 0, afn2
);
2485 /**************************************************************************
2486 * MoveFileA (KERNEL32.@)
2488 * Move file or directory
2490 BOOL WINAPI
MoveFileA( LPCSTR fn1
, LPCSTR fn2
)
2492 DOS_FULL_NAME full_name1
, full_name2
;
2495 TRACE("(%s,%s)\n", fn1
, fn2
);
2497 if (!DOSFS_GetFullName( fn1
, TRUE
, &full_name1
)) return FALSE
;
2498 if (DOSFS_GetFullName( fn2
, TRUE
, &full_name2
)) {
2499 /* The new name must not already exist */
2500 SetLastError(ERROR_ALREADY_EXISTS
);
2503 if (!DOSFS_GetFullName( fn2
, FALSE
, &full_name2
)) return FALSE
;
2505 if (full_name1
.drive
== full_name2
.drive
) /* move */
2506 return MoveFileExA( fn1
, fn2
, MOVEFILE_COPY_ALLOWED
);
2509 if (stat( full_name1
.long_name
, &fstat
))
2511 WARN("Invalid source file %s\n",
2512 full_name1
.long_name
);
2516 if (S_ISDIR(fstat
.st_mode
)) {
2517 /* No Move for directories across file systems */
2518 /* FIXME: Use right error code */
2519 SetLastError( ERROR_GEN_FAILURE
);
2522 return CopyFileA(fn1
, fn2
, TRUE
); /*fail, if exist */
2526 /**************************************************************************
2527 * MoveFileW (KERNEL32.@)
2529 BOOL WINAPI
MoveFileW( LPCWSTR fn1
, LPCWSTR fn2
)
2531 LPSTR afn1
= HEAP_strdupWtoA( GetProcessHeap(), 0, fn1
);
2532 LPSTR afn2
= HEAP_strdupWtoA( GetProcessHeap(), 0, fn2
);
2533 BOOL res
= MoveFileA( afn1
, afn2
);
2534 HeapFree( GetProcessHeap(), 0, afn1
);
2535 HeapFree( GetProcessHeap(), 0, afn2
);
2540 /**************************************************************************
2541 * CopyFileA (KERNEL32.@)
2543 BOOL WINAPI
CopyFileA( LPCSTR source
, LPCSTR dest
, BOOL fail_if_exists
)
2546 BY_HANDLE_FILE_INFORMATION info
;
2552 if ((h1
= _lopen( source
, OF_READ
)) == HFILE_ERROR
) return FALSE
;
2553 if (!GetFileInformationByHandle( h1
, &info
))
2558 mode
= (info
.dwFileAttributes
& FILE_ATTRIBUTE_READONLY
) ? 0444 : 0666;
2559 if ((h2
= CreateFileA( dest
, GENERIC_WRITE
, FILE_SHARE_READ
| FILE_SHARE_WRITE
, NULL
,
2560 fail_if_exists
? CREATE_NEW
: CREATE_ALWAYS
,
2561 info
.dwFileAttributes
, h1
)) == INVALID_HANDLE_VALUE
)
2566 while ((count
= _lread( h1
, buffer
, sizeof(buffer
) )) > 0)
2571 INT res
= _lwrite( h2
, p
, count
);
2572 if (res
<= 0) goto done
;
2585 /**************************************************************************
2586 * CopyFileW (KERNEL32.@)
2588 BOOL WINAPI
CopyFileW( LPCWSTR source
, LPCWSTR dest
, BOOL fail_if_exists
)
2590 LPSTR sourceA
= HEAP_strdupWtoA( GetProcessHeap(), 0, source
);
2591 LPSTR destA
= HEAP_strdupWtoA( GetProcessHeap(), 0, dest
);
2592 BOOL ret
= CopyFileA( sourceA
, destA
, fail_if_exists
);
2593 HeapFree( GetProcessHeap(), 0, sourceA
);
2594 HeapFree( GetProcessHeap(), 0, destA
);
2599 /**************************************************************************
2600 * CopyFileExA (KERNEL32.@)
2602 * This implementation ignores most of the extra parameters passed-in into
2603 * the "ex" version of the method and calls the CopyFile method.
2604 * It will have to be fixed eventually.
2606 BOOL WINAPI
CopyFileExA(LPCSTR sourceFilename
,
2607 LPCSTR destFilename
,
2608 LPPROGRESS_ROUTINE progressRoutine
,
2610 LPBOOL cancelFlagPointer
,
2613 BOOL failIfExists
= FALSE
;
2616 * Interpret the only flag that CopyFile can interpret.
2618 if ( (copyFlags
& COPY_FILE_FAIL_IF_EXISTS
) != 0)
2620 failIfExists
= TRUE
;
2623 return CopyFileA(sourceFilename
, destFilename
, failIfExists
);
2626 /**************************************************************************
2627 * CopyFileExW (KERNEL32.@)
2629 BOOL WINAPI
CopyFileExW(LPCWSTR sourceFilename
,
2630 LPCWSTR destFilename
,
2631 LPPROGRESS_ROUTINE progressRoutine
,
2633 LPBOOL cancelFlagPointer
,
2636 LPSTR sourceA
= HEAP_strdupWtoA( GetProcessHeap(), 0, sourceFilename
);
2637 LPSTR destA
= HEAP_strdupWtoA( GetProcessHeap(), 0, destFilename
);
2639 BOOL ret
= CopyFileExA(sourceA
,
2646 HeapFree( GetProcessHeap(), 0, sourceA
);
2647 HeapFree( GetProcessHeap(), 0, destA
);
2653 /***********************************************************************
2654 * SetFileTime (KERNEL32.@)
2656 BOOL WINAPI
SetFileTime( HANDLE hFile
,
2657 const FILETIME
*lpCreationTime
,
2658 const FILETIME
*lpLastAccessTime
,
2659 const FILETIME
*lpLastWriteTime
)
2662 SERVER_START_REQ( set_file_time
)
2664 req
->handle
= hFile
;
2665 if (lpLastAccessTime
)
2666 RtlTimeToSecondsSince1970( lpLastAccessTime
, (DWORD
*)&req
->access_time
);
2668 req
->access_time
= 0; /* FIXME */
2669 if (lpLastWriteTime
)
2670 RtlTimeToSecondsSince1970( lpLastWriteTime
, (DWORD
*)&req
->write_time
);
2672 req
->write_time
= 0; /* FIXME */
2673 ret
= !wine_server_call_err( req
);
2680 /**************************************************************************
2681 * LockFile (KERNEL32.@)
2683 BOOL WINAPI
LockFile( HANDLE hFile
, DWORD dwFileOffsetLow
, DWORD dwFileOffsetHigh
,
2684 DWORD nNumberOfBytesToLockLow
, DWORD nNumberOfBytesToLockHigh
)
2687 SERVER_START_REQ( lock_file
)
2689 req
->handle
= hFile
;
2690 req
->offset_low
= dwFileOffsetLow
;
2691 req
->offset_high
= dwFileOffsetHigh
;
2692 req
->count_low
= nNumberOfBytesToLockLow
;
2693 req
->count_high
= nNumberOfBytesToLockHigh
;
2694 ret
= !wine_server_call_err( req
);
2700 /**************************************************************************
2701 * LockFileEx [KERNEL32.@]
2703 * Locks a byte range within an open file for shared or exclusive access.
2710 * Per Microsoft docs, the third parameter (reserved) must be set to 0.
2712 BOOL WINAPI
LockFileEx( HANDLE hFile
, DWORD flags
, DWORD reserved
,
2713 DWORD nNumberOfBytesToLockLow
, DWORD nNumberOfBytesToLockHigh
,
2714 LPOVERLAPPED pOverlapped
)
2716 FIXME("hFile=%d,flags=%ld,reserved=%ld,lowbytes=%ld,highbytes=%ld,overlapped=%p: stub.\n",
2717 hFile
, flags
, reserved
, nNumberOfBytesToLockLow
, nNumberOfBytesToLockHigh
,
2720 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
2723 ERR("reserved == %ld: Supposed to be 0??\n", reserved
);
2724 SetLastError(ERROR_INVALID_PARAMETER
);
2731 /**************************************************************************
2732 * UnlockFile (KERNEL32.@)
2734 BOOL WINAPI
UnlockFile( HANDLE hFile
, DWORD dwFileOffsetLow
, DWORD dwFileOffsetHigh
,
2735 DWORD nNumberOfBytesToUnlockLow
, DWORD nNumberOfBytesToUnlockHigh
)
2738 SERVER_START_REQ( unlock_file
)
2740 req
->handle
= hFile
;
2741 req
->offset_low
= dwFileOffsetLow
;
2742 req
->offset_high
= dwFileOffsetHigh
;
2743 req
->count_low
= nNumberOfBytesToUnlockLow
;
2744 req
->count_high
= nNumberOfBytesToUnlockHigh
;
2745 ret
= !wine_server_call_err( req
);
2752 /**************************************************************************
2753 * UnlockFileEx (KERNEL32.@)
2755 BOOL WINAPI
UnlockFileEx(
2758 DWORD nNumberOfBytesToUnlockLow
,
2759 DWORD nNumberOfBytesToUnlockHigh
,
2760 LPOVERLAPPED lpOverlapped
2763 FIXME("hFile=%d,reserved=%ld,lowbytes=%ld,highbytes=%ld,overlapped=%p: stub.\n",
2764 hFile
, dwReserved
, nNumberOfBytesToUnlockLow
, nNumberOfBytesToUnlockHigh
,
2766 if (dwReserved
== 0)
2767 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
2770 ERR("reserved == %ld: Supposed to be 0??\n", dwReserved
);
2771 SetLastError(ERROR_INVALID_PARAMETER
);
2780 struct DOS_FILE_LOCK
{
2781 struct DOS_FILE_LOCK
* next
;
2785 FILE_OBJECT
* dos_file
;
2786 /* char * unix_name;*/
2789 typedef struct DOS_FILE_LOCK DOS_FILE_LOCK
;
2791 static DOS_FILE_LOCK
*locks
= NULL
;
2792 static void DOS_RemoveFileLocks(FILE_OBJECT
*file
);
2795 /* Locks need to be mirrored because unix file locking is based
2796 * on the pid. Inside of wine there can be multiple WINE processes
2797 * that share the same unix pid.
2798 * Read's and writes should check these locks also - not sure
2799 * how critical that is at this point (FIXME).
2802 static BOOL
DOS_AddLock(FILE_OBJECT
*file
, struct flock
*f
)
2804 DOS_FILE_LOCK
*curr
;
2807 processId
= GetCurrentProcessId();
2809 /* check if lock overlaps a current lock for the same file */
2811 for (curr
= locks
; curr
; curr
= curr
->next
) {
2812 if (strcmp(curr
->unix_name
, file
->unix_name
) == 0) {
2813 if ((f
->l_start
== curr
->base
) && (f
->l_len
== curr
->len
))
2814 return TRUE
;/* region is identic */
2815 if ((f
->l_start
< (curr
->base
+ curr
->len
)) &&
2816 ((f
->l_start
+ f
->l_len
) > curr
->base
)) {
2817 /* region overlaps */
2824 curr
= HeapAlloc( GetProcessHeap(), 0, sizeof(DOS_FILE_LOCK
) );
2825 curr
->processId
= GetCurrentProcessId();
2826 curr
->base
= f
->l_start
;
2827 curr
->len
= f
->l_len
;
2828 /* curr->unix_name = HEAP_strdupA( GetProcessHeap(), 0, file->unix_name);*/
2830 curr
->dos_file
= file
;
2835 static void DOS_RemoveFileLocks(FILE_OBJECT
*file
)
2838 DOS_FILE_LOCK
**curr
;
2841 processId
= GetCurrentProcessId();
2844 if ((*curr
)->dos_file
== file
) {
2846 *curr
= (*curr
)->next
;
2847 /* HeapFree( GetProcessHeap(), 0, rem->unix_name );*/
2848 HeapFree( GetProcessHeap(), 0, rem
);
2851 curr
= &(*curr
)->next
;
2855 static BOOL
DOS_RemoveLock(FILE_OBJECT
*file
, struct flock
*f
)
2858 DOS_FILE_LOCK
**curr
;
2861 processId
= GetCurrentProcessId();
2862 for (curr
= &locks
; *curr
; curr
= &(*curr
)->next
) {
2863 if ((*curr
)->processId
== processId
&&
2864 (*curr
)->dos_file
== file
&&
2865 (*curr
)->base
== f
->l_start
&&
2866 (*curr
)->len
== f
->l_len
) {
2867 /* this is the same lock */
2869 *curr
= (*curr
)->next
;
2870 /* HeapFree( GetProcessHeap(), 0, rem->unix_name );*/
2871 HeapFree( GetProcessHeap(), 0, rem
);
2875 /* no matching lock found */
2880 /**************************************************************************
2881 * LockFile (KERNEL32.@)
2883 BOOL WINAPI
LockFile(
2884 HFILE hFile
,DWORD dwFileOffsetLow
,DWORD dwFileOffsetHigh
,
2885 DWORD nNumberOfBytesToLockLow
,DWORD nNumberOfBytesToLockHigh
)
2890 TRACE("handle %d offsetlow=%ld offsethigh=%ld nbyteslow=%ld nbyteshigh=%ld\n",
2891 hFile
, dwFileOffsetLow
, dwFileOffsetHigh
,
2892 nNumberOfBytesToLockLow
, nNumberOfBytesToLockHigh
);
2894 if (dwFileOffsetHigh
|| nNumberOfBytesToLockHigh
) {
2895 FIXME("Unimplemented bytes > 32bits\n");
2899 f
.l_start
= dwFileOffsetLow
;
2900 f
.l_len
= nNumberOfBytesToLockLow
;
2901 f
.l_whence
= SEEK_SET
;
2905 if (!(file
= FILE_GetFile(hFile
,0,NULL
))) return FALSE
;
2907 /* shadow locks internally */
2908 if (!DOS_AddLock(file
, &f
)) {
2909 SetLastError( ERROR_LOCK_VIOLATION
);
2913 /* FIXME: Unix locking commented out for now, doesn't work with Excel */
2914 #ifdef USE_UNIX_LOCKS
2915 if (fcntl(file
->unix_handle
, F_SETLK
, &f
) == -1) {
2916 if (errno
== EACCES
|| errno
== EAGAIN
) {
2917 SetLastError( ERROR_LOCK_VIOLATION
);
2922 /* remove our internal copy of the lock */
2923 DOS_RemoveLock(file
, &f
);
2931 /**************************************************************************
2932 * UnlockFile (KERNEL32.@)
2934 BOOL WINAPI
UnlockFile(
2935 HFILE hFile
,DWORD dwFileOffsetLow
,DWORD dwFileOffsetHigh
,
2936 DWORD nNumberOfBytesToUnlockLow
,DWORD nNumberOfBytesToUnlockHigh
)
2941 TRACE("handle %d offsetlow=%ld offsethigh=%ld nbyteslow=%ld nbyteshigh=%ld\n",
2942 hFile
, dwFileOffsetLow
, dwFileOffsetHigh
,
2943 nNumberOfBytesToUnlockLow
, nNumberOfBytesToUnlockHigh
);
2945 if (dwFileOffsetHigh
|| nNumberOfBytesToUnlockHigh
) {
2946 WARN("Unimplemented bytes > 32bits\n");
2950 f
.l_start
= dwFileOffsetLow
;
2951 f
.l_len
= nNumberOfBytesToUnlockLow
;
2952 f
.l_whence
= SEEK_SET
;
2956 if (!(file
= FILE_GetFile(hFile
,0,NULL
))) return FALSE
;
2958 DOS_RemoveLock(file
, &f
); /* ok if fails - may be another wine */
2960 /* FIXME: Unix locking commented out for now, doesn't work with Excel */
2961 #ifdef USE_UNIX_LOCKS
2962 if (fcntl(file
->unix_handle
, F_SETLK
, &f
) == -1) {
2971 /**************************************************************************
2972 * GetFileAttributesExA [KERNEL32.@]
2974 BOOL WINAPI
GetFileAttributesExA(
2975 LPCSTR lpFileName
, GET_FILEEX_INFO_LEVELS fInfoLevelId
,
2976 LPVOID lpFileInformation
)
2978 DOS_FULL_NAME full_name
;
2979 BY_HANDLE_FILE_INFORMATION info
;
2981 if (lpFileName
== NULL
) return FALSE
;
2982 if (lpFileInformation
== NULL
) return FALSE
;
2984 if (fInfoLevelId
== GetFileExInfoStandard
) {
2985 LPWIN32_FILE_ATTRIBUTE_DATA lpFad
=
2986 (LPWIN32_FILE_ATTRIBUTE_DATA
) lpFileInformation
;
2987 if (!DOSFS_GetFullName( lpFileName
, TRUE
, &full_name
)) return FALSE
;
2988 if (!FILE_Stat( full_name
.long_name
, &info
)) return FALSE
;
2990 lpFad
->dwFileAttributes
= info
.dwFileAttributes
;
2991 lpFad
->ftCreationTime
= info
.ftCreationTime
;
2992 lpFad
->ftLastAccessTime
= info
.ftLastAccessTime
;
2993 lpFad
->ftLastWriteTime
= info
.ftLastWriteTime
;
2994 lpFad
->nFileSizeHigh
= info
.nFileSizeHigh
;
2995 lpFad
->nFileSizeLow
= info
.nFileSizeLow
;
2998 FIXME("invalid info level %d!\n", fInfoLevelId
);
3006 /**************************************************************************
3007 * GetFileAttributesExW [KERNEL32.@]
3009 BOOL WINAPI
GetFileAttributesExW(
3010 LPCWSTR lpFileName
, GET_FILEEX_INFO_LEVELS fInfoLevelId
,
3011 LPVOID lpFileInformation
)
3013 LPSTR nameA
= HEAP_strdupWtoA( GetProcessHeap(), 0, lpFileName
);
3015 GetFileAttributesExA( nameA
, fInfoLevelId
, lpFileInformation
);
3016 HeapFree( GetProcessHeap(), 0, nameA
);