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"
59 #include "wine/debug.h"
61 #include "wine/server.h"
63 WINE_DEFAULT_DEBUG_CHANNEL(file
);
65 #if defined(MAP_ANONYMOUS) && !defined(MAP_ANON)
66 #define MAP_ANON MAP_ANONYMOUS
69 /* Size of per-process table of DOS handles */
70 #define DOS_TABLE_SIZE 256
72 /* Macro to derive file offset from OVERLAPPED struct */
73 #define OVERLAPPED_OFFSET(overlapped) ((off_t) (overlapped)->Offset + ((off_t) (overlapped)->OffsetHigh << 32))
75 static HANDLE dos_handles
[DOS_TABLE_SIZE
];
78 /***********************************************************************
81 * Convert OF_* mode into flags for CreateFile.
83 static void FILE_ConvertOFMode( INT mode
, DWORD
*access
, DWORD
*sharing
)
87 case OF_READ
: *access
= GENERIC_READ
; break;
88 case OF_WRITE
: *access
= GENERIC_WRITE
; break;
89 case OF_READWRITE
: *access
= GENERIC_READ
| GENERIC_WRITE
; break;
90 default: *access
= 0; break;
94 case OF_SHARE_EXCLUSIVE
: *sharing
= 0; break;
95 case OF_SHARE_DENY_WRITE
: *sharing
= FILE_SHARE_READ
; break;
96 case OF_SHARE_DENY_READ
: *sharing
= FILE_SHARE_WRITE
; break;
97 case OF_SHARE_DENY_NONE
:
99 default: *sharing
= FILE_SHARE_READ
| FILE_SHARE_WRITE
; break;
104 /***********************************************************************
107 * locale-independent case conversion for file I/O
109 int FILE_strcasecmp( const char *str1
, const char *str2
)
113 int ret
= FILE_toupper(*str1
) - FILE_toupper(*str2
);
114 if (ret
|| !*str1
) return ret
;
121 /***********************************************************************
124 * locale-independent case conversion for file I/O
126 int FILE_strncasecmp( const char *str1
, const char *str2
, int len
)
129 for ( ; len
> 0; len
--, str1
++, str2
++)
130 if ((ret
= FILE_toupper(*str1
) - FILE_toupper(*str2
)) || !*str1
) break;
135 /***********************************************************************
138 * Set the DOS error code from errno.
140 void FILE_SetDosError(void)
142 int save_errno
= errno
; /* errno gets overwritten by printf */
144 TRACE("errno = %d %s\n", errno
, strerror(errno
));
148 SetLastError( ERROR_SHARING_VIOLATION
);
151 SetLastError( ERROR_INVALID_HANDLE
);
154 SetLastError( ERROR_HANDLE_DISK_FULL
);
159 SetLastError( ERROR_ACCESS_DENIED
);
162 SetLastError( ERROR_LOCK_VIOLATION
);
165 SetLastError( ERROR_FILE_NOT_FOUND
);
168 SetLastError( ERROR_CANNOT_MAKE
);
172 SetLastError( ERROR_NO_MORE_FILES
);
175 SetLastError( ERROR_FILE_EXISTS
);
179 SetLastError( ERROR_SEEK
);
182 SetLastError( ERROR_DIR_NOT_EMPTY
);
185 SetLastError( ERROR_BAD_FORMAT
);
188 WARN("unknown file error: %s\n", strerror(save_errno
) );
189 SetLastError( ERROR_GEN_FAILURE
);
196 /***********************************************************************
199 * Duplicate a Unix handle into a task handle.
200 * Returns 0 on failure.
202 HANDLE
FILE_DupUnixHandle( int fd
, DWORD access
, BOOL inherit
)
206 wine_server_send_fd( fd
);
208 SERVER_START_REQ( alloc_file_handle
)
210 req
->access
= access
;
211 req
->inherit
= inherit
;
213 wine_server_call( req
);
221 /***********************************************************************
222 * FILE_GetUnixHandleType
224 * Retrieve the Unix handle corresponding to a file handle.
225 * Returns -1 on failure.
227 static int FILE_GetUnixHandleType( HANDLE handle
, DWORD access
, enum fd_type
*type
, DWORD
*flags
)
233 SERVER_START_REQ( get_handle_fd
)
235 req
->handle
= handle
;
236 req
->access
= access
;
237 if (!(ret
= wine_server_call_err( req
)))
241 if (type
) *type
= reply
->type
;
242 if (flags
) *flags
= reply
->flags
;
247 if (fd
== -1) /* it wasn't in the cache, get it from the server */
248 fd
= wine_server_recv_fd( handle
);
250 } while (fd
== -2); /* -2 means race condition, so restart from scratch */
254 if ((fd
= dup(fd
)) == -1)
255 SetLastError( ERROR_TOO_MANY_OPEN_FILES
);
260 /***********************************************************************
263 * Retrieve the Unix handle corresponding to a file handle.
264 * Returns -1 on failure.
266 int FILE_GetUnixHandle( HANDLE handle
, DWORD access
)
268 return FILE_GetUnixHandleType( handle
, access
, NULL
, NULL
);
271 /*************************************************************************
274 * Open a handle to the current process console.
275 * Returns 0 on failure.
277 static HANDLE
FILE_OpenConsole( BOOL output
, DWORD access
, DWORD sharing
, LPSECURITY_ATTRIBUTES sa
)
281 SERVER_START_REQ( open_console
)
284 req
->access
= access
;
285 req
->share
= sharing
;
286 req
->inherit
= (sa
&& (sa
->nLength
>=sizeof(*sa
)) && sa
->bInheritHandle
);
288 wine_server_call_err( req
);
296 /***********************************************************************
299 * Implementation of CreateFile. Takes a Unix path name.
300 * Returns 0 on failure.
302 HANDLE
FILE_CreateFile( LPCSTR filename
, DWORD access
, DWORD sharing
,
303 LPSECURITY_ATTRIBUTES sa
, DWORD creation
,
304 DWORD attributes
, HANDLE
template, BOOL fail_read_only
,
312 SERVER_START_REQ( create_file
)
314 req
->access
= access
;
315 req
->inherit
= (sa
&& (sa
->nLength
>=sizeof(*sa
)) && sa
->bInheritHandle
);
316 req
->sharing
= sharing
;
317 req
->create
= creation
;
318 req
->attrs
= attributes
;
319 req
->drive_type
= drive_type
;
320 wine_server_add_data( req
, filename
, strlen(filename
) );
322 err
= wine_server_call( req
);
327 /* If write access failed, retry without GENERIC_WRITE */
329 if (!ret
&& !fail_read_only
&& (access
& GENERIC_WRITE
))
331 if ((err
== STATUS_MEDIA_WRITE_PROTECTED
) || (err
== STATUS_ACCESS_DENIED
))
333 TRACE("Write access failed for file '%s', trying without "
334 "write access\n", filename
);
335 access
&= ~GENERIC_WRITE
;
340 if (err
) SetLastError( RtlNtStatusToDosError(err
) );
342 if (!ret
) WARN("Unable to create file '%s' (GLE %ld)\n", filename
, GetLastError());
348 /***********************************************************************
351 * Same as FILE_CreateFile but for a device
352 * Returns 0 on failure.
354 HANDLE
FILE_CreateDevice( int client_id
, DWORD access
, LPSECURITY_ATTRIBUTES sa
)
357 SERVER_START_REQ( create_device
)
359 req
->access
= access
;
360 req
->inherit
= (sa
&& (sa
->nLength
>=sizeof(*sa
)) && sa
->bInheritHandle
);
363 wine_server_call_err( req
);
370 static HANDLE
FILE_OpenPipe(LPCSTR name
, DWORD access
)
372 WCHAR buffer
[MAX_PATH
];
376 if (name
&& !(len
= MultiByteToWideChar( CP_ACP
, 0, name
, strlen(name
), buffer
, MAX_PATH
)))
378 SetLastError( ERROR_FILENAME_EXCED_RANGE
);
381 SERVER_START_REQ( open_named_pipe
)
383 req
->access
= access
;
385 wine_server_add_data( req
, buffer
, len
* sizeof(WCHAR
) );
386 wine_server_call_err( req
);
390 TRACE("Returned %d\n",ret
);
394 /*************************************************************************
395 * CreateFileA [KERNEL32.@] Creates or opens a file or other object
397 * Creates or opens an object, and returns a handle that can be used to
398 * access that object.
402 * filename [in] pointer to filename to be accessed
403 * access [in] access mode requested
404 * sharing [in] share mode
405 * sa [in] pointer to security attributes
406 * creation [in] how to create the file
407 * attributes [in] attributes for newly created file
408 * template [in] handle to file with extended attributes to copy
411 * Success: Open handle to specified file
412 * Failure: INVALID_HANDLE_VALUE
415 * Should call SetLastError() on failure.
419 * Doesn't support character devices, template files, or a
420 * lot of the 'attributes' flags yet.
422 HANDLE WINAPI
CreateFileA( LPCSTR filename
, DWORD access
, DWORD sharing
,
423 LPSECURITY_ATTRIBUTES sa
, DWORD creation
,
424 DWORD attributes
, HANDLE
template )
426 DOS_FULL_NAME full_name
;
431 SetLastError( ERROR_INVALID_PARAMETER
);
432 return INVALID_HANDLE_VALUE
;
434 TRACE("%s %s%s%s%s%s%s%s\n",filename
,
435 ((access
& GENERIC_READ
)==GENERIC_READ
)?"GENERIC_READ ":"",
436 ((access
& GENERIC_WRITE
)==GENERIC_WRITE
)?"GENERIC_WRITE ":"",
437 (!access
)?"QUERY_ACCESS ":"",
438 ((sharing
& FILE_SHARE_READ
)==FILE_SHARE_READ
)?"FILE_SHARE_READ ":"",
439 ((sharing
& FILE_SHARE_WRITE
)==FILE_SHARE_WRITE
)?"FILE_SHARE_WRITE ":"",
440 ((sharing
& FILE_SHARE_DELETE
)==FILE_SHARE_DELETE
)?"FILE_SHARE_DELETE ":"",
441 (creation
==CREATE_NEW
)?"CREATE_NEW":
442 (creation
==CREATE_ALWAYS
)?"CREATE_ALWAYS ":
443 (creation
==OPEN_EXISTING
)?"OPEN_EXISTING ":
444 (creation
==OPEN_ALWAYS
)?"OPEN_ALWAYS ":
445 (creation
==TRUNCATE_EXISTING
)?"TRUNCATE_EXISTING ":"");
447 /* If the name starts with '\\?\', ignore the first 4 chars. */
448 if (!strncmp(filename
, "\\\\?\\", 4))
451 if (!strncmp(filename
, "UNC\\", 4))
453 FIXME("UNC name (%s) not supported.\n", filename
);
454 SetLastError( ERROR_PATH_NOT_FOUND
);
455 return INVALID_HANDLE_VALUE
;
459 if (!strncmp(filename
, "\\\\.\\", 4)) {
460 if(!strncasecmp(&filename
[4],"pipe\\",5))
462 TRACE("Opening a pipe: %s\n",filename
);
463 ret
= FILE_OpenPipe(filename
,access
);
466 else if (isalpha(filename
[4]) && filename
[5] == ':' && filename
[6] == '\0')
468 ret
= FILE_CreateDevice( (toupper(filename
[4]) - 'A') | 0x20000, access
, sa
);
471 else if (!DOSFS_GetDevice( filename
))
473 ret
= DEVICE_Open( filename
+4, access
, sa
);
477 filename
+=4; /* fall into DOSFS_Device case below */
480 /* If the name still starts with '\\', it's a UNC name. */
481 if (!strncmp(filename
, "\\\\", 2))
483 FIXME("UNC name (%s) not supported.\n", filename
);
484 SetLastError( ERROR_PATH_NOT_FOUND
);
485 return INVALID_HANDLE_VALUE
;
488 /* If the name contains a DOS wild card (* or ?), do no create a file */
489 if(strchr(filename
,'*') || strchr(filename
,'?'))
490 return INVALID_HANDLE_VALUE
;
492 /* Open a console for CONIN$ or CONOUT$ */
493 if (!strcasecmp(filename
, "CONIN$"))
495 ret
= FILE_OpenConsole( FALSE
, access
, sharing
, sa
);
498 if (!strcasecmp(filename
, "CONOUT$"))
500 ret
= FILE_OpenConsole( TRUE
, access
, sharing
, sa
);
504 if (DOSFS_GetDevice( filename
))
506 TRACE("opening device '%s'\n", filename
);
508 if (!(ret
= DOSFS_OpenDevice( filename
, access
, attributes
, sa
)))
510 /* Do not silence this please. It is a critical error. -MM */
511 ERR("Couldn't open device '%s'!\n",filename
);
512 SetLastError( ERROR_FILE_NOT_FOUND
);
517 /* check for filename, don't check for last entry if creating */
518 if (!DOSFS_GetFullName( filename
,
519 (creation
== OPEN_EXISTING
) ||
520 (creation
== TRUNCATE_EXISTING
),
522 WARN("Unable to get full filename from '%s' (GLE %ld)\n",
523 filename
, GetLastError());
524 return INVALID_HANDLE_VALUE
;
527 ret
= FILE_CreateFile( full_name
.long_name
, access
, sharing
,
528 sa
, creation
, attributes
, template,
529 DRIVE_GetFlags(full_name
.drive
) & DRIVE_FAIL_READ_ONLY
,
530 GetDriveTypeA( full_name
.short_name
) );
532 if (!ret
) ret
= INVALID_HANDLE_VALUE
;
538 /*************************************************************************
539 * CreateFileW (KERNEL32.@)
541 HANDLE WINAPI
CreateFileW( LPCWSTR filename
, DWORD access
, DWORD sharing
,
542 LPSECURITY_ATTRIBUTES sa
, DWORD creation
,
543 DWORD attributes
, HANDLE
template)
545 LPSTR afn
= HEAP_strdupWtoA( GetProcessHeap(), 0, filename
);
546 HANDLE res
= CreateFileA( afn
, access
, sharing
, sa
, creation
, attributes
, template );
547 HeapFree( GetProcessHeap(), 0, afn
);
552 /***********************************************************************
555 * Fill a file information from a struct stat.
557 static void FILE_FillInfo( struct stat
*st
, BY_HANDLE_FILE_INFORMATION
*info
)
559 if (S_ISDIR(st
->st_mode
))
560 info
->dwFileAttributes
= FILE_ATTRIBUTE_DIRECTORY
;
562 info
->dwFileAttributes
= FILE_ATTRIBUTE_ARCHIVE
;
563 if (!(st
->st_mode
& S_IWUSR
))
564 info
->dwFileAttributes
|= FILE_ATTRIBUTE_READONLY
;
566 RtlSecondsSince1970ToTime( st
->st_mtime
, &info
->ftCreationTime
);
567 RtlSecondsSince1970ToTime( st
->st_mtime
, &info
->ftLastWriteTime
);
568 RtlSecondsSince1970ToTime( st
->st_atime
, &info
->ftLastAccessTime
);
570 info
->dwVolumeSerialNumber
= 0; /* FIXME */
571 info
->nFileSizeHigh
= 0;
572 info
->nFileSizeLow
= 0;
573 if (!S_ISDIR(st
->st_mode
)) {
574 info
->nFileSizeHigh
= st
->st_size
>> 32;
575 info
->nFileSizeLow
= st
->st_size
& 0xffffffff;
577 info
->nNumberOfLinks
= st
->st_nlink
;
578 info
->nFileIndexHigh
= 0;
579 info
->nFileIndexLow
= st
->st_ino
;
583 /***********************************************************************
586 * Stat a Unix path name. Return TRUE if OK.
588 BOOL
FILE_Stat( LPCSTR unixName
, BY_HANDLE_FILE_INFORMATION
*info
)
592 if (lstat( unixName
, &st
) == -1)
597 if (!S_ISLNK(st
.st_mode
)) FILE_FillInfo( &st
, info
);
600 /* do a "real" stat to find out
601 about the type of the symlink destination */
602 if (stat( unixName
, &st
) == -1)
607 FILE_FillInfo( &st
, info
);
608 info
->dwFileAttributes
|= FILE_ATTRIBUTE_SYMLINK
;
614 /***********************************************************************
615 * GetFileInformationByHandle (KERNEL32.@)
617 DWORD WINAPI
GetFileInformationByHandle( HANDLE hFile
,
618 BY_HANDLE_FILE_INFORMATION
*info
)
623 SERVER_START_REQ( get_file_info
)
626 if ((ret
= !wine_server_call_err( req
)))
628 /* FIXME: which file types are supported ?
629 * Serial ports (FILE_TYPE_CHAR) are not,
630 * and MSDN also says that pipes are not supported.
631 * FILE_TYPE_REMOTE seems to be supported according to
632 * MSDN q234741.txt */
633 if ((reply
->type
== FILE_TYPE_DISK
) || (reply
->type
== FILE_TYPE_REMOTE
))
635 RtlSecondsSince1970ToTime( reply
->write_time
, &info
->ftCreationTime
);
636 RtlSecondsSince1970ToTime( reply
->write_time
, &info
->ftLastWriteTime
);
637 RtlSecondsSince1970ToTime( reply
->access_time
, &info
->ftLastAccessTime
);
638 info
->dwFileAttributes
= reply
->attr
;
639 info
->dwVolumeSerialNumber
= reply
->serial
;
640 info
->nFileSizeHigh
= reply
->size_high
;
641 info
->nFileSizeLow
= reply
->size_low
;
642 info
->nNumberOfLinks
= reply
->links
;
643 info
->nFileIndexHigh
= reply
->index_high
;
644 info
->nFileIndexLow
= reply
->index_low
;
648 SetLastError(ERROR_NOT_SUPPORTED
);
658 /**************************************************************************
659 * GetFileAttributes (KERNEL.420)
661 DWORD WINAPI
GetFileAttributes16( LPCSTR name
)
663 return GetFileAttributesA( name
);
667 /**************************************************************************
668 * GetFileAttributesA (KERNEL32.@)
670 DWORD WINAPI
GetFileAttributesA( LPCSTR name
)
672 DOS_FULL_NAME full_name
;
673 BY_HANDLE_FILE_INFORMATION info
;
677 SetLastError( ERROR_INVALID_PARAMETER
);
680 if (!DOSFS_GetFullName( name
, TRUE
, &full_name
) )
682 if (!FILE_Stat( full_name
.long_name
, &info
)) return -1;
683 return info
.dwFileAttributes
;
687 /**************************************************************************
688 * GetFileAttributesW (KERNEL32.@)
690 DWORD WINAPI
GetFileAttributesW( LPCWSTR name
)
692 LPSTR nameA
= HEAP_strdupWtoA( GetProcessHeap(), 0, name
);
693 DWORD res
= GetFileAttributesA( nameA
);
694 HeapFree( GetProcessHeap(), 0, nameA
);
699 /***********************************************************************
700 * GetFileSize (KERNEL32.@)
702 DWORD WINAPI
GetFileSize( HANDLE hFile
, LPDWORD filesizehigh
)
704 BY_HANDLE_FILE_INFORMATION info
;
705 if (!GetFileInformationByHandle( hFile
, &info
)) return -1;
706 if (filesizehigh
) *filesizehigh
= info
.nFileSizeHigh
;
707 return info
.nFileSizeLow
;
711 /***********************************************************************
712 * GetFileTime (KERNEL32.@)
714 BOOL WINAPI
GetFileTime( HANDLE hFile
, FILETIME
*lpCreationTime
,
715 FILETIME
*lpLastAccessTime
,
716 FILETIME
*lpLastWriteTime
)
718 BY_HANDLE_FILE_INFORMATION info
;
719 if (!GetFileInformationByHandle( hFile
, &info
)) return FALSE
;
720 if (lpCreationTime
) *lpCreationTime
= info
.ftCreationTime
;
721 if (lpLastAccessTime
) *lpLastAccessTime
= info
.ftLastAccessTime
;
722 if (lpLastWriteTime
) *lpLastWriteTime
= info
.ftLastWriteTime
;
726 /***********************************************************************
727 * CompareFileTime (KERNEL32.@)
729 INT WINAPI
CompareFileTime( LPFILETIME x
, LPFILETIME y
)
731 if (!x
|| !y
) return -1;
733 if (x
->dwHighDateTime
> y
->dwHighDateTime
)
735 if (x
->dwHighDateTime
< y
->dwHighDateTime
)
737 if (x
->dwLowDateTime
> y
->dwLowDateTime
)
739 if (x
->dwLowDateTime
< y
->dwLowDateTime
)
744 /***********************************************************************
745 * FILE_GetTempFileName : utility for GetTempFileName
747 static UINT
FILE_GetTempFileName( LPCSTR path
, LPCSTR prefix
, UINT unique
,
748 LPSTR buffer
, BOOL isWin16
)
750 static UINT unique_temp
;
751 DOS_FULL_NAME full_name
;
756 if ( !path
|| !prefix
|| !buffer
) return 0;
758 if (!unique_temp
) unique_temp
= time(NULL
) & 0xffff;
759 num
= unique
? (unique
& 0xffff) : (unique_temp
++ & 0xffff);
761 strcpy( buffer
, path
);
762 p
= buffer
+ strlen(buffer
);
764 /* add a \, if there isn't one and path is more than just the drive letter ... */
765 if ( !((strlen(buffer
) == 2) && (buffer
[1] == ':'))
766 && ((p
== buffer
) || (p
[-1] != '\\'))) *p
++ = '\\';
768 if (isWin16
) *p
++ = '~';
769 for (i
= 3; (i
> 0) && (*prefix
); i
--) *p
++ = *prefix
++;
770 sprintf( p
, "%04x.tmp", num
);
772 /* Now try to create it */
778 HFILE handle
= CreateFileA( buffer
, GENERIC_WRITE
, 0, NULL
,
779 CREATE_NEW
, FILE_ATTRIBUTE_NORMAL
, 0 );
780 if (handle
!= INVALID_HANDLE_VALUE
)
781 { /* We created it */
782 TRACE("created %s\n",
784 CloseHandle( handle
);
787 if (GetLastError() != ERROR_FILE_EXISTS
)
788 break; /* No need to go on */
790 sprintf( p
, "%04x.tmp", num
);
791 } while (num
!= (unique
& 0xffff));
794 /* Get the full path name */
796 if (DOSFS_GetFullName( buffer
, FALSE
, &full_name
))
798 /* Check if we have write access in the directory */
799 if ((p
= strrchr( full_name
.long_name
, '/' ))) *p
= '\0';
800 if (access( full_name
.long_name
, W_OK
) == -1)
801 WARN("returns '%s', which doesn't seem to be writeable.\n",
804 TRACE("returning %s\n", buffer
);
805 return unique
? unique
: num
;
809 /***********************************************************************
810 * GetTempFileNameA (KERNEL32.@)
812 UINT WINAPI
GetTempFileNameA( LPCSTR path
, LPCSTR prefix
, UINT unique
,
815 return FILE_GetTempFileName(path
, prefix
, unique
, buffer
, FALSE
);
818 /***********************************************************************
819 * GetTempFileNameW (KERNEL32.@)
821 UINT WINAPI
GetTempFileNameW( LPCWSTR path
, LPCWSTR prefix
, UINT unique
,
829 patha
= HEAP_strdupWtoA( GetProcessHeap(), 0, path
);
830 prefixa
= HEAP_strdupWtoA( GetProcessHeap(), 0, prefix
);
831 ret
= FILE_GetTempFileName( patha
, prefixa
, unique
, buffera
, FALSE
);
832 MultiByteToWideChar( CP_ACP
, 0, buffera
, -1, buffer
, MAX_PATH
);
833 HeapFree( GetProcessHeap(), 0, patha
);
834 HeapFree( GetProcessHeap(), 0, prefixa
);
839 /***********************************************************************
840 * GetTempFileName (KERNEL.97)
842 UINT16 WINAPI
GetTempFileName16( BYTE drive
, LPCSTR prefix
, UINT16 unique
,
847 if (!(drive
& ~TF_FORCEDRIVE
)) /* drive 0 means current default drive */
848 drive
|= DRIVE_GetCurrentDrive() + 'A';
850 if ((drive
& TF_FORCEDRIVE
) &&
851 !DRIVE_IsValid( toupper(drive
& ~TF_FORCEDRIVE
) - 'A' ))
853 drive
&= ~TF_FORCEDRIVE
;
854 WARN("invalid drive %d specified\n", drive
);
857 if (drive
& TF_FORCEDRIVE
)
858 sprintf(temppath
,"%c:", drive
& ~TF_FORCEDRIVE
);
860 GetTempPathA( 132, temppath
);
861 return (UINT16
)FILE_GetTempFileName( temppath
, prefix
, unique
, buffer
, TRUE
);
864 /***********************************************************************
867 * Implementation of OpenFile16() and OpenFile32().
869 static HFILE
FILE_DoOpenFile( LPCSTR name
, OFSTRUCT
*ofs
, UINT mode
,
874 WORD filedatetime
[2];
875 DOS_FULL_NAME full_name
;
876 DWORD access
, sharing
;
879 if (!ofs
) return HFILE_ERROR
;
881 TRACE("%s %s %s %s%s%s%s%s%s%s%s%s\n",name
,
882 ((mode
& 0x3 )==OF_READ
)?"OF_READ":
883 ((mode
& 0x3 )==OF_WRITE
)?"OF_WRITE":
884 ((mode
& 0x3 )==OF_READWRITE
)?"OF_READWRITE":"unknown",
885 ((mode
& 0x70 )==OF_SHARE_COMPAT
)?"OF_SHARE_COMPAT":
886 ((mode
& 0x70 )==OF_SHARE_DENY_NONE
)?"OF_SHARE_DENY_NONE":
887 ((mode
& 0x70 )==OF_SHARE_DENY_READ
)?"OF_SHARE_DENY_READ":
888 ((mode
& 0x70 )==OF_SHARE_DENY_WRITE
)?"OF_SHARE_DENY_WRITE":
889 ((mode
& 0x70 )==OF_SHARE_EXCLUSIVE
)?"OF_SHARE_EXCLUSIVE":"unknown",
890 ((mode
& OF_PARSE
)==OF_PARSE
)?"OF_PARSE ":"",
891 ((mode
& OF_DELETE
)==OF_DELETE
)?"OF_DELETE ":"",
892 ((mode
& OF_VERIFY
)==OF_VERIFY
)?"OF_VERIFY ":"",
893 ((mode
& OF_SEARCH
)==OF_SEARCH
)?"OF_SEARCH ":"",
894 ((mode
& OF_CANCEL
)==OF_CANCEL
)?"OF_CANCEL ":"",
895 ((mode
& OF_CREATE
)==OF_CREATE
)?"OF_CREATE ":"",
896 ((mode
& OF_PROMPT
)==OF_PROMPT
)?"OF_PROMPT ":"",
897 ((mode
& OF_EXIST
)==OF_EXIST
)?"OF_EXIST ":"",
898 ((mode
& OF_REOPEN
)==OF_REOPEN
)?"OF_REOPEN ":""
902 ofs
->cBytes
= sizeof(OFSTRUCT
);
904 if (mode
& OF_REOPEN
) name
= ofs
->szPathName
;
907 ERR("called with `name' set to NULL ! Please debug.\n");
911 TRACE("%s %04x\n", name
, mode
);
913 /* the watcom 10.6 IDE relies on a valid path returned in ofs->szPathName
914 Are there any cases where getting the path here is wrong?
915 Uwe Bonnes 1997 Apr 2 */
916 if (!GetFullPathNameA( name
, sizeof(ofs
->szPathName
),
917 ofs
->szPathName
, NULL
)) goto error
;
918 FILE_ConvertOFMode( mode
, &access
, &sharing
);
920 /* OF_PARSE simply fills the structure */
924 ofs
->fFixedDisk
= (GetDriveType16( ofs
->szPathName
[0]-'A' )
926 TRACE("(%s): OF_PARSE, res = '%s'\n",
927 name
, ofs
->szPathName
);
931 /* OF_CREATE is completely different from all other options, so
934 if (mode
& OF_CREATE
)
936 if ((hFileRet
= CreateFileA( name
, GENERIC_READ
| GENERIC_WRITE
,
937 sharing
, NULL
, CREATE_ALWAYS
,
938 FILE_ATTRIBUTE_NORMAL
, 0 ))== INVALID_HANDLE_VALUE
)
943 /* If OF_SEARCH is set, ignore the given path */
945 if ((mode
& OF_SEARCH
) && !(mode
& OF_REOPEN
))
947 /* First try the file name as is */
948 if (DOSFS_GetFullName( name
, TRUE
, &full_name
)) goto found
;
949 /* Now remove the path */
950 if (name
[0] && (name
[1] == ':')) name
+= 2;
951 if ((p
= strrchr( name
, '\\' ))) name
= p
+ 1;
952 if ((p
= strrchr( name
, '/' ))) name
= p
+ 1;
953 if (!name
[0]) goto not_found
;
956 /* Now look for the file */
958 if (!DIR_SearchPath( NULL
, name
, NULL
, &full_name
, win32
)) goto not_found
;
961 TRACE("found %s = %s\n",
962 full_name
.long_name
, full_name
.short_name
);
963 lstrcpynA( ofs
->szPathName
, full_name
.short_name
,
964 sizeof(ofs
->szPathName
) );
966 if (mode
& OF_SHARE_EXCLUSIVE
)
967 /* Some InstallShield version uses OF_SHARE_EXCLUSIVE
968 on the file <tempdir>/_ins0432._mp to determine how
969 far installation has proceeded.
970 _ins0432._mp is an executable and while running the
971 application expects the open with OF_SHARE_ to fail*/
973 As our loader closes the files after loading the executable,
974 we can't find the running executable with FILE_InUse.
975 The loader should keep the file open, as Windows does that, too.
978 char *last
= strrchr(full_name
.long_name
,'/');
980 last
= full_name
.long_name
- 1;
981 if (GetModuleHandle16(last
+1))
983 TRACE("Denying shared open for %s\n",full_name
.long_name
);
988 if (mode
& OF_DELETE
)
990 if (unlink( full_name
.long_name
) == -1) goto not_found
;
991 TRACE("(%s): OF_DELETE return = OK\n", name
);
995 hFileRet
= FILE_CreateFile( full_name
.long_name
, access
, sharing
,
996 NULL
, OPEN_EXISTING
, 0, 0,
997 DRIVE_GetFlags(full_name
.drive
) & DRIVE_FAIL_READ_ONLY
,
998 GetDriveTypeA( full_name
.short_name
) );
999 if (!hFileRet
) goto not_found
;
1001 GetFileTime( hFileRet
, NULL
, NULL
, &filetime
);
1002 FileTimeToDosDateTime( &filetime
, &filedatetime
[0], &filedatetime
[1] );
1003 if ((mode
& OF_VERIFY
) && (mode
& OF_REOPEN
))
1005 if (memcmp( ofs
->reserved
, filedatetime
, sizeof(ofs
->reserved
) ))
1007 CloseHandle( hFileRet
);
1008 WARN("(%s): OF_VERIFY failed\n", name
);
1009 /* FIXME: what error here? */
1010 SetLastError( ERROR_FILE_NOT_FOUND
);
1014 memcpy( ofs
->reserved
, filedatetime
, sizeof(ofs
->reserved
) );
1016 success
: /* We get here if the open was successful */
1017 TRACE("(%s): OK, return = %d\n", name
, hFileRet
);
1020 if (mode
& OF_EXIST
) /* Return the handle, but close it first */
1021 CloseHandle( hFileRet
);
1025 hFileRet
= Win32HandleToDosFileHandle( hFileRet
);
1026 if (hFileRet
== HFILE_ERROR16
) goto error
;
1027 if (mode
& OF_EXIST
) /* Return the handle, but close it first */
1028 _lclose16( hFileRet
);
1032 not_found
: /* We get here if the file does not exist */
1033 WARN("'%s' not found or sharing violation\n", name
);
1034 SetLastError( ERROR_FILE_NOT_FOUND
);
1037 error
: /* We get here if there was an error opening the file */
1038 ofs
->nErrCode
= GetLastError();
1039 WARN("(%s): return = HFILE_ERROR error= %d\n",
1040 name
,ofs
->nErrCode
);
1045 /***********************************************************************
1046 * OpenFile (KERNEL.74)
1047 * OpenFileEx (KERNEL.360)
1049 HFILE16 WINAPI
OpenFile16( LPCSTR name
, OFSTRUCT
*ofs
, UINT16 mode
)
1051 return FILE_DoOpenFile( name
, ofs
, mode
, FALSE
);
1055 /***********************************************************************
1056 * OpenFile (KERNEL32.@)
1058 HFILE WINAPI
OpenFile( LPCSTR name
, OFSTRUCT
*ofs
, UINT mode
)
1060 return FILE_DoOpenFile( name
, ofs
, mode
, TRUE
);
1064 /***********************************************************************
1065 * FILE_InitProcessDosHandles
1067 * Allocates the default DOS handles for a process. Called either by
1068 * Win32HandleToDosFileHandle below or by the DOSVM stuff.
1070 static void FILE_InitProcessDosHandles( void )
1072 dos_handles
[0] = GetStdHandle(STD_INPUT_HANDLE
);
1073 dos_handles
[1] = GetStdHandle(STD_OUTPUT_HANDLE
);
1074 dos_handles
[2] = GetStdHandle(STD_ERROR_HANDLE
);
1075 dos_handles
[3] = GetStdHandle(STD_ERROR_HANDLE
);
1076 dos_handles
[4] = GetStdHandle(STD_ERROR_HANDLE
);
1079 /***********************************************************************
1080 * Win32HandleToDosFileHandle (KERNEL32.21)
1082 * Allocate a DOS handle for a Win32 handle. The Win32 handle is no
1083 * longer valid after this function (even on failure).
1085 * Note: this is not exactly right, since on Win95 the Win32 handles
1086 * are on top of DOS handles and we do it the other way
1087 * around. Should be good enough though.
1089 HFILE WINAPI
Win32HandleToDosFileHandle( HANDLE handle
)
1093 if (!handle
|| (handle
== INVALID_HANDLE_VALUE
))
1096 for (i
= 5; i
< DOS_TABLE_SIZE
; i
++)
1097 if (!dos_handles
[i
])
1099 dos_handles
[i
] = handle
;
1100 TRACE("Got %d for h32 %d\n", i
, handle
);
1103 CloseHandle( handle
);
1104 SetLastError( ERROR_TOO_MANY_OPEN_FILES
);
1109 /***********************************************************************
1110 * DosFileHandleToWin32Handle (KERNEL32.20)
1112 * Return the Win32 handle for a DOS handle.
1114 * Note: this is not exactly right, since on Win95 the Win32 handles
1115 * are on top of DOS handles and we do it the other way
1116 * around. Should be good enough though.
1118 HANDLE WINAPI
DosFileHandleToWin32Handle( HFILE handle
)
1120 HFILE16 hfile
= (HFILE16
)handle
;
1121 if (hfile
< 5 && !dos_handles
[hfile
]) FILE_InitProcessDosHandles();
1122 if ((hfile
>= DOS_TABLE_SIZE
) || !dos_handles
[hfile
])
1124 SetLastError( ERROR_INVALID_HANDLE
);
1125 return INVALID_HANDLE_VALUE
;
1127 return dos_handles
[hfile
];
1131 /***********************************************************************
1132 * DisposeLZ32Handle (KERNEL32.22)
1134 * Note: this is not entirely correct, we should only close the
1135 * 32-bit handle and not the 16-bit one, but we cannot do
1136 * this because of the way our DOS handles are implemented.
1137 * It shouldn't break anything though.
1139 void WINAPI
DisposeLZ32Handle( HANDLE handle
)
1143 if (!handle
|| (handle
== INVALID_HANDLE_VALUE
)) return;
1145 for (i
= 5; i
< DOS_TABLE_SIZE
; i
++)
1146 if (dos_handles
[i
] == handle
)
1149 CloseHandle( handle
);
1155 /***********************************************************************
1158 * dup2() function for DOS handles.
1160 HFILE16
FILE_Dup2( HFILE16 hFile1
, HFILE16 hFile2
)
1164 if (hFile1
< 5 && !dos_handles
[hFile1
]) FILE_InitProcessDosHandles();
1166 if ((hFile1
>= DOS_TABLE_SIZE
) || (hFile2
>= DOS_TABLE_SIZE
) || !dos_handles
[hFile1
])
1168 SetLastError( ERROR_INVALID_HANDLE
);
1169 return HFILE_ERROR16
;
1173 FIXME("stdio handle closed, need proper conversion\n" );
1174 SetLastError( ERROR_INVALID_HANDLE
);
1175 return HFILE_ERROR16
;
1177 if (!DuplicateHandle( GetCurrentProcess(), dos_handles
[hFile1
],
1178 GetCurrentProcess(), &new_handle
,
1179 0, FALSE
, DUPLICATE_SAME_ACCESS
))
1180 return HFILE_ERROR16
;
1181 if (dos_handles
[hFile2
]) CloseHandle( dos_handles
[hFile2
] );
1182 dos_handles
[hFile2
] = new_handle
;
1187 /***********************************************************************
1188 * _lclose (KERNEL.81)
1190 HFILE16 WINAPI
_lclose16( HFILE16 hFile
)
1194 FIXME("stdio handle closed, need proper conversion\n" );
1195 SetLastError( ERROR_INVALID_HANDLE
);
1196 return HFILE_ERROR16
;
1198 if ((hFile
>= DOS_TABLE_SIZE
) || !dos_handles
[hFile
])
1200 SetLastError( ERROR_INVALID_HANDLE
);
1201 return HFILE_ERROR16
;
1203 TRACE("%d (handle32=%d)\n", hFile
, dos_handles
[hFile
] );
1204 CloseHandle( dos_handles
[hFile
] );
1205 dos_handles
[hFile
] = 0;
1210 /***********************************************************************
1211 * _lclose (KERNEL32.@)
1213 HFILE WINAPI
_lclose( HFILE hFile
)
1215 TRACE("handle %d\n", hFile
);
1216 return CloseHandle( hFile
) ? 0 : HFILE_ERROR
;
1219 /***********************************************************************
1220 * GetOverlappedResult (KERNEL32.@)
1222 * Check the result of an Asynchronous data transfer from a file.
1228 * If successful (and relevant) lpTransferred will hold the number of
1229 * bytes transferred during the async operation.
1233 * Currently only works for WaitCommEvent, ReadFile, WriteFile
1234 * with communications ports.
1237 BOOL WINAPI
GetOverlappedResult(
1238 HANDLE hFile
, /* [in] handle of file to check on */
1239 LPOVERLAPPED lpOverlapped
, /* [in/out] pointer to overlapped */
1240 LPDWORD lpTransferred
, /* [in/out] number of bytes transferred */
1241 BOOL bWait
/* [in] wait for the transfer to complete ? */
1245 TRACE("(%d %p %p %x)\n", hFile
, lpOverlapped
, lpTransferred
, bWait
);
1247 if(lpOverlapped
==NULL
)
1249 ERR("lpOverlapped was null\n");
1252 if(!lpOverlapped
->hEvent
)
1254 ERR("lpOverlapped->hEvent was null\n");
1259 TRACE("waiting on %p\n",lpOverlapped
);
1260 r
= WaitForSingleObjectEx(lpOverlapped
->hEvent
, bWait
?INFINITE
:0, TRUE
);
1261 TRACE("wait on %p returned %ld\n",lpOverlapped
,r
);
1262 } while (r
==STATUS_USER_APC
);
1265 *lpTransferred
= lpOverlapped
->InternalHigh
;
1267 SetLastError(lpOverlapped
->Internal
);
1269 return (r
==WAIT_OBJECT_0
);
1273 /***********************************************************************
1274 * FILE_StartAsync (INTERNAL)
1276 * type==ASYNC_TYPE_NONE means cancel the indicated overlapped operation
1277 * lpOverlapped==NULL means all overlappeds match
1279 BOOL
FILE_StartAsync(HANDLE hFile
, LPOVERLAPPED lpOverlapped
, DWORD type
, DWORD count
, DWORD status
)
1282 SERVER_START_REQ(register_async
)
1284 req
->handle
= hFile
;
1285 req
->overlapped
= lpOverlapped
;
1288 req
->func
= check_async_list
;
1289 req
->status
= status
;
1290 ret
= wine_server_call( req
);
1296 /***********************************************************************
1297 * CancelIo (KERNEL32.@)
1299 BOOL WINAPI
CancelIo(HANDLE handle
)
1301 async_private
*ovp
,*t
;
1303 TRACE("handle = %x\n",handle
);
1305 ovp
= NtCurrentTeb()->pending_list
;
1309 if(FILE_StartAsync(handle
, ovp
->lpOverlapped
, ovp
->type
, 0, STATUS_CANCELLED
))
1311 TRACE("overlapped = %p\n",ovp
->lpOverlapped
);
1312 finish_async(ovp
, STATUS_CANCELLED
);
1316 WaitForMultipleObjectsEx(0,NULL
,FALSE
,1,TRUE
);
1320 /***********************************************************************
1321 * FILE_AsyncReadService (INTERNAL)
1323 * This function is called while the client is waiting on the
1324 * server, so we can't make any server calls here.
1326 static void FILE_AsyncReadService(async_private
*ovp
)
1328 LPOVERLAPPED lpOverlapped
= ovp
->lpOverlapped
;
1330 int already
= lpOverlapped
->InternalHigh
;
1332 TRACE("%p %p\n", lpOverlapped
, ovp
->buffer
);
1334 /* check to see if the data is ready (non-blocking) */
1336 result
= pread (ovp
->fd
, &ovp
->buffer
[already
], ovp
->count
- already
,
1337 OVERLAPPED_OFFSET (lpOverlapped
) + already
);
1338 if ((result
< 0) && (errno
== ESPIPE
))
1339 result
= read (ovp
->fd
, &ovp
->buffer
[already
], ovp
->count
- already
);
1341 if ( (result
<0) && ((errno
== EAGAIN
) || (errno
== EINTR
)))
1343 TRACE("Deferred read %d\n",errno
);
1348 /* check to see if the transfer is complete */
1351 TRACE("read returned errno %d\n",errno
);
1352 r
= STATUS_UNSUCCESSFUL
;
1356 lpOverlapped
->InternalHigh
+= result
;
1357 TRACE("read %d more bytes %ld/%d so far\n",result
,lpOverlapped
->InternalHigh
,ovp
->count
);
1359 if(lpOverlapped
->InternalHigh
< ovp
->count
)
1365 lpOverlapped
->Internal
= r
;
1368 /***********************************************************************
1369 * FILE_ReadFileEx (INTERNAL)
1371 static BOOL
FILE_ReadFileEx(HANDLE hFile
, LPVOID buffer
, DWORD bytesToRead
,
1372 LPOVERLAPPED overlapped
,
1373 LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine
)
1378 TRACE("file %d to buf %p num %ld %p func %p\n",
1379 hFile
, buffer
, bytesToRead
, overlapped
, lpCompletionRoutine
);
1381 /* check that there is an overlapped struct */
1382 if (overlapped
==NULL
)
1384 SetLastError(ERROR_INVALID_PARAMETER
);
1388 fd
= FILE_GetUnixHandle( hFile
, GENERIC_READ
);
1391 TRACE("Couldn't get FD\n");
1395 ovp
= (async_private
*) HeapAlloc(GetProcessHeap(), 0, sizeof (async_private
));
1398 TRACE("HeapAlloc Failed\n");
1399 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
1403 ovp
->lpOverlapped
= overlapped
;
1404 ovp
->count
= bytesToRead
;
1405 ovp
->completion_func
= lpCompletionRoutine
;
1406 ovp
->func
= FILE_AsyncReadService
;
1407 ovp
->buffer
= buffer
;
1409 ovp
->type
= ASYNC_TYPE_READ
;
1410 ovp
->handle
= hFile
;
1412 /* hook this overlap into the pending async operation list */
1413 ovp
->next
= NtCurrentTeb()->pending_list
;
1416 ovp
->next
->prev
= ovp
;
1417 NtCurrentTeb()->pending_list
= ovp
;
1419 if ( !FILE_StartAsync(hFile
, overlapped
, ASYNC_TYPE_READ
, bytesToRead
, STATUS_PENDING
) )
1421 /* FIXME: remove async_private and release memory */
1422 ERR("FILE_StartAsync failed\n");
1429 /***********************************************************************
1430 * ReadFileEx (KERNEL32.@)
1432 BOOL WINAPI
ReadFileEx(HANDLE hFile
, LPVOID buffer
, DWORD bytesToRead
,
1433 LPOVERLAPPED overlapped
,
1434 LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine
)
1436 overlapped
->Internal
= STATUS_PENDING
;
1437 overlapped
->InternalHigh
= 0;
1438 return FILE_ReadFileEx(hFile
,buffer
,bytesToRead
,overlapped
,lpCompletionRoutine
);
1441 static VOID CALLBACK
FILE_OverlappedComplete(DWORD status
, DWORD count
, LPOVERLAPPED ov
)
1443 NtSetEvent(ov
->hEvent
,NULL
);
1446 static BOOL
FILE_TimeoutRead(HANDLE hFile
, LPVOID buffer
, DWORD bytesToRead
, LPDWORD bytesRead
)
1451 TRACE("%d %p %ld %p\n", hFile
, buffer
, bytesToRead
, bytesRead
);
1453 ZeroMemory(&ov
, sizeof (OVERLAPPED
));
1454 if(STATUS_SUCCESS
==NtCreateEvent(&ov
.hEvent
, SYNCHRONIZE
, NULL
, 0, 0))
1456 if(ReadFileEx(hFile
, buffer
, bytesToRead
, &ov
, FILE_OverlappedComplete
))
1458 r
= GetOverlappedResult(hFile
, &ov
, bytesRead
, TRUE
);
1461 CloseHandle(ov
.hEvent
);
1465 /***********************************************************************
1466 * ReadFile (KERNEL32.@)
1468 BOOL WINAPI
ReadFile( HANDLE hFile
, LPVOID buffer
, DWORD bytesToRead
,
1469 LPDWORD bytesRead
, LPOVERLAPPED overlapped
)
1471 int unix_handle
, result
;
1475 TRACE("%d %p %ld %p %p\n", hFile
, buffer
, bytesToRead
,
1476 bytesRead
, overlapped
);
1478 if (bytesRead
) *bytesRead
= 0; /* Do this before anything else */
1479 if (!bytesToRead
) return TRUE
;
1481 unix_handle
= FILE_GetUnixHandleType( hFile
, GENERIC_READ
, &type
, &flags
);
1483 if (flags
& FD_FLAG_OVERLAPPED
)
1485 if (unix_handle
== -1) return FALSE
;
1486 if ( (overlapped
==NULL
) || NtResetEvent( overlapped
->hEvent
, NULL
) )
1488 TRACE("Overlapped not specified or invalid event flag\n");
1490 SetLastError(ERROR_INVALID_PARAMETER
);
1494 /* see if we can read some data already (this shouldn't block) */
1495 result
= pread( unix_handle
, buffer
, bytesToRead
, OVERLAPPED_OFFSET(overlapped
) );
1496 if ((result
< 0) && (errno
== ESPIPE
))
1497 result
= read( unix_handle
, buffer
, bytesToRead
);
1502 if( (errno
!=EAGAIN
) && (errno
!=EINTR
) &&
1503 ((errno
!= EFAULT
) || IsBadWritePtr( buffer
, bytesToRead
)) )
1512 /* if we read enough to keep the app happy, then return now */
1513 if(result
>=bytesToRead
)
1515 *bytesRead
= result
;
1519 /* at last resort, do an overlapped read */
1520 overlapped
->Internal
= STATUS_PENDING
;
1521 overlapped
->InternalHigh
= result
;
1523 if(!FILE_ReadFileEx(hFile
, buffer
, bytesToRead
, overlapped
, FILE_OverlappedComplete
))
1526 /* fail on return, with ERROR_IO_PENDING */
1527 SetLastError(ERROR_IO_PENDING
);
1530 if (flags
& FD_FLAG_TIMEOUT
)
1533 return FILE_TimeoutRead(hFile
, buffer
, bytesToRead
, bytesRead
);
1537 case FD_TYPE_CONSOLE
:
1538 return ReadConsoleA(hFile
, buffer
, bytesToRead
, bytesRead
, NULL
);
1541 /* normal unix files */
1542 if (unix_handle
== -1)
1547 SetLastError(ERROR_INVALID_PARAMETER
);
1553 /* code for synchronous reads */
1554 while ((result
= read( unix_handle
, buffer
, bytesToRead
)) == -1)
1556 if ((errno
== EAGAIN
) || (errno
== EINTR
)) continue;
1557 if ((errno
== EFAULT
) && !IsBadWritePtr( buffer
, bytesToRead
)) continue;
1561 close( unix_handle
);
1562 if (result
== -1) return FALSE
;
1563 if (bytesRead
) *bytesRead
= result
;
1568 /***********************************************************************
1569 * FILE_AsyncWriteService (INTERNAL)
1571 * This function is called while the client is waiting on the
1572 * server, so we can't make any server calls here.
1574 static void FILE_AsyncWriteService(struct async_private
*ovp
)
1576 LPOVERLAPPED lpOverlapped
= ovp
->lpOverlapped
;
1578 int already
= lpOverlapped
->InternalHigh
;
1580 TRACE("(%p %p)\n",lpOverlapped
,ovp
->buffer
);
1582 /* write some data (non-blocking) */
1584 result
= pwrite(ovp
->fd
, &ovp
->buffer
[already
], ovp
->count
- already
,
1585 OVERLAPPED_OFFSET (lpOverlapped
) + already
);
1586 if ((result
< 0) && (errno
== ESPIPE
))
1587 result
= write(ovp
->fd
, &ovp
->buffer
[already
], ovp
->count
- already
);
1589 if ( (result
<0) && ((errno
== EAGAIN
) || (errno
== EINTR
)))
1595 /* check to see if the transfer is complete */
1598 r
= STATUS_UNSUCCESSFUL
;
1602 lpOverlapped
->InternalHigh
+= result
;
1604 TRACE("wrote %d more bytes %ld/%d so far\n",result
,lpOverlapped
->InternalHigh
,ovp
->count
);
1606 if(lpOverlapped
->InternalHigh
< ovp
->count
)
1612 lpOverlapped
->Internal
= r
;
1615 /***********************************************************************
1618 static BOOL
FILE_WriteFileEx(HANDLE hFile
, LPCVOID buffer
, DWORD bytesToWrite
,
1619 LPOVERLAPPED overlapped
,
1620 LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine
)
1624 TRACE("file %d to buf %p num %ld %p func %p stub\n",
1625 hFile
, buffer
, bytesToWrite
, overlapped
, lpCompletionRoutine
);
1627 if (overlapped
== NULL
)
1629 SetLastError(ERROR_INVALID_PARAMETER
);
1633 overlapped
->Internal
= STATUS_PENDING
;
1634 overlapped
->InternalHigh
= 0;
1636 if (!FILE_StartAsync(hFile
, overlapped
, ASYNC_TYPE_WRITE
, bytesToWrite
, STATUS_PENDING
))
1638 TRACE("FILE_StartAsync failed\n");
1642 ovp
= (async_private
*) HeapAlloc(GetProcessHeap(), 0, sizeof (async_private
));
1645 TRACE("HeapAlloc Failed\n");
1646 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
1649 ovp
->lpOverlapped
= overlapped
;
1650 ovp
->func
= FILE_AsyncWriteService
;
1651 ovp
->buffer
= (LPVOID
) buffer
;
1652 ovp
->count
= bytesToWrite
;
1653 ovp
->completion_func
= lpCompletionRoutine
;
1654 ovp
->fd
= FILE_GetUnixHandle( hFile
, GENERIC_WRITE
);
1655 ovp
->type
= ASYNC_TYPE_WRITE
;
1656 ovp
->handle
= hFile
;
1660 HeapFree(GetProcessHeap(), 0, ovp
);
1664 /* hook this overlap into the pending async operation list */
1665 ovp
->next
= NtCurrentTeb()->pending_list
;
1668 ovp
->next
->prev
= ovp
;
1669 NtCurrentTeb()->pending_list
= ovp
;
1674 /***********************************************************************
1675 * WriteFileEx (KERNEL32.@)
1677 BOOL WINAPI
WriteFileEx(HANDLE hFile
, LPCVOID buffer
, DWORD bytesToWrite
,
1678 LPOVERLAPPED overlapped
,
1679 LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine
)
1681 overlapped
->Internal
= STATUS_PENDING
;
1682 overlapped
->InternalHigh
= 0;
1684 return FILE_WriteFileEx(hFile
, buffer
, bytesToWrite
, overlapped
, lpCompletionRoutine
);
1687 /***********************************************************************
1688 * WriteFile (KERNEL32.@)
1690 BOOL WINAPI
WriteFile( HANDLE hFile
, LPCVOID buffer
, DWORD bytesToWrite
,
1691 LPDWORD bytesWritten
, LPOVERLAPPED overlapped
)
1693 int unix_handle
, result
;
1697 TRACE("%d %p %ld %p %p\n", hFile
, buffer
, bytesToWrite
,
1698 bytesWritten
, overlapped
);
1700 if (bytesWritten
) *bytesWritten
= 0; /* Do this before anything else */
1701 if (!bytesToWrite
) return TRUE
;
1703 unix_handle
= FILE_GetUnixHandleType( hFile
, GENERIC_WRITE
, &type
, &flags
);
1705 if (flags
& FD_FLAG_OVERLAPPED
)
1707 if (unix_handle
== -1) return FALSE
;
1708 if ( (overlapped
==NULL
) || NtResetEvent( overlapped
->hEvent
, NULL
) )
1710 TRACE("Overlapped not specified or invalid event flag\n");
1712 SetLastError(ERROR_INVALID_PARAMETER
);
1716 /* see if we can write some data already (this shouldn't block) */
1718 result
= pwrite( unix_handle
, buffer
, bytesToWrite
, OVERLAPPED_OFFSET (overlapped
) );
1719 if ((result
< 0) && (errno
== ESPIPE
))
1720 result
= write( unix_handle
, buffer
, bytesToWrite
);
1726 if( (errno
!=EAGAIN
) && (errno
!=EINTR
) &&
1727 ((errno
!= EFAULT
) || IsBadReadPtr( buffer
, bytesToWrite
)) )
1736 /* if we wrote enough to keep the app happy, then return now */
1737 if(result
>=bytesToWrite
)
1739 *bytesWritten
= result
;
1743 /* at last resort, do an overlapped read */
1744 overlapped
->Internal
= STATUS_PENDING
;
1745 overlapped
->InternalHigh
= result
;
1747 if(!FILE_WriteFileEx(hFile
, buffer
, bytesToWrite
, overlapped
, FILE_OverlappedComplete
))
1750 /* fail on return, with ERROR_IO_PENDING */
1751 SetLastError(ERROR_IO_PENDING
);
1757 case FD_TYPE_CONSOLE
:
1758 TRACE("%d %s %ld %p %p\n", hFile
, debugstr_an(buffer
, bytesToWrite
), bytesToWrite
,
1759 bytesWritten
, overlapped
);
1760 return WriteConsoleA(hFile
, buffer
, bytesToWrite
, bytesWritten
, NULL
);
1762 if (unix_handle
== -1)
1766 /* synchronous file write */
1767 while ((result
= write( unix_handle
, buffer
, bytesToWrite
)) == -1)
1769 if ((errno
== EAGAIN
) || (errno
== EINTR
)) continue;
1770 if ((errno
== EFAULT
) && !IsBadReadPtr( buffer
, bytesToWrite
)) continue;
1771 if (errno
== ENOSPC
)
1772 SetLastError( ERROR_DISK_FULL
);
1777 close( unix_handle
);
1778 if (result
== -1) return FALSE
;
1779 if (bytesWritten
) *bytesWritten
= result
;
1784 /***********************************************************************
1785 * _hread (KERNEL.349)
1787 LONG WINAPI
WIN16_hread( HFILE16 hFile
, SEGPTR buffer
, LONG count
)
1791 TRACE("%d %08lx %ld\n",
1792 hFile
, (DWORD
)buffer
, count
);
1794 /* Some programs pass a count larger than the allocated buffer */
1795 maxlen
= GetSelectorLimit16( SELECTOROF(buffer
) ) - OFFSETOF(buffer
) + 1;
1796 if (count
> maxlen
) count
= maxlen
;
1797 return _lread(DosFileHandleToWin32Handle(hFile
), MapSL(buffer
), count
);
1801 /***********************************************************************
1802 * _lread (KERNEL.82)
1804 UINT16 WINAPI
WIN16_lread( HFILE16 hFile
, SEGPTR buffer
, UINT16 count
)
1806 return (UINT16
)WIN16_hread( hFile
, buffer
, (LONG
)count
);
1810 /***********************************************************************
1811 * _lread (KERNEL32.@)
1813 UINT WINAPI
_lread( HFILE handle
, LPVOID buffer
, UINT count
)
1816 if (!ReadFile( handle
, buffer
, count
, &result
, NULL
)) return -1;
1821 /***********************************************************************
1822 * _lread16 (KERNEL.82)
1824 UINT16 WINAPI
_lread16( HFILE16 hFile
, LPVOID buffer
, UINT16 count
)
1826 return (UINT16
)_lread(DosFileHandleToWin32Handle(hFile
), buffer
, (LONG
)count
);
1830 /***********************************************************************
1831 * _lcreat (KERNEL.83)
1833 HFILE16 WINAPI
_lcreat16( LPCSTR path
, INT16 attr
)
1835 return Win32HandleToDosFileHandle( _lcreat( path
, attr
) );
1839 /***********************************************************************
1840 * _lcreat (KERNEL32.@)
1842 HFILE WINAPI
_lcreat( LPCSTR path
, INT attr
)
1844 /* Mask off all flags not explicitly allowed by the doc */
1845 attr
&= FILE_ATTRIBUTE_READONLY
| FILE_ATTRIBUTE_HIDDEN
| FILE_ATTRIBUTE_SYSTEM
;
1846 TRACE("%s %02x\n", path
, attr
);
1847 return CreateFileA( path
, GENERIC_READ
| GENERIC_WRITE
,
1848 FILE_SHARE_READ
| FILE_SHARE_WRITE
, NULL
,
1849 CREATE_ALWAYS
, attr
, 0 );
1853 /***********************************************************************
1854 * SetFilePointer (KERNEL32.@)
1856 DWORD WINAPI
SetFilePointer( HANDLE hFile
, LONG distance
, LONG
*highword
,
1859 DWORD ret
= 0xffffffff;
1861 TRACE("handle %d offset %ld high %ld origin %ld\n",
1862 hFile
, distance
, highword
?*highword
:0, method
);
1864 SERVER_START_REQ( set_file_pointer
)
1866 req
->handle
= hFile
;
1867 req
->low
= distance
;
1868 req
->high
= highword
? *highword
: (distance
>= 0) ? 0 : -1;
1869 /* FIXME: assumes 1:1 mapping between Windows and Unix seek constants */
1870 req
->whence
= method
;
1872 if (!wine_server_call_err( req
))
1874 ret
= reply
->new_low
;
1875 if (highword
) *highword
= reply
->new_high
;
1883 /***********************************************************************
1884 * _llseek (KERNEL.84)
1887 * Seeking before the start of the file should be allowed for _llseek16,
1888 * but cause subsequent I/O operations to fail (cf. interrupt list)
1891 LONG WINAPI
_llseek16( HFILE16 hFile
, LONG lOffset
, INT16 nOrigin
)
1893 return SetFilePointer( DosFileHandleToWin32Handle(hFile
), lOffset
, NULL
, nOrigin
);
1897 /***********************************************************************
1898 * _llseek (KERNEL32.@)
1900 LONG WINAPI
_llseek( HFILE hFile
, LONG lOffset
, INT nOrigin
)
1902 return SetFilePointer( hFile
, lOffset
, NULL
, nOrigin
);
1906 /***********************************************************************
1907 * _lopen (KERNEL.85)
1909 HFILE16 WINAPI
_lopen16( LPCSTR path
, INT16 mode
)
1911 return Win32HandleToDosFileHandle( _lopen( path
, mode
) );
1915 /***********************************************************************
1916 * _lopen (KERNEL32.@)
1918 HFILE WINAPI
_lopen( LPCSTR path
, INT mode
)
1920 DWORD access
, sharing
;
1922 TRACE("('%s',%04x)\n", path
, mode
);
1923 FILE_ConvertOFMode( mode
, &access
, &sharing
);
1924 return CreateFileA( path
, access
, sharing
, NULL
, OPEN_EXISTING
, 0, 0 );
1928 /***********************************************************************
1929 * _lwrite (KERNEL.86)
1931 UINT16 WINAPI
_lwrite16( HFILE16 hFile
, LPCSTR buffer
, UINT16 count
)
1933 return (UINT16
)_hwrite( DosFileHandleToWin32Handle(hFile
), buffer
, (LONG
)count
);
1936 /***********************************************************************
1937 * _lwrite (KERNEL32.@)
1939 UINT WINAPI
_lwrite( HFILE hFile
, LPCSTR buffer
, UINT count
)
1941 return (UINT
)_hwrite( hFile
, buffer
, (LONG
)count
);
1945 /***********************************************************************
1946 * _hread16 (KERNEL.349)
1948 LONG WINAPI
_hread16( HFILE16 hFile
, LPVOID buffer
, LONG count
)
1950 return _lread( DosFileHandleToWin32Handle(hFile
), buffer
, count
);
1954 /***********************************************************************
1955 * _hread (KERNEL32.@)
1957 LONG WINAPI
_hread( HFILE hFile
, LPVOID buffer
, LONG count
)
1959 return _lread( hFile
, buffer
, count
);
1963 /***********************************************************************
1964 * _hwrite (KERNEL.350)
1966 LONG WINAPI
_hwrite16( HFILE16 hFile
, LPCSTR buffer
, LONG count
)
1968 return _hwrite( DosFileHandleToWin32Handle(hFile
), buffer
, count
);
1972 /***********************************************************************
1973 * _hwrite (KERNEL32.@)
1975 * experimentation yields that _lwrite:
1976 * o truncates the file at the current position with
1978 * o returns 0 on a 0 length write
1979 * o works with console handles
1982 LONG WINAPI
_hwrite( HFILE handle
, LPCSTR buffer
, LONG count
)
1986 TRACE("%d %p %ld\n", handle
, buffer
, count
);
1990 /* Expand or truncate at current position */
1991 if (!SetEndOfFile( handle
)) return HFILE_ERROR
;
1994 if (!WriteFile( handle
, buffer
, count
, &result
, NULL
))
2000 /***********************************************************************
2001 * SetHandleCount (KERNEL.199)
2003 UINT16 WINAPI
SetHandleCount16( UINT16 count
)
2005 return SetHandleCount( count
);
2009 /*************************************************************************
2010 * SetHandleCount (KERNEL32.@)
2012 UINT WINAPI
SetHandleCount( UINT count
)
2014 return min( 256, count
);
2018 /***********************************************************************
2019 * FlushFileBuffers (KERNEL32.@)
2021 BOOL WINAPI
FlushFileBuffers( HANDLE hFile
)
2024 SERVER_START_REQ( flush_file
)
2026 req
->handle
= hFile
;
2027 ret
= !wine_server_call_err( req
);
2034 /**************************************************************************
2035 * SetEndOfFile (KERNEL32.@)
2037 BOOL WINAPI
SetEndOfFile( HANDLE hFile
)
2040 SERVER_START_REQ( truncate_file
)
2042 req
->handle
= hFile
;
2043 ret
= !wine_server_call_err( req
);
2050 /***********************************************************************
2051 * DeleteFile (KERNEL.146)
2053 BOOL16 WINAPI
DeleteFile16( LPCSTR path
)
2055 return DeleteFileA( path
);
2059 /***********************************************************************
2060 * DeleteFileA (KERNEL32.@)
2062 BOOL WINAPI
DeleteFileA( LPCSTR path
)
2064 DOS_FULL_NAME full_name
;
2068 SetLastError(ERROR_INVALID_PARAMETER
);
2071 TRACE("'%s'\n", path
);
2075 ERR("Empty path passed\n");
2078 if (DOSFS_GetDevice( path
))
2080 WARN("cannot remove DOS device '%s'!\n", path
);
2081 SetLastError( ERROR_FILE_NOT_FOUND
);
2085 if (!DOSFS_GetFullName( path
, TRUE
, &full_name
)) return FALSE
;
2086 if (unlink( full_name
.long_name
) == -1)
2095 /***********************************************************************
2096 * DeleteFileW (KERNEL32.@)
2098 BOOL WINAPI
DeleteFileW( LPCWSTR path
)
2100 LPSTR xpath
= HEAP_strdupWtoA( GetProcessHeap(), 0, path
);
2101 BOOL ret
= DeleteFileA( xpath
);
2102 HeapFree( GetProcessHeap(), 0, xpath
);
2107 /***********************************************************************
2108 * GetFileType (KERNEL32.@)
2110 DWORD WINAPI
GetFileType( HANDLE hFile
)
2112 DWORD ret
= FILE_TYPE_UNKNOWN
;
2113 SERVER_START_REQ( get_file_info
)
2115 req
->handle
= hFile
;
2116 if (!wine_server_call_err( req
)) ret
= reply
->type
;
2123 /* check if a file name is for an executable file (.exe or .com) */
2124 inline static BOOL
is_executable( const char *name
)
2126 int len
= strlen(name
);
2128 if (len
< 4) return FALSE
;
2129 return (!strcasecmp( name
+ len
- 4, ".exe" ) ||
2130 !strcasecmp( name
+ len
- 4, ".com" ));
2134 /***********************************************************************
2135 * FILE_AddBootRenameEntry
2137 * Adds an entry to the registry that is loaded when windows boots and
2138 * checks if there are some files to be removed or renamed/moved.
2139 * <fn1> has to be valid and <fn2> may be NULL. If both pointers are
2140 * non-NULL then the file is moved, otherwise it is deleted. The
2141 * entry of the registrykey is always appended with two zero
2142 * terminated strings. If <fn2> is NULL then the second entry is
2143 * simply a single 0-byte. Otherwise the second filename goes
2144 * there. The entries are prepended with \??\ before the path and the
2145 * second filename gets also a '!' as the first character if
2146 * MOVEFILE_REPLACE_EXISTING is set. After the final string another
2147 * 0-byte follows to indicate the end of the strings.
2149 * \??\D:\test\file1[0]
2150 * !\??\D:\test\file1_renamed[0]
2151 * \??\D:\Test|delete[0]
2152 * [0] <- file is to be deleted, second string empty
2153 * \??\D:\test\file2[0]
2154 * !\??\D:\test\file2_renamed[0]
2155 * [0] <- indicates end of strings
2158 * \??\D:\test\file1[0]
2159 * !\??\D:\test\file1_renamed[0]
2160 * \??\D:\Test|delete[0]
2161 * [0] <- file is to be deleted, second string empty
2162 * [0] <- indicates end of strings
2165 static BOOL
FILE_AddBootRenameEntry( const char *fn1
, const char *fn2
, DWORD flags
)
2167 static const char PreString
[] = "\\??\\";
2168 static const char ValueName
[] = "PendingFileRenameOperations";
2172 DWORD Type
, len1
, len2
, l
;
2174 BYTE
*Buffer
= NULL
;
2176 if(RegCreateKeyA(HKEY_LOCAL_MACHINE
, "SYSTEM\\CurrentControlSet\\Control\\Session Manager",
2177 &Reboot
) != ERROR_SUCCESS
)
2179 WARN("Error creating key for reboot managment [%s]\n",
2180 "SYSTEM\\CurrentControlSet\\Control\\Session Manager");
2184 l
= strlen(PreString
);
2185 len1
= strlen(fn1
) + l
+ 1;
2188 len2
= strlen(fn2
) + l
+ 1;
2189 if (flags
& MOVEFILE_REPLACE_EXISTING
) len2
++; /* Plus 1 because of the leading '!' */
2191 else len2
= 1; /* minimum is the 0 byte for the empty second string */
2193 /* First we check if the key exists and if so how many bytes it already contains. */
2194 if (RegQueryValueExA(Reboot
, ValueName
, NULL
, &Type
, NULL
, &DataSize
) == ERROR_SUCCESS
)
2196 if (Type
!= REG_MULTI_SZ
) goto Quit
;
2197 if (!(Buffer
= HeapAlloc( GetProcessHeap(), 0, DataSize
+ len1
+ len2
+ 1 ))) goto Quit
;
2198 if (RegQueryValueExA(Reboot
, ValueName
, NULL
, &Type
, Buffer
, &DataSize
) != ERROR_SUCCESS
)
2200 if (DataSize
) DataSize
--; /* remove terminating null (will be added back later) */
2204 if (!(Buffer
= HeapAlloc( GetProcessHeap(), 0, len1
+ len2
+ 1 ))) goto Quit
;
2207 sprintf( Buffer
+ DataSize
, "%s%s", PreString
, fn1
);
2211 sprintf( Buffer
+ DataSize
, "%s%s%s",
2212 (flags
& MOVEFILE_REPLACE_EXISTING
) ? "!" : "", PreString
, fn2
);
2215 else Buffer
[DataSize
++] = 0;
2217 Buffer
[DataSize
++] = 0; /* add final null */
2218 rc
= !RegSetValueExA( Reboot
, ValueName
, 0, REG_MULTI_SZ
, Buffer
, DataSize
);
2221 if (Reboot
) RegCloseKey(Reboot
);
2222 if (Buffer
) HeapFree( GetProcessHeap(), 0, Buffer
);
2227 /**************************************************************************
2228 * MoveFileExA (KERNEL32.@)
2230 BOOL WINAPI
MoveFileExA( LPCSTR fn1
, LPCSTR fn2
, DWORD flag
)
2232 DOS_FULL_NAME full_name1
, full_name2
;
2234 TRACE("(%s,%s,%04lx)\n", fn1
, fn2
, flag
);
2236 /* FIXME: <Gerhard W. Gruber>sparhawk@gmx.at
2237 In case of W9x and lesser this function should return 120 (ERROR_CALL_NOT_IMPLEMENTED)
2238 to be really compatible. Most programs wont have any problems though. In case
2239 you encounter one, this is what you should return here. I don't know what's up
2240 with NT 3.5. Is this function available there or not?
2241 Does anybody really care about 3.5? :)
2244 /* Filename1 has to be always set to a valid path. Filename2 may be NULL
2245 if the source file has to be deleted.
2248 SetLastError(ERROR_INVALID_PARAMETER
);
2252 /* This function has to be run through in order to process the name properly.
2253 If the BOOTDELAY flag is set, the file doesn't need to exist though. At least
2254 that is the behaviour on NT 4.0. The operation accepts the filenames as
2255 they are given but it can't reply with a reasonable returncode. Success
2256 means in that case success for entering the values into the registry.
2258 if(!DOSFS_GetFullName( fn1
, TRUE
, &full_name1
))
2260 if(!(flag
& MOVEFILE_DELAY_UNTIL_REBOOT
))
2264 if (fn2
) /* !fn2 means delete fn1 */
2266 if (DOSFS_GetFullName( fn2
, TRUE
, &full_name2
))
2268 if(!(flag
& MOVEFILE_DELAY_UNTIL_REBOOT
))
2270 /* target exists, check if we may overwrite */
2271 if (!(flag
& MOVEFILE_REPLACE_EXISTING
))
2273 /* FIXME: Use right error code */
2274 SetLastError( ERROR_ACCESS_DENIED
);
2281 if (!DOSFS_GetFullName( fn2
, FALSE
, &full_name2
))
2283 if(!(flag
& MOVEFILE_DELAY_UNTIL_REBOOT
))
2288 /* Source name and target path are valid */
2290 if (flag
& MOVEFILE_DELAY_UNTIL_REBOOT
)
2292 /* FIXME: (bon@elektron.ikp.physik.th-darmstadt.de 970706)
2293 Perhaps we should queue these command and execute it
2294 when exiting... What about using on_exit(2)
2296 FIXME("Please move existing file '%s' to file '%s' when Wine has finished\n",
2298 return FILE_AddBootRenameEntry( fn1
, fn2
, flag
);
2301 if (full_name1
.drive
!= full_name2
.drive
)
2303 /* use copy, if allowed */
2304 if (!(flag
& MOVEFILE_COPY_ALLOWED
))
2306 /* FIXME: Use right error code */
2307 SetLastError( ERROR_FILE_EXISTS
);
2310 return CopyFileA( fn1
, fn2
, !(flag
& MOVEFILE_REPLACE_EXISTING
) );
2312 if (rename( full_name1
.long_name
, full_name2
.long_name
) == -1)
2317 if (is_executable( full_name1
.long_name
) != is_executable( full_name2
.long_name
))
2320 if (stat( full_name2
.long_name
, &fstat
) != -1)
2322 if (is_executable( full_name2
.long_name
))
2323 /* set executable bit where read bit is set */
2324 fstat
.st_mode
|= (fstat
.st_mode
& 0444) >> 2;
2326 fstat
.st_mode
&= ~0111;
2327 chmod( full_name2
.long_name
, fstat
.st_mode
);
2332 else /* fn2 == NULL means delete source */
2334 if (flag
& MOVEFILE_DELAY_UNTIL_REBOOT
)
2336 if (flag
& MOVEFILE_COPY_ALLOWED
) {
2337 WARN("Illegal flag\n");
2338 SetLastError( ERROR_GEN_FAILURE
);
2341 /* FIXME: (bon@elektron.ikp.physik.th-darmstadt.de 970706)
2342 Perhaps we should queue these command and execute it
2343 when exiting... What about using on_exit(2)
2345 FIXME("Please delete file '%s' when Wine has finished\n", fn1
);
2346 return FILE_AddBootRenameEntry( fn1
, NULL
, flag
);
2349 if (unlink( full_name1
.long_name
) == -1)
2354 return TRUE
; /* successfully deleted */
2358 /**************************************************************************
2359 * MoveFileExW (KERNEL32.@)
2361 BOOL WINAPI
MoveFileExW( LPCWSTR fn1
, LPCWSTR fn2
, DWORD flag
)
2363 LPSTR afn1
= HEAP_strdupWtoA( GetProcessHeap(), 0, fn1
);
2364 LPSTR afn2
= HEAP_strdupWtoA( GetProcessHeap(), 0, fn2
);
2365 BOOL res
= MoveFileExA( afn1
, afn2
, flag
);
2366 HeapFree( GetProcessHeap(), 0, afn1
);
2367 HeapFree( GetProcessHeap(), 0, afn2
);
2372 /**************************************************************************
2373 * MoveFileA (KERNEL32.@)
2375 * Move file or directory
2377 BOOL WINAPI
MoveFileA( LPCSTR fn1
, LPCSTR fn2
)
2379 DOS_FULL_NAME full_name1
, full_name2
;
2382 TRACE("(%s,%s)\n", fn1
, fn2
);
2384 if (!DOSFS_GetFullName( fn1
, TRUE
, &full_name1
)) return FALSE
;
2385 if (DOSFS_GetFullName( fn2
, TRUE
, &full_name2
)) {
2386 /* The new name must not already exist */
2387 SetLastError(ERROR_ALREADY_EXISTS
);
2390 if (!DOSFS_GetFullName( fn2
, FALSE
, &full_name2
)) return FALSE
;
2392 if (full_name1
.drive
== full_name2
.drive
) /* move */
2393 return MoveFileExA( fn1
, fn2
, MOVEFILE_COPY_ALLOWED
);
2396 if (stat( full_name1
.long_name
, &fstat
))
2398 WARN("Invalid source file %s\n",
2399 full_name1
.long_name
);
2403 if (S_ISDIR(fstat
.st_mode
)) {
2404 /* No Move for directories across file systems */
2405 /* FIXME: Use right error code */
2406 SetLastError( ERROR_GEN_FAILURE
);
2409 return CopyFileA(fn1
, fn2
, TRUE
); /*fail, if exist */
2413 /**************************************************************************
2414 * MoveFileW (KERNEL32.@)
2416 BOOL WINAPI
MoveFileW( LPCWSTR fn1
, LPCWSTR fn2
)
2418 LPSTR afn1
= HEAP_strdupWtoA( GetProcessHeap(), 0, fn1
);
2419 LPSTR afn2
= HEAP_strdupWtoA( GetProcessHeap(), 0, fn2
);
2420 BOOL res
= MoveFileA( afn1
, afn2
);
2421 HeapFree( GetProcessHeap(), 0, afn1
);
2422 HeapFree( GetProcessHeap(), 0, afn2
);
2427 /**************************************************************************
2428 * CopyFileA (KERNEL32.@)
2430 BOOL WINAPI
CopyFileA( LPCSTR source
, LPCSTR dest
, BOOL fail_if_exists
)
2433 BY_HANDLE_FILE_INFORMATION info
;
2439 if ((h1
= _lopen( source
, OF_READ
)) == HFILE_ERROR
) return FALSE
;
2440 if (!GetFileInformationByHandle( h1
, &info
))
2445 mode
= (info
.dwFileAttributes
& FILE_ATTRIBUTE_READONLY
) ? 0444 : 0666;
2446 if ((h2
= CreateFileA( dest
, GENERIC_WRITE
, FILE_SHARE_READ
| FILE_SHARE_WRITE
, NULL
,
2447 fail_if_exists
? CREATE_NEW
: CREATE_ALWAYS
,
2448 info
.dwFileAttributes
, h1
)) == INVALID_HANDLE_VALUE
)
2453 while ((count
= _lread( h1
, buffer
, sizeof(buffer
) )) > 0)
2458 INT res
= _lwrite( h2
, p
, count
);
2459 if (res
<= 0) goto done
;
2472 /**************************************************************************
2473 * CopyFileW (KERNEL32.@)
2475 BOOL WINAPI
CopyFileW( LPCWSTR source
, LPCWSTR dest
, BOOL fail_if_exists
)
2477 LPSTR sourceA
= HEAP_strdupWtoA( GetProcessHeap(), 0, source
);
2478 LPSTR destA
= HEAP_strdupWtoA( GetProcessHeap(), 0, dest
);
2479 BOOL ret
= CopyFileA( sourceA
, destA
, fail_if_exists
);
2480 HeapFree( GetProcessHeap(), 0, sourceA
);
2481 HeapFree( GetProcessHeap(), 0, destA
);
2486 /**************************************************************************
2487 * CopyFileExA (KERNEL32.@)
2489 * This implementation ignores most of the extra parameters passed-in into
2490 * the "ex" version of the method and calls the CopyFile method.
2491 * It will have to be fixed eventually.
2493 BOOL WINAPI
CopyFileExA(LPCSTR sourceFilename
,
2494 LPCSTR destFilename
,
2495 LPPROGRESS_ROUTINE progressRoutine
,
2497 LPBOOL cancelFlagPointer
,
2500 BOOL failIfExists
= FALSE
;
2503 * Interpret the only flag that CopyFile can interpret.
2505 if ( (copyFlags
& COPY_FILE_FAIL_IF_EXISTS
) != 0)
2507 failIfExists
= TRUE
;
2510 return CopyFileA(sourceFilename
, destFilename
, failIfExists
);
2513 /**************************************************************************
2514 * CopyFileExW (KERNEL32.@)
2516 BOOL WINAPI
CopyFileExW(LPCWSTR sourceFilename
,
2517 LPCWSTR destFilename
,
2518 LPPROGRESS_ROUTINE progressRoutine
,
2520 LPBOOL cancelFlagPointer
,
2523 LPSTR sourceA
= HEAP_strdupWtoA( GetProcessHeap(), 0, sourceFilename
);
2524 LPSTR destA
= HEAP_strdupWtoA( GetProcessHeap(), 0, destFilename
);
2526 BOOL ret
= CopyFileExA(sourceA
,
2533 HeapFree( GetProcessHeap(), 0, sourceA
);
2534 HeapFree( GetProcessHeap(), 0, destA
);
2540 /***********************************************************************
2541 * SetFileTime (KERNEL32.@)
2543 BOOL WINAPI
SetFileTime( HANDLE hFile
,
2544 const FILETIME
*lpCreationTime
,
2545 const FILETIME
*lpLastAccessTime
,
2546 const FILETIME
*lpLastWriteTime
)
2549 SERVER_START_REQ( set_file_time
)
2551 req
->handle
= hFile
;
2552 if (lpLastAccessTime
)
2553 RtlTimeToSecondsSince1970( lpLastAccessTime
, (DWORD
*)&req
->access_time
);
2555 req
->access_time
= 0; /* FIXME */
2556 if (lpLastWriteTime
)
2557 RtlTimeToSecondsSince1970( lpLastWriteTime
, (DWORD
*)&req
->write_time
);
2559 req
->write_time
= 0; /* FIXME */
2560 ret
= !wine_server_call_err( req
);
2567 /**************************************************************************
2568 * LockFile (KERNEL32.@)
2570 BOOL WINAPI
LockFile( HANDLE hFile
, DWORD dwFileOffsetLow
, DWORD dwFileOffsetHigh
,
2571 DWORD nNumberOfBytesToLockLow
, DWORD nNumberOfBytesToLockHigh
)
2574 SERVER_START_REQ( lock_file
)
2576 req
->handle
= hFile
;
2577 req
->offset_low
= dwFileOffsetLow
;
2578 req
->offset_high
= dwFileOffsetHigh
;
2579 req
->count_low
= nNumberOfBytesToLockLow
;
2580 req
->count_high
= nNumberOfBytesToLockHigh
;
2581 ret
= !wine_server_call_err( req
);
2587 /**************************************************************************
2588 * LockFileEx [KERNEL32.@]
2590 * Locks a byte range within an open file for shared or exclusive access.
2597 * Per Microsoft docs, the third parameter (reserved) must be set to 0.
2599 BOOL WINAPI
LockFileEx( HANDLE hFile
, DWORD flags
, DWORD reserved
,
2600 DWORD nNumberOfBytesToLockLow
, DWORD nNumberOfBytesToLockHigh
,
2601 LPOVERLAPPED pOverlapped
)
2603 FIXME("hFile=%d,flags=%ld,reserved=%ld,lowbytes=%ld,highbytes=%ld,overlapped=%p: stub.\n",
2604 hFile
, flags
, reserved
, nNumberOfBytesToLockLow
, nNumberOfBytesToLockHigh
,
2607 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
2610 ERR("reserved == %ld: Supposed to be 0??\n", reserved
);
2611 SetLastError(ERROR_INVALID_PARAMETER
);
2618 /**************************************************************************
2619 * UnlockFile (KERNEL32.@)
2621 BOOL WINAPI
UnlockFile( HANDLE hFile
, DWORD dwFileOffsetLow
, DWORD dwFileOffsetHigh
,
2622 DWORD nNumberOfBytesToUnlockLow
, DWORD nNumberOfBytesToUnlockHigh
)
2625 SERVER_START_REQ( unlock_file
)
2627 req
->handle
= hFile
;
2628 req
->offset_low
= dwFileOffsetLow
;
2629 req
->offset_high
= dwFileOffsetHigh
;
2630 req
->count_low
= nNumberOfBytesToUnlockLow
;
2631 req
->count_high
= nNumberOfBytesToUnlockHigh
;
2632 ret
= !wine_server_call_err( req
);
2639 /**************************************************************************
2640 * UnlockFileEx (KERNEL32.@)
2642 BOOL WINAPI
UnlockFileEx(
2645 DWORD nNumberOfBytesToUnlockLow
,
2646 DWORD nNumberOfBytesToUnlockHigh
,
2647 LPOVERLAPPED lpOverlapped
2650 FIXME("hFile=%d,reserved=%ld,lowbytes=%ld,highbytes=%ld,overlapped=%p: stub.\n",
2651 hFile
, dwReserved
, nNumberOfBytesToUnlockLow
, nNumberOfBytesToUnlockHigh
,
2653 if (dwReserved
== 0)
2654 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
2657 ERR("reserved == %ld: Supposed to be 0??\n", dwReserved
);
2658 SetLastError(ERROR_INVALID_PARAMETER
);
2667 struct DOS_FILE_LOCK
{
2668 struct DOS_FILE_LOCK
* next
;
2672 FILE_OBJECT
* dos_file
;
2673 /* char * unix_name;*/
2676 typedef struct DOS_FILE_LOCK DOS_FILE_LOCK
;
2678 static DOS_FILE_LOCK
*locks
= NULL
;
2679 static void DOS_RemoveFileLocks(FILE_OBJECT
*file
);
2682 /* Locks need to be mirrored because unix file locking is based
2683 * on the pid. Inside of wine there can be multiple WINE processes
2684 * that share the same unix pid.
2685 * Read's and writes should check these locks also - not sure
2686 * how critical that is at this point (FIXME).
2689 static BOOL
DOS_AddLock(FILE_OBJECT
*file
, struct flock
*f
)
2691 DOS_FILE_LOCK
*curr
;
2694 processId
= GetCurrentProcessId();
2696 /* check if lock overlaps a current lock for the same file */
2698 for (curr
= locks
; curr
; curr
= curr
->next
) {
2699 if (strcmp(curr
->unix_name
, file
->unix_name
) == 0) {
2700 if ((f
->l_start
== curr
->base
) && (f
->l_len
== curr
->len
))
2701 return TRUE
;/* region is identic */
2702 if ((f
->l_start
< (curr
->base
+ curr
->len
)) &&
2703 ((f
->l_start
+ f
->l_len
) > curr
->base
)) {
2704 /* region overlaps */
2711 curr
= HeapAlloc( GetProcessHeap(), 0, sizeof(DOS_FILE_LOCK
) );
2712 curr
->processId
= GetCurrentProcessId();
2713 curr
->base
= f
->l_start
;
2714 curr
->len
= f
->l_len
;
2715 /* curr->unix_name = HEAP_strdupA( GetProcessHeap(), 0, file->unix_name);*/
2717 curr
->dos_file
= file
;
2722 static void DOS_RemoveFileLocks(FILE_OBJECT
*file
)
2725 DOS_FILE_LOCK
**curr
;
2728 processId
= GetCurrentProcessId();
2731 if ((*curr
)->dos_file
== file
) {
2733 *curr
= (*curr
)->next
;
2734 /* HeapFree( GetProcessHeap(), 0, rem->unix_name );*/
2735 HeapFree( GetProcessHeap(), 0, rem
);
2738 curr
= &(*curr
)->next
;
2742 static BOOL
DOS_RemoveLock(FILE_OBJECT
*file
, struct flock
*f
)
2745 DOS_FILE_LOCK
**curr
;
2748 processId
= GetCurrentProcessId();
2749 for (curr
= &locks
; *curr
; curr
= &(*curr
)->next
) {
2750 if ((*curr
)->processId
== processId
&&
2751 (*curr
)->dos_file
== file
&&
2752 (*curr
)->base
== f
->l_start
&&
2753 (*curr
)->len
== f
->l_len
) {
2754 /* this is the same lock */
2756 *curr
= (*curr
)->next
;
2757 /* HeapFree( GetProcessHeap(), 0, rem->unix_name );*/
2758 HeapFree( GetProcessHeap(), 0, rem
);
2762 /* no matching lock found */
2767 /**************************************************************************
2768 * LockFile (KERNEL32.@)
2770 BOOL WINAPI
LockFile(
2771 HFILE hFile
,DWORD dwFileOffsetLow
,DWORD dwFileOffsetHigh
,
2772 DWORD nNumberOfBytesToLockLow
,DWORD nNumberOfBytesToLockHigh
)
2777 TRACE("handle %d offsetlow=%ld offsethigh=%ld nbyteslow=%ld nbyteshigh=%ld\n",
2778 hFile
, dwFileOffsetLow
, dwFileOffsetHigh
,
2779 nNumberOfBytesToLockLow
, nNumberOfBytesToLockHigh
);
2781 if (dwFileOffsetHigh
|| nNumberOfBytesToLockHigh
) {
2782 FIXME("Unimplemented bytes > 32bits\n");
2786 f
.l_start
= dwFileOffsetLow
;
2787 f
.l_len
= nNumberOfBytesToLockLow
;
2788 f
.l_whence
= SEEK_SET
;
2792 if (!(file
= FILE_GetFile(hFile
,0,NULL
))) return FALSE
;
2794 /* shadow locks internally */
2795 if (!DOS_AddLock(file
, &f
)) {
2796 SetLastError( ERROR_LOCK_VIOLATION
);
2800 /* FIXME: Unix locking commented out for now, doesn't work with Excel */
2801 #ifdef USE_UNIX_LOCKS
2802 if (fcntl(file
->unix_handle
, F_SETLK
, &f
) == -1) {
2803 if (errno
== EACCES
|| errno
== EAGAIN
) {
2804 SetLastError( ERROR_LOCK_VIOLATION
);
2809 /* remove our internal copy of the lock */
2810 DOS_RemoveLock(file
, &f
);
2818 /**************************************************************************
2819 * UnlockFile (KERNEL32.@)
2821 BOOL WINAPI
UnlockFile(
2822 HFILE hFile
,DWORD dwFileOffsetLow
,DWORD dwFileOffsetHigh
,
2823 DWORD nNumberOfBytesToUnlockLow
,DWORD nNumberOfBytesToUnlockHigh
)
2828 TRACE("handle %d offsetlow=%ld offsethigh=%ld nbyteslow=%ld nbyteshigh=%ld\n",
2829 hFile
, dwFileOffsetLow
, dwFileOffsetHigh
,
2830 nNumberOfBytesToUnlockLow
, nNumberOfBytesToUnlockHigh
);
2832 if (dwFileOffsetHigh
|| nNumberOfBytesToUnlockHigh
) {
2833 WARN("Unimplemented bytes > 32bits\n");
2837 f
.l_start
= dwFileOffsetLow
;
2838 f
.l_len
= nNumberOfBytesToUnlockLow
;
2839 f
.l_whence
= SEEK_SET
;
2843 if (!(file
= FILE_GetFile(hFile
,0,NULL
))) return FALSE
;
2845 DOS_RemoveLock(file
, &f
); /* ok if fails - may be another wine */
2847 /* FIXME: Unix locking commented out for now, doesn't work with Excel */
2848 #ifdef USE_UNIX_LOCKS
2849 if (fcntl(file
->unix_handle
, F_SETLK
, &f
) == -1) {
2858 /**************************************************************************
2859 * GetFileAttributesExA [KERNEL32.@]
2861 BOOL WINAPI
GetFileAttributesExA(
2862 LPCSTR lpFileName
, GET_FILEEX_INFO_LEVELS fInfoLevelId
,
2863 LPVOID lpFileInformation
)
2865 DOS_FULL_NAME full_name
;
2866 BY_HANDLE_FILE_INFORMATION info
;
2868 if (lpFileName
== NULL
) return FALSE
;
2869 if (lpFileInformation
== NULL
) return FALSE
;
2871 if (fInfoLevelId
== GetFileExInfoStandard
) {
2872 LPWIN32_FILE_ATTRIBUTE_DATA lpFad
=
2873 (LPWIN32_FILE_ATTRIBUTE_DATA
) lpFileInformation
;
2874 if (!DOSFS_GetFullName( lpFileName
, TRUE
, &full_name
)) return FALSE
;
2875 if (!FILE_Stat( full_name
.long_name
, &info
)) return FALSE
;
2877 lpFad
->dwFileAttributes
= info
.dwFileAttributes
;
2878 lpFad
->ftCreationTime
= info
.ftCreationTime
;
2879 lpFad
->ftLastAccessTime
= info
.ftLastAccessTime
;
2880 lpFad
->ftLastWriteTime
= info
.ftLastWriteTime
;
2881 lpFad
->nFileSizeHigh
= info
.nFileSizeHigh
;
2882 lpFad
->nFileSizeLow
= info
.nFileSizeLow
;
2885 FIXME("invalid info level %d!\n", fInfoLevelId
);
2893 /**************************************************************************
2894 * GetFileAttributesExW [KERNEL32.@]
2896 BOOL WINAPI
GetFileAttributesExW(
2897 LPCWSTR lpFileName
, GET_FILEEX_INFO_LEVELS fInfoLevelId
,
2898 LPVOID lpFileInformation
)
2900 LPSTR nameA
= HEAP_strdupWtoA( GetProcessHeap(), 0, lpFileName
);
2902 GetFileAttributesExA( nameA
, fInfoLevelId
, lpFileInformation
);
2903 HeapFree( GetProcessHeap(), 0, nameA
);