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
;
2155 SetLastError(ERROR_INVALID_PARAMETER
);
2158 TRACE("'%s'\n", path
);
2162 ERR("Empty path passed\n");
2165 if (DOSFS_GetDevice( path
))
2167 WARN("cannot remove DOS device '%s'!\n", path
);
2168 SetLastError( ERROR_FILE_NOT_FOUND
);
2172 if (!DOSFS_GetFullName( path
, TRUE
, &full_name
)) return FALSE
;
2173 if (unlink( full_name
.long_name
) == -1)
2182 /***********************************************************************
2183 * DeleteFileW (KERNEL32.@)
2185 BOOL WINAPI
DeleteFileW( LPCWSTR path
)
2187 LPSTR xpath
= HEAP_strdupWtoA( GetProcessHeap(), 0, path
);
2188 BOOL ret
= DeleteFileA( xpath
);
2189 HeapFree( GetProcessHeap(), 0, xpath
);
2194 /***********************************************************************
2195 * GetFileType (KERNEL32.@)
2197 DWORD WINAPI
GetFileType( HANDLE hFile
)
2199 DWORD ret
= FILE_TYPE_UNKNOWN
;
2200 SERVER_START_REQ( get_file_info
)
2202 req
->handle
= hFile
;
2203 if (!wine_server_call_err( req
)) ret
= reply
->type
;
2210 /* check if a file name is for an executable file (.exe or .com) */
2211 inline static BOOL
is_executable( const char *name
)
2213 int len
= strlen(name
);
2215 if (len
< 4) return FALSE
;
2216 return (!strcasecmp( name
+ len
- 4, ".exe" ) ||
2217 !strcasecmp( name
+ len
- 4, ".com" ));
2221 /***********************************************************************
2222 * FILE_AddBootRenameEntry
2224 * Adds an entry to the registry that is loaded when windows boots and
2225 * checks if there are some files to be removed or renamed/moved.
2226 * <fn1> has to be valid and <fn2> may be NULL. If both pointers are
2227 * non-NULL then the file is moved, otherwise it is deleted. The
2228 * entry of the registrykey is always appended with two zero
2229 * terminated strings. If <fn2> is NULL then the second entry is
2230 * simply a single 0-byte. Otherwise the second filename goes
2231 * there. The entries are prepended with \??\ before the path and the
2232 * second filename gets also a '!' as the first character if
2233 * MOVEFILE_REPLACE_EXISTING is set. After the final string another
2234 * 0-byte follows to indicate the end of the strings.
2236 * \??\D:\test\file1[0]
2237 * !\??\D:\test\file1_renamed[0]
2238 * \??\D:\Test|delete[0]
2239 * [0] <- file is to be deleted, second string empty
2240 * \??\D:\test\file2[0]
2241 * !\??\D:\test\file2_renamed[0]
2242 * [0] <- indicates end of strings
2245 * \??\D:\test\file1[0]
2246 * !\??\D:\test\file1_renamed[0]
2247 * \??\D:\Test|delete[0]
2248 * [0] <- file is to be deleted, second string empty
2249 * [0] <- indicates end of strings
2252 static BOOL
FILE_AddBootRenameEntry( const char *fn1
, const char *fn2
, DWORD flags
)
2254 static const char PreString
[] = "\\??\\";
2255 static const char ValueName
[] = "PendingFileRenameOperations";
2259 DWORD Type
, len1
, len2
, l
;
2261 BYTE
*Buffer
= NULL
;
2263 if(RegCreateKeyA(HKEY_LOCAL_MACHINE
, "SYSTEM\\CurrentControlSet\\Control\\Session Manager",
2264 &Reboot
) != ERROR_SUCCESS
)
2266 WARN("Error creating key for reboot managment [%s]\n",
2267 "SYSTEM\\CurrentControlSet\\Control\\Session Manager");
2271 l
= strlen(PreString
);
2272 len1
= strlen(fn1
) + l
+ 1;
2275 len2
= strlen(fn2
) + l
+ 1;
2276 if (flags
& MOVEFILE_REPLACE_EXISTING
) len2
++; /* Plus 1 because of the leading '!' */
2278 else len2
= 1; /* minimum is the 0 byte for the empty second string */
2280 /* First we check if the key exists and if so how many bytes it already contains. */
2281 if (RegQueryValueExA(Reboot
, ValueName
, NULL
, &Type
, NULL
, &DataSize
) == ERROR_SUCCESS
)
2283 if (Type
!= REG_MULTI_SZ
) goto Quit
;
2284 if (!(Buffer
= HeapAlloc( GetProcessHeap(), 0, DataSize
+ len1
+ len2
+ 1 ))) goto Quit
;
2285 if (RegQueryValueExA(Reboot
, ValueName
, NULL
, &Type
, Buffer
, &DataSize
) != ERROR_SUCCESS
)
2287 if (DataSize
) DataSize
--; /* remove terminating null (will be added back later) */
2291 if (!(Buffer
= HeapAlloc( GetProcessHeap(), 0, len1
+ len2
+ 1 ))) goto Quit
;
2294 sprintf( Buffer
+ DataSize
, "%s%s", PreString
, fn1
);
2298 sprintf( Buffer
+ DataSize
, "%s%s%s",
2299 (flags
& MOVEFILE_REPLACE_EXISTING
) ? "!" : "", PreString
, fn2
);
2302 else Buffer
[DataSize
++] = 0;
2304 Buffer
[DataSize
++] = 0; /* add final null */
2305 rc
= !RegSetValueExA( Reboot
, ValueName
, 0, REG_MULTI_SZ
, Buffer
, DataSize
);
2308 if (Reboot
) RegCloseKey(Reboot
);
2309 if (Buffer
) HeapFree( GetProcessHeap(), 0, Buffer
);
2314 /**************************************************************************
2315 * MoveFileExA (KERNEL32.@)
2317 BOOL WINAPI
MoveFileExA( LPCSTR fn1
, LPCSTR fn2
, DWORD flag
)
2319 DOS_FULL_NAME full_name1
, full_name2
;
2321 TRACE("(%s,%s,%04lx)\n", fn1
, fn2
, flag
);
2323 /* FIXME: <Gerhard W. Gruber>sparhawk@gmx.at
2324 In case of W9x and lesser this function should return 120 (ERROR_CALL_NOT_IMPLEMENTED)
2325 to be really compatible. Most programs wont have any problems though. In case
2326 you encounter one, this is what you should return here. I don't know what's up
2327 with NT 3.5. Is this function available there or not?
2328 Does anybody really care about 3.5? :)
2331 /* Filename1 has to be always set to a valid path. Filename2 may be NULL
2332 if the source file has to be deleted.
2335 SetLastError(ERROR_INVALID_PARAMETER
);
2339 /* This function has to be run through in order to process the name properly.
2340 If the BOOTDELAY flag is set, the file doesn't need to exist though. At least
2341 that is the behaviour on NT 4.0. The operation accepts the filenames as
2342 they are given but it can't reply with a reasonable returncode. Success
2343 means in that case success for entering the values into the registry.
2345 if(!DOSFS_GetFullName( fn1
, TRUE
, &full_name1
))
2347 if(!(flag
& MOVEFILE_DELAY_UNTIL_REBOOT
))
2351 if (fn2
) /* !fn2 means delete fn1 */
2353 if (DOSFS_GetFullName( fn2
, TRUE
, &full_name2
))
2355 if(!(flag
& MOVEFILE_DELAY_UNTIL_REBOOT
))
2357 /* target exists, check if we may overwrite */
2358 if (!(flag
& MOVEFILE_REPLACE_EXISTING
))
2360 /* FIXME: Use right error code */
2361 SetLastError( ERROR_ACCESS_DENIED
);
2368 if (!DOSFS_GetFullName( fn2
, FALSE
, &full_name2
))
2370 if(!(flag
& MOVEFILE_DELAY_UNTIL_REBOOT
))
2375 /* Source name and target path are valid */
2377 if (flag
& MOVEFILE_DELAY_UNTIL_REBOOT
)
2379 /* FIXME: (bon@elektron.ikp.physik.th-darmstadt.de 970706)
2380 Perhaps we should queue these command and execute it
2381 when exiting... What about using on_exit(2)
2383 FIXME("Please move existing file '%s' to file '%s' when Wine has finished\n",
2385 return FILE_AddBootRenameEntry( fn1
, fn2
, flag
);
2388 if (full_name1
.drive
!= full_name2
.drive
)
2390 /* use copy, if allowed */
2391 if (!(flag
& MOVEFILE_COPY_ALLOWED
))
2393 /* FIXME: Use right error code */
2394 SetLastError( ERROR_FILE_EXISTS
);
2397 return CopyFileA( fn1
, fn2
, !(flag
& MOVEFILE_REPLACE_EXISTING
) );
2399 if (rename( full_name1
.long_name
, full_name2
.long_name
) == -1)
2404 if (is_executable( full_name1
.long_name
) != is_executable( full_name2
.long_name
))
2407 if (stat( full_name2
.long_name
, &fstat
) != -1)
2409 if (is_executable( full_name2
.long_name
))
2410 /* set executable bit where read bit is set */
2411 fstat
.st_mode
|= (fstat
.st_mode
& 0444) >> 2;
2413 fstat
.st_mode
&= ~0111;
2414 chmod( full_name2
.long_name
, fstat
.st_mode
);
2419 else /* fn2 == NULL means delete source */
2421 if (flag
& MOVEFILE_DELAY_UNTIL_REBOOT
)
2423 if (flag
& MOVEFILE_COPY_ALLOWED
) {
2424 WARN("Illegal flag\n");
2425 SetLastError( ERROR_GEN_FAILURE
);
2428 /* FIXME: (bon@elektron.ikp.physik.th-darmstadt.de 970706)
2429 Perhaps we should queue these command and execute it
2430 when exiting... What about using on_exit(2)
2432 FIXME("Please delete file '%s' when Wine has finished\n", fn1
);
2433 return FILE_AddBootRenameEntry( fn1
, NULL
, flag
);
2436 if (unlink( full_name1
.long_name
) == -1)
2441 return TRUE
; /* successfully deleted */
2445 /**************************************************************************
2446 * MoveFileExW (KERNEL32.@)
2448 BOOL WINAPI
MoveFileExW( LPCWSTR fn1
, LPCWSTR fn2
, DWORD flag
)
2450 LPSTR afn1
= HEAP_strdupWtoA( GetProcessHeap(), 0, fn1
);
2451 LPSTR afn2
= HEAP_strdupWtoA( GetProcessHeap(), 0, fn2
);
2452 BOOL res
= MoveFileExA( afn1
, afn2
, flag
);
2453 HeapFree( GetProcessHeap(), 0, afn1
);
2454 HeapFree( GetProcessHeap(), 0, afn2
);
2459 /**************************************************************************
2460 * MoveFileA (KERNEL32.@)
2462 * Move file or directory
2464 BOOL WINAPI
MoveFileA( LPCSTR fn1
, LPCSTR fn2
)
2466 DOS_FULL_NAME full_name1
, full_name2
;
2469 TRACE("(%s,%s)\n", fn1
, fn2
);
2471 if (!DOSFS_GetFullName( fn1
, TRUE
, &full_name1
)) return FALSE
;
2472 if (DOSFS_GetFullName( fn2
, TRUE
, &full_name2
)) {
2473 /* The new name must not already exist */
2474 SetLastError(ERROR_ALREADY_EXISTS
);
2477 if (!DOSFS_GetFullName( fn2
, FALSE
, &full_name2
)) return FALSE
;
2479 if (full_name1
.drive
== full_name2
.drive
) /* move */
2480 return MoveFileExA( fn1
, fn2
, MOVEFILE_COPY_ALLOWED
);
2483 if (stat( full_name1
.long_name
, &fstat
))
2485 WARN("Invalid source file %s\n",
2486 full_name1
.long_name
);
2490 if (S_ISDIR(fstat
.st_mode
)) {
2491 /* No Move for directories across file systems */
2492 /* FIXME: Use right error code */
2493 SetLastError( ERROR_GEN_FAILURE
);
2496 return CopyFileA(fn1
, fn2
, TRUE
); /*fail, if exist */
2500 /**************************************************************************
2501 * MoveFileW (KERNEL32.@)
2503 BOOL WINAPI
MoveFileW( LPCWSTR fn1
, LPCWSTR fn2
)
2505 LPSTR afn1
= HEAP_strdupWtoA( GetProcessHeap(), 0, fn1
);
2506 LPSTR afn2
= HEAP_strdupWtoA( GetProcessHeap(), 0, fn2
);
2507 BOOL res
= MoveFileA( afn1
, afn2
);
2508 HeapFree( GetProcessHeap(), 0, afn1
);
2509 HeapFree( GetProcessHeap(), 0, afn2
);
2514 /**************************************************************************
2515 * CopyFileA (KERNEL32.@)
2517 BOOL WINAPI
CopyFileA( LPCSTR source
, LPCSTR dest
, BOOL fail_if_exists
)
2520 BY_HANDLE_FILE_INFORMATION info
;
2526 if ((h1
= _lopen( source
, OF_READ
)) == HFILE_ERROR
) return FALSE
;
2527 if (!GetFileInformationByHandle( h1
, &info
))
2532 mode
= (info
.dwFileAttributes
& FILE_ATTRIBUTE_READONLY
) ? 0444 : 0666;
2533 if ((h2
= CreateFileA( dest
, GENERIC_WRITE
, FILE_SHARE_READ
| FILE_SHARE_WRITE
, NULL
,
2534 fail_if_exists
? CREATE_NEW
: CREATE_ALWAYS
,
2535 info
.dwFileAttributes
, h1
)) == INVALID_HANDLE_VALUE
)
2540 while ((count
= _lread( h1
, buffer
, sizeof(buffer
) )) > 0)
2545 INT res
= _lwrite( h2
, p
, count
);
2546 if (res
<= 0) goto done
;
2559 /**************************************************************************
2560 * CopyFileW (KERNEL32.@)
2562 BOOL WINAPI
CopyFileW( LPCWSTR source
, LPCWSTR dest
, BOOL fail_if_exists
)
2564 LPSTR sourceA
= HEAP_strdupWtoA( GetProcessHeap(), 0, source
);
2565 LPSTR destA
= HEAP_strdupWtoA( GetProcessHeap(), 0, dest
);
2566 BOOL ret
= CopyFileA( sourceA
, destA
, fail_if_exists
);
2567 HeapFree( GetProcessHeap(), 0, sourceA
);
2568 HeapFree( GetProcessHeap(), 0, destA
);
2573 /**************************************************************************
2574 * CopyFileExA (KERNEL32.@)
2576 * This implementation ignores most of the extra parameters passed-in into
2577 * the "ex" version of the method and calls the CopyFile method.
2578 * It will have to be fixed eventually.
2580 BOOL WINAPI
CopyFileExA(LPCSTR sourceFilename
,
2581 LPCSTR destFilename
,
2582 LPPROGRESS_ROUTINE progressRoutine
,
2584 LPBOOL cancelFlagPointer
,
2587 BOOL failIfExists
= FALSE
;
2590 * Interpret the only flag that CopyFile can interpret.
2592 if ( (copyFlags
& COPY_FILE_FAIL_IF_EXISTS
) != 0)
2594 failIfExists
= TRUE
;
2597 return CopyFileA(sourceFilename
, destFilename
, failIfExists
);
2600 /**************************************************************************
2601 * CopyFileExW (KERNEL32.@)
2603 BOOL WINAPI
CopyFileExW(LPCWSTR sourceFilename
,
2604 LPCWSTR destFilename
,
2605 LPPROGRESS_ROUTINE progressRoutine
,
2607 LPBOOL cancelFlagPointer
,
2610 LPSTR sourceA
= HEAP_strdupWtoA( GetProcessHeap(), 0, sourceFilename
);
2611 LPSTR destA
= HEAP_strdupWtoA( GetProcessHeap(), 0, destFilename
);
2613 BOOL ret
= CopyFileExA(sourceA
,
2620 HeapFree( GetProcessHeap(), 0, sourceA
);
2621 HeapFree( GetProcessHeap(), 0, destA
);
2627 /***********************************************************************
2628 * SetFileTime (KERNEL32.@)
2630 BOOL WINAPI
SetFileTime( HANDLE hFile
,
2631 const FILETIME
*lpCreationTime
,
2632 const FILETIME
*lpLastAccessTime
,
2633 const FILETIME
*lpLastWriteTime
)
2636 SERVER_START_REQ( set_file_time
)
2638 req
->handle
= hFile
;
2639 if (lpLastAccessTime
)
2640 RtlTimeToSecondsSince1970( lpLastAccessTime
, (DWORD
*)&req
->access_time
);
2642 req
->access_time
= 0; /* FIXME */
2643 if (lpLastWriteTime
)
2644 RtlTimeToSecondsSince1970( lpLastWriteTime
, (DWORD
*)&req
->write_time
);
2646 req
->write_time
= 0; /* FIXME */
2647 ret
= !wine_server_call_err( req
);
2654 /**************************************************************************
2655 * LockFile (KERNEL32.@)
2657 BOOL WINAPI
LockFile( HANDLE hFile
, DWORD dwFileOffsetLow
, DWORD dwFileOffsetHigh
,
2658 DWORD nNumberOfBytesToLockLow
, DWORD nNumberOfBytesToLockHigh
)
2661 SERVER_START_REQ( lock_file
)
2663 req
->handle
= hFile
;
2664 req
->offset_low
= dwFileOffsetLow
;
2665 req
->offset_high
= dwFileOffsetHigh
;
2666 req
->count_low
= nNumberOfBytesToLockLow
;
2667 req
->count_high
= nNumberOfBytesToLockHigh
;
2668 ret
= !wine_server_call_err( req
);
2674 /**************************************************************************
2675 * LockFileEx [KERNEL32.@]
2677 * Locks a byte range within an open file for shared or exclusive access.
2684 * Per Microsoft docs, the third parameter (reserved) must be set to 0.
2686 BOOL WINAPI
LockFileEx( HANDLE hFile
, DWORD flags
, DWORD reserved
,
2687 DWORD nNumberOfBytesToLockLow
, DWORD nNumberOfBytesToLockHigh
,
2688 LPOVERLAPPED pOverlapped
)
2690 FIXME("hFile=%d,flags=%ld,reserved=%ld,lowbytes=%ld,highbytes=%ld,overlapped=%p: stub.\n",
2691 hFile
, flags
, reserved
, nNumberOfBytesToLockLow
, nNumberOfBytesToLockHigh
,
2694 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
2697 ERR("reserved == %ld: Supposed to be 0??\n", reserved
);
2698 SetLastError(ERROR_INVALID_PARAMETER
);
2705 /**************************************************************************
2706 * UnlockFile (KERNEL32.@)
2708 BOOL WINAPI
UnlockFile( HANDLE hFile
, DWORD dwFileOffsetLow
, DWORD dwFileOffsetHigh
,
2709 DWORD nNumberOfBytesToUnlockLow
, DWORD nNumberOfBytesToUnlockHigh
)
2712 SERVER_START_REQ( unlock_file
)
2714 req
->handle
= hFile
;
2715 req
->offset_low
= dwFileOffsetLow
;
2716 req
->offset_high
= dwFileOffsetHigh
;
2717 req
->count_low
= nNumberOfBytesToUnlockLow
;
2718 req
->count_high
= nNumberOfBytesToUnlockHigh
;
2719 ret
= !wine_server_call_err( req
);
2726 /**************************************************************************
2727 * UnlockFileEx (KERNEL32.@)
2729 BOOL WINAPI
UnlockFileEx(
2732 DWORD nNumberOfBytesToUnlockLow
,
2733 DWORD nNumberOfBytesToUnlockHigh
,
2734 LPOVERLAPPED lpOverlapped
2737 FIXME("hFile=%d,reserved=%ld,lowbytes=%ld,highbytes=%ld,overlapped=%p: stub.\n",
2738 hFile
, dwReserved
, nNumberOfBytesToUnlockLow
, nNumberOfBytesToUnlockHigh
,
2740 if (dwReserved
== 0)
2741 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
2744 ERR("reserved == %ld: Supposed to be 0??\n", dwReserved
);
2745 SetLastError(ERROR_INVALID_PARAMETER
);
2754 struct DOS_FILE_LOCK
{
2755 struct DOS_FILE_LOCK
* next
;
2759 FILE_OBJECT
* dos_file
;
2760 /* char * unix_name;*/
2763 typedef struct DOS_FILE_LOCK DOS_FILE_LOCK
;
2765 static DOS_FILE_LOCK
*locks
= NULL
;
2766 static void DOS_RemoveFileLocks(FILE_OBJECT
*file
);
2769 /* Locks need to be mirrored because unix file locking is based
2770 * on the pid. Inside of wine there can be multiple WINE processes
2771 * that share the same unix pid.
2772 * Read's and writes should check these locks also - not sure
2773 * how critical that is at this point (FIXME).
2776 static BOOL
DOS_AddLock(FILE_OBJECT
*file
, struct flock
*f
)
2778 DOS_FILE_LOCK
*curr
;
2781 processId
= GetCurrentProcessId();
2783 /* check if lock overlaps a current lock for the same file */
2785 for (curr
= locks
; curr
; curr
= curr
->next
) {
2786 if (strcmp(curr
->unix_name
, file
->unix_name
) == 0) {
2787 if ((f
->l_start
== curr
->base
) && (f
->l_len
== curr
->len
))
2788 return TRUE
;/* region is identic */
2789 if ((f
->l_start
< (curr
->base
+ curr
->len
)) &&
2790 ((f
->l_start
+ f
->l_len
) > curr
->base
)) {
2791 /* region overlaps */
2798 curr
= HeapAlloc( GetProcessHeap(), 0, sizeof(DOS_FILE_LOCK
) );
2799 curr
->processId
= GetCurrentProcessId();
2800 curr
->base
= f
->l_start
;
2801 curr
->len
= f
->l_len
;
2802 /* curr->unix_name = HEAP_strdupA( GetProcessHeap(), 0, file->unix_name);*/
2804 curr
->dos_file
= file
;
2809 static void DOS_RemoveFileLocks(FILE_OBJECT
*file
)
2812 DOS_FILE_LOCK
**curr
;
2815 processId
= GetCurrentProcessId();
2818 if ((*curr
)->dos_file
== file
) {
2820 *curr
= (*curr
)->next
;
2821 /* HeapFree( GetProcessHeap(), 0, rem->unix_name );*/
2822 HeapFree( GetProcessHeap(), 0, rem
);
2825 curr
= &(*curr
)->next
;
2829 static BOOL
DOS_RemoveLock(FILE_OBJECT
*file
, struct flock
*f
)
2832 DOS_FILE_LOCK
**curr
;
2835 processId
= GetCurrentProcessId();
2836 for (curr
= &locks
; *curr
; curr
= &(*curr
)->next
) {
2837 if ((*curr
)->processId
== processId
&&
2838 (*curr
)->dos_file
== file
&&
2839 (*curr
)->base
== f
->l_start
&&
2840 (*curr
)->len
== f
->l_len
) {
2841 /* this is the same lock */
2843 *curr
= (*curr
)->next
;
2844 /* HeapFree( GetProcessHeap(), 0, rem->unix_name );*/
2845 HeapFree( GetProcessHeap(), 0, rem
);
2849 /* no matching lock found */
2854 /**************************************************************************
2855 * LockFile (KERNEL32.@)
2857 BOOL WINAPI
LockFile(
2858 HFILE hFile
,DWORD dwFileOffsetLow
,DWORD dwFileOffsetHigh
,
2859 DWORD nNumberOfBytesToLockLow
,DWORD nNumberOfBytesToLockHigh
)
2864 TRACE("handle %d offsetlow=%ld offsethigh=%ld nbyteslow=%ld nbyteshigh=%ld\n",
2865 hFile
, dwFileOffsetLow
, dwFileOffsetHigh
,
2866 nNumberOfBytesToLockLow
, nNumberOfBytesToLockHigh
);
2868 if (dwFileOffsetHigh
|| nNumberOfBytesToLockHigh
) {
2869 FIXME("Unimplemented bytes > 32bits\n");
2873 f
.l_start
= dwFileOffsetLow
;
2874 f
.l_len
= nNumberOfBytesToLockLow
;
2875 f
.l_whence
= SEEK_SET
;
2879 if (!(file
= FILE_GetFile(hFile
,0,NULL
))) return FALSE
;
2881 /* shadow locks internally */
2882 if (!DOS_AddLock(file
, &f
)) {
2883 SetLastError( ERROR_LOCK_VIOLATION
);
2887 /* FIXME: Unix locking commented out for now, doesn't work with Excel */
2888 #ifdef USE_UNIX_LOCKS
2889 if (fcntl(file
->unix_handle
, F_SETLK
, &f
) == -1) {
2890 if (errno
== EACCES
|| errno
== EAGAIN
) {
2891 SetLastError( ERROR_LOCK_VIOLATION
);
2896 /* remove our internal copy of the lock */
2897 DOS_RemoveLock(file
, &f
);
2905 /**************************************************************************
2906 * UnlockFile (KERNEL32.@)
2908 BOOL WINAPI
UnlockFile(
2909 HFILE hFile
,DWORD dwFileOffsetLow
,DWORD dwFileOffsetHigh
,
2910 DWORD nNumberOfBytesToUnlockLow
,DWORD nNumberOfBytesToUnlockHigh
)
2915 TRACE("handle %d offsetlow=%ld offsethigh=%ld nbyteslow=%ld nbyteshigh=%ld\n",
2916 hFile
, dwFileOffsetLow
, dwFileOffsetHigh
,
2917 nNumberOfBytesToUnlockLow
, nNumberOfBytesToUnlockHigh
);
2919 if (dwFileOffsetHigh
|| nNumberOfBytesToUnlockHigh
) {
2920 WARN("Unimplemented bytes > 32bits\n");
2924 f
.l_start
= dwFileOffsetLow
;
2925 f
.l_len
= nNumberOfBytesToUnlockLow
;
2926 f
.l_whence
= SEEK_SET
;
2930 if (!(file
= FILE_GetFile(hFile
,0,NULL
))) return FALSE
;
2932 DOS_RemoveLock(file
, &f
); /* ok if fails - may be another wine */
2934 /* FIXME: Unix locking commented out for now, doesn't work with Excel */
2935 #ifdef USE_UNIX_LOCKS
2936 if (fcntl(file
->unix_handle
, F_SETLK
, &f
) == -1) {
2945 /**************************************************************************
2946 * GetFileAttributesExA [KERNEL32.@]
2948 BOOL WINAPI
GetFileAttributesExA(
2949 LPCSTR lpFileName
, GET_FILEEX_INFO_LEVELS fInfoLevelId
,
2950 LPVOID lpFileInformation
)
2952 DOS_FULL_NAME full_name
;
2953 BY_HANDLE_FILE_INFORMATION info
;
2955 if (lpFileName
== NULL
) return FALSE
;
2956 if (lpFileInformation
== NULL
) return FALSE
;
2958 if (fInfoLevelId
== GetFileExInfoStandard
) {
2959 LPWIN32_FILE_ATTRIBUTE_DATA lpFad
=
2960 (LPWIN32_FILE_ATTRIBUTE_DATA
) lpFileInformation
;
2961 if (!DOSFS_GetFullName( lpFileName
, TRUE
, &full_name
)) return FALSE
;
2962 if (!FILE_Stat( full_name
.long_name
, &info
)) return FALSE
;
2964 lpFad
->dwFileAttributes
= info
.dwFileAttributes
;
2965 lpFad
->ftCreationTime
= info
.ftCreationTime
;
2966 lpFad
->ftLastAccessTime
= info
.ftLastAccessTime
;
2967 lpFad
->ftLastWriteTime
= info
.ftLastWriteTime
;
2968 lpFad
->nFileSizeHigh
= info
.nFileSizeHigh
;
2969 lpFad
->nFileSizeLow
= info
.nFileSizeLow
;
2972 FIXME("invalid info level %d!\n", fInfoLevelId
);
2980 /**************************************************************************
2981 * GetFileAttributesExW [KERNEL32.@]
2983 BOOL WINAPI
GetFileAttributesExW(
2984 LPCWSTR lpFileName
, GET_FILEEX_INFO_LEVELS fInfoLevelId
,
2985 LPVOID lpFileInformation
)
2987 LPSTR nameA
= HEAP_strdupWtoA( GetProcessHeap(), 0, lpFileName
);
2989 GetFileAttributesExA( nameA
, fInfoLevelId
, lpFileInformation
);
2990 HeapFree( GetProcessHeap(), 0, nameA
);