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"
61 #include "wine/debug.h"
63 #include "wine/server.h"
65 WINE_DEFAULT_DEBUG_CHANNEL(file);
67 #if defined(MAP_ANONYMOUS) && !defined(MAP_ANON)
68 #define MAP_ANON MAP_ANONYMOUS
71 /* Size of per-process table of DOS handles */
72 #define DOS_TABLE_SIZE 256
74 /* Macro to derive file offset from OVERLAPPED struct */
75 #define OVERLAPPED_OFFSET(overlapped) ((off_t) (overlapped)->Offset + ((off_t) (overlapped)->OffsetHigh << 32))
77 static HANDLE dos_handles[DOS_TABLE_SIZE];
79 extern WINAPI HANDLE FILE_SmbOpen(LPCSTR name);
81 /***********************************************************************
84 * Convert OF_* mode into flags for CreateFile.
86 static void FILE_ConvertOFMode( INT mode, DWORD *access, DWORD *sharing )
90 case OF_READ: *access = GENERIC_READ; break;
91 case OF_WRITE: *access = GENERIC_WRITE; break;
92 case OF_READWRITE: *access = GENERIC_READ | GENERIC_WRITE; break;
93 default: *access = 0; break;
97 case OF_SHARE_EXCLUSIVE: *sharing = 0; break;
98 case OF_SHARE_DENY_WRITE: *sharing = FILE_SHARE_READ; break;
99 case OF_SHARE_DENY_READ: *sharing = FILE_SHARE_WRITE; break;
100 case OF_SHARE_DENY_NONE:
101 case OF_SHARE_COMPAT:
102 default: *sharing = FILE_SHARE_READ | FILE_SHARE_WRITE; break;
107 /***********************************************************************
110 * locale-independent case conversion for file I/O
112 int FILE_strcasecmp( const char *str1, const char *str2 )
116 int ret = FILE_toupper(*str1) - FILE_toupper(*str2);
117 if (ret || !*str1) return ret;
124 /***********************************************************************
127 * locale-independent case conversion for file I/O
129 int FILE_strncasecmp( const char *str1, const char *str2, int len )
132 for ( ; len > 0; len--, str1++, str2++)
133 if ((ret = FILE_toupper(*str1) - FILE_toupper(*str2)) || !*str1) break;
138 /***********************************************************************
141 * Set the DOS error code from errno.
143 void FILE_SetDosError(void)
145 int save_errno = errno; /* errno gets overwritten by printf */
147 TRACE("errno = %d %s\n", errno, strerror(errno));
151 SetLastError( ERROR_SHARING_VIOLATION );
154 SetLastError( ERROR_INVALID_HANDLE );
157 SetLastError( ERROR_HANDLE_DISK_FULL );
162 SetLastError( ERROR_ACCESS_DENIED );
165 SetLastError( ERROR_LOCK_VIOLATION );
168 SetLastError( ERROR_FILE_NOT_FOUND );
171 SetLastError( ERROR_CANNOT_MAKE );
175 SetLastError( ERROR_NO_MORE_FILES );
178 SetLastError( ERROR_FILE_EXISTS );
182 SetLastError( ERROR_SEEK );
185 SetLastError( ERROR_DIR_NOT_EMPTY );
188 SetLastError( ERROR_BAD_FORMAT );
191 WARN("unknown file error: %s\n", strerror(save_errno) );
192 SetLastError( ERROR_GEN_FAILURE );
199 /***********************************************************************
202 * Duplicate a Unix handle into a task handle.
203 * Returns 0 on failure.
205 HANDLE FILE_DupUnixHandle( int fd, DWORD access, BOOL inherit )
209 wine_server_send_fd( fd );
211 SERVER_START_REQ( alloc_file_handle )
213 req->access = access;
214 req->inherit = inherit;
216 wine_server_call( req );
224 /***********************************************************************
225 * FILE_GetUnixHandleType
227 * Retrieve the Unix handle corresponding to a file handle.
228 * Returns -1 on failure.
230 static int FILE_GetUnixHandleType( HANDLE handle, DWORD access, enum fd_type *type, DWORD *flags )
236 SERVER_START_REQ( get_handle_fd )
238 req->handle = handle;
239 req->access = access;
240 if (!(ret = wine_server_call_err( req )))
244 if (type) *type = reply->type;
245 if (flags) *flags = reply->flags;
250 if (fd == -1) /* it wasn't in the cache, get it from the server */
251 fd = wine_server_recv_fd( handle );
253 } while (fd == -2); /* -2 means race condition, so restart from scratch */
257 if ((fd = dup(fd)) == -1)
258 SetLastError( ERROR_TOO_MANY_OPEN_FILES );
263 /***********************************************************************
266 * Retrieve the Unix handle corresponding to a file handle.
267 * Returns -1 on failure.
269 int FILE_GetUnixHandle( HANDLE handle, DWORD access )
271 return FILE_GetUnixHandleType( handle, access, NULL, NULL );
274 /*************************************************************************
277 * Open a handle to the current process console.
278 * Returns 0 on failure.
280 static HANDLE FILE_OpenConsole( BOOL output, DWORD access, DWORD sharing, LPSECURITY_ATTRIBUTES sa )
284 SERVER_START_REQ( open_console )
287 req->access = access;
288 req->share = sharing;
289 req->inherit = (sa && (sa->nLength>=sizeof(*sa)) && sa->bInheritHandle);
291 wine_server_call_err( req );
299 /***********************************************************************
302 * Implementation of CreateFile. Takes a Unix path name.
303 * Returns 0 on failure.
305 HANDLE FILE_CreateFile( LPCSTR filename, DWORD access, DWORD sharing,
306 LPSECURITY_ATTRIBUTES sa, DWORD creation,
307 DWORD attributes, HANDLE template, BOOL fail_read_only,
315 SERVER_START_REQ( create_file )
317 req->access = access;
318 req->inherit = (sa && (sa->nLength>=sizeof(*sa)) && sa->bInheritHandle);
319 req->sharing = sharing;
320 req->create = creation;
321 req->attrs = attributes;
322 req->drive_type = drive_type;
323 wine_server_add_data( req, filename, strlen(filename) );
325 err = wine_server_call( req );
330 /* If write access failed, retry without GENERIC_WRITE */
332 if (!ret && !fail_read_only && (access & GENERIC_WRITE))
334 if ((err == STATUS_MEDIA_WRITE_PROTECTED) || (err == STATUS_ACCESS_DENIED))
336 TRACE("Write access failed for file '%s', trying without "
337 "write access\n", filename);
338 access &= ~GENERIC_WRITE;
343 if (err) SetLastError( RtlNtStatusToDosError(err) );
345 if (!ret) WARN("Unable to create file '%s' (GLE %ld)\n", filename, GetLastError());
351 /***********************************************************************
354 * Same as FILE_CreateFile but for a device
355 * Returns 0 on failure.
357 HANDLE FILE_CreateDevice( int client_id, DWORD access, LPSECURITY_ATTRIBUTES sa )
360 SERVER_START_REQ( create_device )
362 req->access = access;
363 req->inherit = (sa && (sa->nLength>=sizeof(*sa)) && sa->bInheritHandle);
366 wine_server_call_err( req );
373 static HANDLE FILE_OpenPipe(LPCSTR name, DWORD access)
375 WCHAR buffer[MAX_PATH];
379 if (name && !(len = MultiByteToWideChar( CP_ACP, 0, name, strlen(name), buffer, MAX_PATH )))
381 SetLastError( ERROR_FILENAME_EXCED_RANGE );
384 SERVER_START_REQ( open_named_pipe )
386 req->access = access;
388 wine_server_add_data( req, buffer, len * sizeof(WCHAR) );
389 wine_server_call_err( req );
393 TRACE("Returned %d\n",ret);
397 /*************************************************************************
398 * CreateFileA [KERNEL32.@] Creates or opens a file or other object
400 * Creates or opens an object, and returns a handle that can be used to
401 * access that object.
405 * filename [in] pointer to filename to be accessed
406 * access [in] access mode requested
407 * sharing [in] share mode
408 * sa [in] pointer to security attributes
409 * creation [in] how to create the file
410 * attributes [in] attributes for newly created file
411 * template [in] handle to file with extended attributes to copy
414 * Success: Open handle to specified file
415 * Failure: INVALID_HANDLE_VALUE
418 * Should call SetLastError() on failure.
422 * Doesn't support character devices, template files, or a
423 * lot of the 'attributes' flags yet.
425 HANDLE WINAPI CreateFileA( LPCSTR filename, DWORD access, DWORD sharing,
426 LPSECURITY_ATTRIBUTES sa, DWORD creation,
427 DWORD attributes, HANDLE template )
429 DOS_FULL_NAME full_name;
434 SetLastError( ERROR_INVALID_PARAMETER );
435 return INVALID_HANDLE_VALUE;
437 TRACE("%s %s%s%s%s%s%s%s\n",filename,
438 ((access & GENERIC_READ)==GENERIC_READ)?"GENERIC_READ ":"",
439 ((access & GENERIC_WRITE)==GENERIC_WRITE)?"GENERIC_WRITE ":"",
440 (!access)?"QUERY_ACCESS ":"",
441 ((sharing & FILE_SHARE_READ)==FILE_SHARE_READ)?"FILE_SHARE_READ ":"",
442 ((sharing & FILE_SHARE_WRITE)==FILE_SHARE_WRITE)?"FILE_SHARE_WRITE ":"",
443 ((sharing & FILE_SHARE_DELETE)==FILE_SHARE_DELETE)?"FILE_SHARE_DELETE ":"",
444 (creation ==CREATE_NEW)?"CREATE_NEW":
445 (creation ==CREATE_ALWAYS)?"CREATE_ALWAYS ":
446 (creation ==OPEN_EXISTING)?"OPEN_EXISTING ":
447 (creation ==OPEN_ALWAYS)?"OPEN_ALWAYS ":
448 (creation ==TRUNCATE_EXISTING)?"TRUNCATE_EXISTING ":"");
450 /* If the name starts with '\\?\', ignore the first 4 chars. */
451 if (!strncmp(filename, "\\\\?\\", 4))
454 if (!strncmp(filename, "UNC\\", 4))
456 FIXME("UNC name (%s) not supported.\n", filename );
457 SetLastError( ERROR_PATH_NOT_FOUND );
458 return INVALID_HANDLE_VALUE;
462 if (!strncmp(filename, "\\\\.\\", 4)) {
463 if(!strncasecmp(&filename[4],"pipe\\",5))
465 TRACE("Opening a pipe: %s\n",filename);
466 ret = FILE_OpenPipe(filename,access);
469 else if (isalpha(filename[4]) && filename[5] == ':' && filename[6] == '\0')
471 ret = FILE_CreateDevice( (toupper(filename[4]) - 'A') | 0x20000, access, sa );
474 else if (!DOSFS_GetDevice( filename ))
476 ret = DEVICE_Open( filename+4, access, sa );
480 filename+=4; /* fall into DOSFS_Device case below */
483 /* If the name still starts with '\\', it's a UNC name. */
484 if (!strncmp(filename, "\\\\", 2))
486 ret = SMB_CreateFileA(filename, access, sharing, sa, creation, attributes, template );
490 /* If the name contains a DOS wild card (* or ?), do no create a file */
491 if(strchr(filename,'*') || strchr(filename,'?'))
492 return INVALID_HANDLE_VALUE;
494 /* Open a console for CONIN$ or CONOUT$ */
495 if (!strcasecmp(filename, "CONIN$"))
497 ret = FILE_OpenConsole( FALSE, access, sharing, sa );
500 if (!strcasecmp(filename, "CONOUT$"))
502 ret = FILE_OpenConsole( TRUE, access, sharing, sa );
506 if (DOSFS_GetDevice( filename ))
508 TRACE("opening device '%s'\n", filename );
510 if (!(ret = DOSFS_OpenDevice( filename, access, attributes, sa )))
512 /* Do not silence this please. It is a critical error. -MM */
513 ERR("Couldn't open device '%s'!\n",filename);
514 SetLastError( ERROR_FILE_NOT_FOUND );
519 /* check for filename, don't check for last entry if creating */
520 if (!DOSFS_GetFullName( filename,
521 (creation == OPEN_EXISTING) ||
522 (creation == TRUNCATE_EXISTING),
524 WARN("Unable to get full filename from '%s' (GLE %ld)\n",
525 filename, GetLastError());
526 return INVALID_HANDLE_VALUE;
529 ret = FILE_CreateFile( full_name.long_name, access, sharing,
530 sa, creation, attributes, template,
531 DRIVE_GetFlags(full_name.drive) & DRIVE_FAIL_READ_ONLY,
532 GetDriveTypeA( full_name.short_name ) );
534 if (!ret) ret = INVALID_HANDLE_VALUE;
540 /*************************************************************************
541 * CreateFileW (KERNEL32.@)
543 HANDLE WINAPI CreateFileW( LPCWSTR filename, DWORD access, DWORD sharing,
544 LPSECURITY_ATTRIBUTES sa, DWORD creation,
545 DWORD attributes, HANDLE template)
547 LPSTR afn = HEAP_strdupWtoA( GetProcessHeap(), 0, filename );
548 HANDLE res = CreateFileA( afn, access, sharing, sa, creation, attributes, template );
549 HeapFree( GetProcessHeap(), 0, afn );
554 /***********************************************************************
557 * Fill a file information from a struct stat.
559 static void FILE_FillInfo( struct stat *st, BY_HANDLE_FILE_INFORMATION *info )
561 if (S_ISDIR(st->st_mode))
562 info->dwFileAttributes = FILE_ATTRIBUTE_DIRECTORY;
564 info->dwFileAttributes = FILE_ATTRIBUTE_ARCHIVE;
565 if (!(st->st_mode & S_IWUSR))
566 info->dwFileAttributes |= FILE_ATTRIBUTE_READONLY;
568 RtlSecondsSince1970ToTime( st->st_mtime, &info->ftCreationTime );
569 RtlSecondsSince1970ToTime( st->st_mtime, &info->ftLastWriteTime );
570 RtlSecondsSince1970ToTime( st->st_atime, &info->ftLastAccessTime );
572 info->dwVolumeSerialNumber = 0; /* FIXME */
573 info->nFileSizeHigh = 0;
574 info->nFileSizeLow = 0;
575 if (!S_ISDIR(st->st_mode)) {
576 info->nFileSizeHigh = st->st_size >> 32;
577 info->nFileSizeLow = st->st_size & 0xffffffff;
579 info->nNumberOfLinks = st->st_nlink;
580 info->nFileIndexHigh = 0;
581 info->nFileIndexLow = st->st_ino;
585 /***********************************************************************
588 * Stat a Unix path name. Return TRUE if OK.
590 BOOL FILE_Stat( LPCSTR unixName, BY_HANDLE_FILE_INFORMATION *info )
594 if (lstat( unixName, &st ) == -1)
599 if (!S_ISLNK(st.st_mode)) FILE_FillInfo( &st, info );
602 /* do a "real" stat to find out
603 about the type of the symlink destination */
604 if (stat( unixName, &st ) == -1)
609 FILE_FillInfo( &st, info );
610 info->dwFileAttributes |= FILE_ATTRIBUTE_SYMLINK;
616 /***********************************************************************
617 * GetFileInformationByHandle (KERNEL32.@)
619 DWORD WINAPI GetFileInformationByHandle( HANDLE hFile,
620 BY_HANDLE_FILE_INFORMATION *info )
625 SERVER_START_REQ( get_file_info )
628 if ((ret = !wine_server_call_err( req )))
630 /* FIXME: which file types are supported ?
631 * Serial ports (FILE_TYPE_CHAR) are not,
632 * and MSDN also says that pipes are not supported.
633 * FILE_TYPE_REMOTE seems to be supported according to
634 * MSDN q234741.txt */
635 if ((reply->type == FILE_TYPE_DISK) || (reply->type == FILE_TYPE_REMOTE))
637 RtlSecondsSince1970ToTime( reply->write_time, &info->ftCreationTime );
638 RtlSecondsSince1970ToTime( reply->write_time, &info->ftLastWriteTime );
639 RtlSecondsSince1970ToTime( reply->access_time, &info->ftLastAccessTime );
640 info->dwFileAttributes = reply->attr;
641 info->dwVolumeSerialNumber = reply->serial;
642 info->nFileSizeHigh = reply->size_high;
643 info->nFileSizeLow = reply->size_low;
644 info->nNumberOfLinks = reply->links;
645 info->nFileIndexHigh = reply->index_high;
646 info->nFileIndexLow = reply->index_low;
650 SetLastError(ERROR_NOT_SUPPORTED);
660 /**************************************************************************
661 * GetFileAttributes (KERNEL.420)
663 DWORD WINAPI GetFileAttributes16( LPCSTR name )
665 return GetFileAttributesA( name );
669 /**************************************************************************
670 * GetFileAttributesA (KERNEL32.@)
672 DWORD WINAPI GetFileAttributesA( LPCSTR name )
674 DOS_FULL_NAME full_name;
675 BY_HANDLE_FILE_INFORMATION info;
679 SetLastError( ERROR_INVALID_PARAMETER );
682 if (!DOSFS_GetFullName( name, TRUE, &full_name) )
684 if (!FILE_Stat( full_name.long_name, &info )) return -1;
685 return info.dwFileAttributes;
689 /**************************************************************************
690 * GetFileAttributesW (KERNEL32.@)
692 DWORD WINAPI GetFileAttributesW( LPCWSTR name )
694 LPSTR nameA = HEAP_strdupWtoA( GetProcessHeap(), 0, name );
695 DWORD res = GetFileAttributesA( nameA );
696 HeapFree( GetProcessHeap(), 0, nameA );
701 /***********************************************************************
702 * GetFileSize (KERNEL32.@)
704 DWORD WINAPI GetFileSize( HANDLE hFile, LPDWORD filesizehigh )
706 BY_HANDLE_FILE_INFORMATION info;
707 if (!GetFileInformationByHandle( hFile, &info )) return -1;
708 if (filesizehigh) *filesizehigh = info.nFileSizeHigh;
709 return info.nFileSizeLow;
713 /***********************************************************************
714 * GetFileTime (KERNEL32.@)
716 BOOL WINAPI GetFileTime( HANDLE hFile, FILETIME *lpCreationTime,
717 FILETIME *lpLastAccessTime,
718 FILETIME *lpLastWriteTime )
720 BY_HANDLE_FILE_INFORMATION info;
721 if (!GetFileInformationByHandle( hFile, &info )) return FALSE;
722 if (lpCreationTime) *lpCreationTime = info.ftCreationTime;
723 if (lpLastAccessTime) *lpLastAccessTime = info.ftLastAccessTime;
724 if (lpLastWriteTime) *lpLastWriteTime = info.ftLastWriteTime;
728 /***********************************************************************
729 * CompareFileTime (KERNEL32.@)
731 INT WINAPI CompareFileTime( LPFILETIME x, LPFILETIME y )
733 if (!x || !y) return -1;
735 if (x->dwHighDateTime > y->dwHighDateTime)
737 if (x->dwHighDateTime < y->dwHighDateTime)
739 if (x->dwLowDateTime > y->dwLowDateTime)
741 if (x->dwLowDateTime < y->dwLowDateTime)
746 /***********************************************************************
747 * FILE_GetTempFileName : utility for GetTempFileName
749 static UINT FILE_GetTempFileName( LPCSTR path, LPCSTR prefix, UINT unique,
750 LPSTR buffer, BOOL isWin16 )
752 static UINT unique_temp;
753 DOS_FULL_NAME full_name;
758 if ( !path || !prefix || !buffer ) return 0;
760 if (!unique_temp) unique_temp = time(NULL) & 0xffff;
761 num = unique ? (unique & 0xffff) : (unique_temp++ & 0xffff);
763 strcpy( buffer, path );
764 p = buffer + strlen(buffer);
766 /* add a \, if there isn't one and path is more than just the drive letter ... */
767 if ( !((strlen(buffer) == 2) && (buffer[1] == ':'))
768 && ((p == buffer) || (p[-1] != '\\'))) *p++ = '\\';
770 if (isWin16) *p++ = '~';
771 for (i = 3; (i > 0) && (*prefix); i--) *p++ = *prefix++;
772 sprintf( p, "%04x.tmp", num );
774 /* Now try to create it */
780 HFILE handle = CreateFileA( buffer, GENERIC_WRITE, 0, NULL,
781 CREATE_NEW, FILE_ATTRIBUTE_NORMAL, 0 );
782 if (handle != INVALID_HANDLE_VALUE)
783 { /* We created it */
784 TRACE("created %s\n",
786 CloseHandle( handle );
789 if (GetLastError() != ERROR_FILE_EXISTS)
790 break; /* No need to go on */
792 sprintf( p, "%04x.tmp", num );
793 } while (num != (unique & 0xffff));
796 /* Get the full path name */
798 if (DOSFS_GetFullName( buffer, FALSE, &full_name ))
800 /* Check if we have write access in the directory */
801 if ((p = strrchr( full_name.long_name, '/' ))) *p = '\0';
802 if (access( full_name.long_name, W_OK ) == -1)
803 WARN("returns '%s', which doesn't seem to be writeable.\n",
806 TRACE("returning %s\n", buffer );
807 return unique ? unique : num;
811 /***********************************************************************
812 * GetTempFileNameA (KERNEL32.@)
814 UINT WINAPI GetTempFileNameA( LPCSTR path, LPCSTR prefix, UINT unique,
817 return FILE_GetTempFileName(path, prefix, unique, buffer, FALSE);
820 /***********************************************************************
821 * GetTempFileNameW (KERNEL32.@)
823 UINT WINAPI GetTempFileNameW( LPCWSTR path, LPCWSTR prefix, UINT unique,
831 patha = HEAP_strdupWtoA( GetProcessHeap(), 0, path );
832 prefixa = HEAP_strdupWtoA( GetProcessHeap(), 0, prefix );
833 ret = FILE_GetTempFileName( patha, prefixa, unique, buffera, FALSE );
834 MultiByteToWideChar( CP_ACP, 0, buffera, -1, buffer, MAX_PATH );
835 HeapFree( GetProcessHeap(), 0, patha );
836 HeapFree( GetProcessHeap(), 0, prefixa );
841 /***********************************************************************
842 * GetTempFileName (KERNEL.97)
844 UINT16 WINAPI GetTempFileName16( BYTE drive, LPCSTR prefix, UINT16 unique,
849 if (!(drive & ~TF_FORCEDRIVE)) /* drive 0 means current default drive */
850 drive |= DRIVE_GetCurrentDrive() + 'A';
852 if ((drive & TF_FORCEDRIVE) &&
853 !DRIVE_IsValid( toupper(drive & ~TF_FORCEDRIVE) - 'A' ))
855 drive &= ~TF_FORCEDRIVE;
856 WARN("invalid drive %d specified\n", drive );
859 if (drive & TF_FORCEDRIVE)
860 sprintf(temppath,"%c:", drive & ~TF_FORCEDRIVE );
862 GetTempPathA( 132, temppath );
863 return (UINT16)FILE_GetTempFileName( temppath, prefix, unique, buffer, TRUE );
866 /***********************************************************************
869 * Implementation of OpenFile16() and OpenFile32().
871 static HFILE FILE_DoOpenFile( LPCSTR name, OFSTRUCT *ofs, UINT mode,
876 WORD filedatetime[2];
877 DOS_FULL_NAME full_name;
878 DWORD access, sharing;
881 if (!ofs) return HFILE_ERROR;
883 TRACE("%s %s %s %s%s%s%s%s%s%s%s%s\n",name,
884 ((mode & 0x3 )==OF_READ)?"OF_READ":
885 ((mode & 0x3 )==OF_WRITE)?"OF_WRITE":
886 ((mode & 0x3 )==OF_READWRITE)?"OF_READWRITE":"unknown",
887 ((mode & 0x70 )==OF_SHARE_COMPAT)?"OF_SHARE_COMPAT":
888 ((mode & 0x70 )==OF_SHARE_DENY_NONE)?"OF_SHARE_DENY_NONE":
889 ((mode & 0x70 )==OF_SHARE_DENY_READ)?"OF_SHARE_DENY_READ":
890 ((mode & 0x70 )==OF_SHARE_DENY_WRITE)?"OF_SHARE_DENY_WRITE":
891 ((mode & 0x70 )==OF_SHARE_EXCLUSIVE)?"OF_SHARE_EXCLUSIVE":"unknown",
892 ((mode & OF_PARSE )==OF_PARSE)?"OF_PARSE ":"",
893 ((mode & OF_DELETE )==OF_DELETE)?"OF_DELETE ":"",
894 ((mode & OF_VERIFY )==OF_VERIFY)?"OF_VERIFY ":"",
895 ((mode & OF_SEARCH )==OF_SEARCH)?"OF_SEARCH ":"",
896 ((mode & OF_CANCEL )==OF_CANCEL)?"OF_CANCEL ":"",
897 ((mode & OF_CREATE )==OF_CREATE)?"OF_CREATE ":"",
898 ((mode & OF_PROMPT )==OF_PROMPT)?"OF_PROMPT ":"",
899 ((mode & OF_EXIST )==OF_EXIST)?"OF_EXIST ":"",
900 ((mode & OF_REOPEN )==OF_REOPEN)?"OF_REOPEN ":""
904 ofs->cBytes = sizeof(OFSTRUCT);
906 if (mode & OF_REOPEN) name = ofs->szPathName;
909 ERR("called with `name' set to NULL ! Please debug.\n");
913 TRACE("%s %04x\n", name, mode );
915 /* the watcom 10.6 IDE relies on a valid path returned in ofs->szPathName
916 Are there any cases where getting the path here is wrong?
917 Uwe Bonnes 1997 Apr 2 */
918 if (!GetFullPathNameA( name, sizeof(ofs->szPathName),
919 ofs->szPathName, NULL )) goto error;
920 FILE_ConvertOFMode( mode, &access, &sharing );
922 /* OF_PARSE simply fills the structure */
926 ofs->fFixedDisk = (GetDriveType16( ofs->szPathName[0]-'A' )
928 TRACE("(%s): OF_PARSE, res = '%s'\n",
929 name, ofs->szPathName );
933 /* OF_CREATE is completely different from all other options, so
936 if (mode & OF_CREATE)
938 if ((hFileRet = CreateFileA( name, GENERIC_READ | GENERIC_WRITE,
939 sharing, NULL, CREATE_ALWAYS,
940 FILE_ATTRIBUTE_NORMAL, 0 ))== INVALID_HANDLE_VALUE)
945 /* If OF_SEARCH is set, ignore the given path */
947 if ((mode & OF_SEARCH) && !(mode & OF_REOPEN))
949 /* First try the file name as is */
950 if (DOSFS_GetFullName( name, TRUE, &full_name )) goto found;
951 /* Now remove the path */
952 if (name[0] && (name[1] == ':')) name += 2;
953 if ((p = strrchr( name, '\\' ))) name = p + 1;
954 if ((p = strrchr( name, '/' ))) name = p + 1;
955 if (!name[0]) goto not_found;
958 /* Now look for the file */
960 if (!DIR_SearchPath( NULL, name, NULL, &full_name, win32 )) goto not_found;
963 TRACE("found %s = %s\n",
964 full_name.long_name, full_name.short_name );
965 lstrcpynA( ofs->szPathName, full_name.short_name,
966 sizeof(ofs->szPathName) );
968 if (mode & OF_SHARE_EXCLUSIVE)
969 /* Some InstallShield version uses OF_SHARE_EXCLUSIVE
970 on the file <tempdir>/_ins0432._mp to determine how
971 far installation has proceeded.
972 _ins0432._mp is an executable and while running the
973 application expects the open with OF_SHARE_ to fail*/
975 As our loader closes the files after loading the executable,
976 we can't find the running executable with FILE_InUse.
977 The loader should keep the file open, as Windows does that, too.
980 char *last = strrchr(full_name.long_name,'/');
982 last = full_name.long_name - 1;
983 if (GetModuleHandle16(last+1))
985 TRACE("Denying shared open for %s\n",full_name.long_name);
990 if (mode & OF_DELETE)
992 if (unlink( full_name.long_name ) == -1) goto not_found;
993 TRACE("(%s): OF_DELETE return = OK\n", name);
997 hFileRet = FILE_CreateFile( full_name.long_name, access, sharing,
998 NULL, OPEN_EXISTING, 0, 0,
999 DRIVE_GetFlags(full_name.drive) & DRIVE_FAIL_READ_ONLY,
1000 GetDriveTypeA( full_name.short_name ) );
1001 if (!hFileRet) goto not_found;
1003 GetFileTime( hFileRet, NULL, NULL, &filetime );
1004 FileTimeToDosDateTime( &filetime, &filedatetime[0], &filedatetime[1] );
1005 if ((mode & OF_VERIFY) && (mode & OF_REOPEN))
1007 if (memcmp( ofs->reserved, filedatetime, sizeof(ofs->reserved) ))
1009 CloseHandle( hFileRet );
1010 WARN("(%s): OF_VERIFY failed\n", name );
1011 /* FIXME: what error here? */
1012 SetLastError( ERROR_FILE_NOT_FOUND );
1016 memcpy( ofs->reserved, filedatetime, sizeof(ofs->reserved) );
1018 success: /* We get here if the open was successful */
1019 TRACE("(%s): OK, return = %d\n", name, hFileRet );
1022 if (mode & OF_EXIST) /* Return the handle, but close it first */
1023 CloseHandle( hFileRet );
1027 hFileRet = Win32HandleToDosFileHandle( hFileRet );
1028 if (hFileRet == HFILE_ERROR16) goto error;
1029 if (mode & OF_EXIST) /* Return the handle, but close it first */
1030 _lclose16( hFileRet );
1034 not_found: /* We get here if the file does not exist */
1035 WARN("'%s' not found or sharing violation\n", name );
1036 SetLastError( ERROR_FILE_NOT_FOUND );
1039 error: /* We get here if there was an error opening the file */
1040 ofs->nErrCode = GetLastError();
1041 WARN("(%s): return = HFILE_ERROR error= %d\n",
1042 name,ofs->nErrCode );
1047 /***********************************************************************
1048 * OpenFile (KERNEL.74)
1049 * OpenFileEx (KERNEL.360)
1051 HFILE16 WINAPI OpenFile16( LPCSTR name, OFSTRUCT *ofs, UINT16 mode )
1053 return FILE_DoOpenFile( name, ofs, mode, FALSE );
1057 /***********************************************************************
1058 * OpenFile (KERNEL32.@)
1060 HFILE WINAPI OpenFile( LPCSTR name, OFSTRUCT *ofs, UINT mode )
1062 return FILE_DoOpenFile( name, ofs, mode, TRUE );
1066 /***********************************************************************
1067 * FILE_InitProcessDosHandles
1069 * Allocates the default DOS handles for a process. Called either by
1070 * Win32HandleToDosFileHandle below or by the DOSVM stuff.
1072 static void FILE_InitProcessDosHandles( void )
1074 dos_handles[0] = GetStdHandle(STD_INPUT_HANDLE);
1075 dos_handles[1] = GetStdHandle(STD_OUTPUT_HANDLE);
1076 dos_handles[2] = GetStdHandle(STD_ERROR_HANDLE);
1077 dos_handles[3] = GetStdHandle(STD_ERROR_HANDLE);
1078 dos_handles[4] = GetStdHandle(STD_ERROR_HANDLE);
1081 /***********************************************************************
1082 * Win32HandleToDosFileHandle (KERNEL32.21)
1084 * Allocate a DOS handle for a Win32 handle. The Win32 handle is no
1085 * longer valid after this function (even on failure).
1087 * Note: this is not exactly right, since on Win95 the Win32 handles
1088 * are on top of DOS handles and we do it the other way
1089 * around. Should be good enough though.
1091 HFILE WINAPI Win32HandleToDosFileHandle( HANDLE handle )
1095 if (!handle || (handle == INVALID_HANDLE_VALUE))
1098 for (i = 5; i < DOS_TABLE_SIZE; i++)
1099 if (!dos_handles[i])
1101 dos_handles[i] = handle;
1102 TRACE("Got %d for h32 %d\n", i, handle );
1105 CloseHandle( handle );
1106 SetLastError( ERROR_TOO_MANY_OPEN_FILES );
1111 /***********************************************************************
1112 * DosFileHandleToWin32Handle (KERNEL32.20)
1114 * Return the Win32 handle for a DOS handle.
1116 * Note: this is not exactly right, since on Win95 the Win32 handles
1117 * are on top of DOS handles and we do it the other way
1118 * around. Should be good enough though.
1120 HANDLE WINAPI DosFileHandleToWin32Handle( HFILE handle )
1122 HFILE16 hfile = (HFILE16)handle;
1123 if (hfile < 5 && !dos_handles[hfile]) FILE_InitProcessDosHandles();
1124 if ((hfile >= DOS_TABLE_SIZE) || !dos_handles[hfile])
1126 SetLastError( ERROR_INVALID_HANDLE );
1127 return INVALID_HANDLE_VALUE;
1129 return dos_handles[hfile];
1133 /***********************************************************************
1134 * DisposeLZ32Handle (KERNEL32.22)
1136 * Note: this is not entirely correct, we should only close the
1137 * 32-bit handle and not the 16-bit one, but we cannot do
1138 * this because of the way our DOS handles are implemented.
1139 * It shouldn't break anything though.
1141 void WINAPI DisposeLZ32Handle( HANDLE handle )
1145 if (!handle || (handle == INVALID_HANDLE_VALUE)) return;
1147 for (i = 5; i < DOS_TABLE_SIZE; i++)
1148 if (dos_handles[i] == handle)
1151 CloseHandle( handle );
1157 /***********************************************************************
1160 * dup2() function for DOS handles.
1162 HFILE16 FILE_Dup2( HFILE16 hFile1, HFILE16 hFile2 )
1166 if (hFile1 < 5 && !dos_handles[hFile1]) FILE_InitProcessDosHandles();
1168 if ((hFile1 >= DOS_TABLE_SIZE) || (hFile2 >= DOS_TABLE_SIZE) || !dos_handles[hFile1])
1170 SetLastError( ERROR_INVALID_HANDLE );
1171 return HFILE_ERROR16;
1175 FIXME("stdio handle closed, need proper conversion\n" );
1176 SetLastError( ERROR_INVALID_HANDLE );
1177 return HFILE_ERROR16;
1179 if (!DuplicateHandle( GetCurrentProcess(), dos_handles[hFile1],
1180 GetCurrentProcess(), &new_handle,
1181 0, FALSE, DUPLICATE_SAME_ACCESS ))
1182 return HFILE_ERROR16;
1183 if (dos_handles[hFile2]) CloseHandle( dos_handles[hFile2] );
1184 dos_handles[hFile2] = new_handle;
1189 /***********************************************************************
1190 * _lclose (KERNEL.81)
1192 HFILE16 WINAPI _lclose16( HFILE16 hFile )
1196 FIXME("stdio handle closed, need proper conversion\n" );
1197 SetLastError( ERROR_INVALID_HANDLE );
1198 return HFILE_ERROR16;
1200 if ((hFile >= DOS_TABLE_SIZE) || !dos_handles[hFile])
1202 SetLastError( ERROR_INVALID_HANDLE );
1203 return HFILE_ERROR16;
1205 TRACE("%d (handle32=%d)\n", hFile, dos_handles[hFile] );
1206 CloseHandle( dos_handles[hFile] );
1207 dos_handles[hFile] = 0;
1212 /***********************************************************************
1213 * _lclose (KERNEL32.@)
1215 HFILE WINAPI _lclose( HFILE hFile )
1217 TRACE("handle %d\n", hFile );
1218 return CloseHandle( hFile ) ? 0 : HFILE_ERROR;
1221 /***********************************************************************
1222 * GetOverlappedResult (KERNEL32.@)
1224 * Check the result of an Asynchronous data transfer from a file.
1230 * If successful (and relevant) lpTransferred will hold the number of
1231 * bytes transferred during the async operation.
1235 * Currently only works for WaitCommEvent, ReadFile, WriteFile
1236 * with communications ports.
1239 BOOL WINAPI GetOverlappedResult(
1240 HANDLE hFile, /* [in] handle of file to check on */
1241 LPOVERLAPPED lpOverlapped, /* [in/out] pointer to overlapped */
1242 LPDWORD lpTransferred, /* [in/out] number of bytes transferred */
1243 BOOL bWait /* [in] wait for the transfer to complete ? */
1247 TRACE("(%d %p %p %x)\n", hFile, lpOverlapped, lpTransferred, bWait);
1249 if(lpOverlapped==NULL)
1251 ERR("lpOverlapped was null\n");
1254 if(!lpOverlapped->hEvent)
1256 ERR("lpOverlapped->hEvent was null\n");
1261 TRACE("waiting on %p\n",lpOverlapped);
1262 r = WaitForSingleObjectEx(lpOverlapped->hEvent, bWait?INFINITE:0, TRUE);
1263 TRACE("wait on %p returned %ld\n",lpOverlapped,r);
1264 } while (r==STATUS_USER_APC);
1267 *lpTransferred = lpOverlapped->InternalHigh;
1269 SetLastError(lpOverlapped->Internal);
1271 return (r==WAIT_OBJECT_0);
1275 /***********************************************************************
1276 * FILE_StartAsync (INTERNAL)
1278 * type==ASYNC_TYPE_NONE means cancel the indicated overlapped operation
1279 * lpOverlapped==NULL means all overlappeds match
1281 BOOL FILE_StartAsync(HANDLE hFile, LPOVERLAPPED lpOverlapped, DWORD type, DWORD count, DWORD status)
1284 SERVER_START_REQ(register_async)
1286 req->handle = hFile;
1287 req->overlapped = lpOverlapped;
1290 req->func = check_async_list;
1291 req->status = status;
1292 ret = wine_server_call( req );
1298 /***********************************************************************
1299 * CancelIo (KERNEL32.@)
1301 BOOL WINAPI CancelIo(HANDLE handle)
1303 async_private *ovp,*t;
1305 TRACE("handle = %x\n",handle);
1307 ovp = NtCurrentTeb()->pending_list;
1311 if(FILE_StartAsync(handle, ovp->lpOverlapped, ovp->type, 0, STATUS_CANCELLED))
1313 TRACE("overlapped = %p\n",ovp->lpOverlapped);
1314 finish_async(ovp, STATUS_CANCELLED);
1318 WaitForMultipleObjectsEx(0,NULL,FALSE,1,TRUE);
1322 /***********************************************************************
1323 * FILE_AsyncReadService (INTERNAL)
1325 * This function is called while the client is waiting on the
1326 * server, so we can't make any server calls here.
1328 static void FILE_AsyncReadService(async_private *ovp)
1330 LPOVERLAPPED lpOverlapped = ovp->lpOverlapped;
1332 int already = lpOverlapped->InternalHigh;
1334 TRACE("%p %p\n", lpOverlapped, ovp->buffer );
1336 /* check to see if the data is ready (non-blocking) */
1338 result = pread (ovp->fd, &ovp->buffer[already], ovp->count - already,
1339 OVERLAPPED_OFFSET (lpOverlapped) + already);
1340 if ((result < 0) && (errno == ESPIPE))
1341 result = read (ovp->fd, &ovp->buffer[already], ovp->count - already);
1343 if ( (result<0) && ((errno == EAGAIN) || (errno == EINTR)))
1345 TRACE("Deferred read %d\n",errno);
1350 /* check to see if the transfer is complete */
1353 TRACE("read returned errno %d\n",errno);
1354 r = STATUS_UNSUCCESSFUL;
1358 lpOverlapped->InternalHigh += result;
1359 TRACE("read %d more bytes %ld/%d so far\n",result,lpOverlapped->InternalHigh,ovp->count);
1361 if(lpOverlapped->InternalHigh < ovp->count)
1367 lpOverlapped->Internal = r;
1370 /***********************************************************************
1371 * FILE_ReadFileEx (INTERNAL)
1373 static BOOL FILE_ReadFileEx(HANDLE hFile, LPVOID buffer, DWORD bytesToRead,
1374 LPOVERLAPPED overlapped,
1375 LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine,
1381 TRACE("file %d to buf %p num %ld %p func %p\n",
1382 hFile, buffer, bytesToRead, overlapped, lpCompletionRoutine);
1384 /* check that there is an overlapped struct */
1385 if (overlapped==NULL)
1387 SetLastError(ERROR_INVALID_PARAMETER);
1391 fd = FILE_GetUnixHandle( hFile, GENERIC_READ );
1394 TRACE("Couldn't get FD\n");
1398 ovp = (async_private *) HeapAlloc(GetProcessHeap(), 0, sizeof (async_private));
1401 TRACE("HeapAlloc Failed\n");
1402 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1406 ovp->event = hEvent;
1407 ovp->lpOverlapped = overlapped;
1408 ovp->count = bytesToRead;
1409 ovp->completion_func = lpCompletionRoutine;
1410 ovp->func = FILE_AsyncReadService;
1411 ovp->buffer = buffer;
1413 ovp->type = ASYNC_TYPE_READ;
1414 ovp->handle = hFile;
1416 /* hook this overlap into the pending async operation list */
1417 ovp->next = NtCurrentTeb()->pending_list;
1420 ovp->next->prev = ovp;
1421 NtCurrentTeb()->pending_list = ovp;
1423 if ( !FILE_StartAsync(hFile, overlapped, ASYNC_TYPE_READ, bytesToRead, STATUS_PENDING) )
1425 /* FIXME: remove async_private and release memory */
1426 ERR("FILE_StartAsync failed\n");
1433 /***********************************************************************
1434 * ReadFileEx (KERNEL32.@)
1436 BOOL WINAPI ReadFileEx(HANDLE hFile, LPVOID buffer, DWORD bytesToRead,
1437 LPOVERLAPPED overlapped,
1438 LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine)
1440 overlapped->Internal = STATUS_PENDING;
1441 overlapped->InternalHigh = 0;
1442 return FILE_ReadFileEx(hFile,buffer,bytesToRead,overlapped,lpCompletionRoutine, INVALID_HANDLE_VALUE);
1445 static BOOL FILE_TimeoutRead(HANDLE hFile, LPVOID buffer, DWORD bytesToRead, LPDWORD bytesRead)
1450 TRACE("%d %p %ld %p\n", hFile, buffer, bytesToRead, bytesRead );
1452 ZeroMemory(&ov, sizeof (OVERLAPPED));
1453 if(STATUS_SUCCESS==NtCreateEvent(&ov.hEvent, SYNCHRONIZE, NULL, 0, 0))
1455 if(FILE_ReadFileEx(hFile, buffer, bytesToRead, &ov, NULL, ov.hEvent))
1457 r = GetOverlappedResult(hFile, &ov, bytesRead, TRUE);
1460 CloseHandle(ov.hEvent);
1464 /***********************************************************************
1465 * ReadFile (KERNEL32.@)
1467 BOOL WINAPI ReadFile( HANDLE hFile, LPVOID buffer, DWORD bytesToRead,
1468 LPDWORD bytesRead, LPOVERLAPPED overlapped )
1470 int unix_handle, result;
1474 TRACE("%d %p %ld %p %p\n", hFile, buffer, bytesToRead,
1475 bytesRead, overlapped );
1477 if (bytesRead) *bytesRead = 0; /* Do this before anything else */
1478 if (!bytesToRead) return TRUE;
1480 unix_handle = FILE_GetUnixHandleType( hFile, GENERIC_READ, &type, &flags );
1482 if (flags & FD_FLAG_OVERLAPPED)
1484 if (unix_handle == -1) return FALSE;
1485 if ( (overlapped==NULL) || NtResetEvent( overlapped->hEvent, NULL ) )
1487 TRACE("Overlapped not specified or invalid event flag\n");
1489 SetLastError(ERROR_INVALID_PARAMETER);
1493 /* see if we can read some data already (this shouldn't block) */
1494 result = pread( unix_handle, buffer, bytesToRead, OVERLAPPED_OFFSET(overlapped) );
1495 if ((result < 0) && (errno == ESPIPE))
1496 result = read( unix_handle, buffer, bytesToRead );
1501 if( (errno!=EAGAIN) && (errno!=EINTR) &&
1502 ((errno != EFAULT) || IsBadWritePtr( buffer, bytesToRead )) )
1511 /* if we read enough to keep the app happy, then return now */
1512 if(result>=bytesToRead)
1514 *bytesRead = result;
1518 /* at last resort, do an overlapped read */
1519 overlapped->Internal = STATUS_PENDING;
1520 overlapped->InternalHigh = result;
1522 if(!FILE_ReadFileEx(hFile, buffer, bytesToRead, overlapped, NULL, overlapped->hEvent))
1525 /* fail on return, with ERROR_IO_PENDING */
1526 SetLastError(ERROR_IO_PENDING);
1529 if (flags & FD_FLAG_TIMEOUT)
1532 return FILE_TimeoutRead(hFile, buffer, bytesToRead, bytesRead);
1537 return SMB_ReadFile(hFile, buffer, bytesToRead, bytesRead, NULL);
1538 case FD_TYPE_CONSOLE:
1539 return ReadConsoleA(hFile, buffer, bytesToRead, bytesRead, NULL);
1542 /* normal unix files */
1543 if (unix_handle == -1)
1548 SetLastError(ERROR_INVALID_PARAMETER);
1554 /* code for synchronous reads */
1555 while ((result = read( unix_handle, buffer, bytesToRead )) == -1)
1557 if ((errno == EAGAIN) || (errno == EINTR)) continue;
1558 if ((errno == EFAULT) && !IsBadWritePtr( buffer, bytesToRead )) continue;
1562 close( unix_handle );
1563 if (result == -1) return FALSE;
1564 if (bytesRead) *bytesRead = result;
1569 /***********************************************************************
1570 * FILE_AsyncWriteService (INTERNAL)
1572 * This function is called while the client is waiting on the
1573 * server, so we can't make any server calls here.
1575 static void FILE_AsyncWriteService(struct async_private *ovp)
1577 LPOVERLAPPED lpOverlapped = ovp->lpOverlapped;
1579 int already = lpOverlapped->InternalHigh;
1581 TRACE("(%p %p)\n",lpOverlapped,ovp->buffer);
1583 /* write some data (non-blocking) */
1585 result = pwrite(ovp->fd, &ovp->buffer[already], ovp->count - already,
1586 OVERLAPPED_OFFSET (lpOverlapped) + already);
1587 if ((result < 0) && (errno == ESPIPE))
1588 result = write(ovp->fd, &ovp->buffer[already], ovp->count - already);
1590 if ( (result<0) && ((errno == EAGAIN) || (errno == EINTR)))
1596 /* check to see if the transfer is complete */
1599 r = STATUS_UNSUCCESSFUL;
1603 lpOverlapped->InternalHigh += result;
1605 TRACE("wrote %d more bytes %ld/%d so far\n",result,lpOverlapped->InternalHigh,ovp->count);
1607 if(lpOverlapped->InternalHigh < ovp->count)
1613 lpOverlapped->Internal = r;
1616 /***********************************************************************
1619 static BOOL FILE_WriteFileEx(HANDLE hFile, LPCVOID buffer, DWORD bytesToWrite,
1620 LPOVERLAPPED overlapped,
1621 LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine,
1626 TRACE("file %d to buf %p num %ld %p func %p stub\n",
1627 hFile, buffer, bytesToWrite, overlapped, lpCompletionRoutine);
1629 if (overlapped == NULL)
1631 SetLastError(ERROR_INVALID_PARAMETER);
1635 overlapped->Internal = STATUS_PENDING;
1636 overlapped->InternalHigh = 0;
1638 if (!FILE_StartAsync(hFile, overlapped, ASYNC_TYPE_WRITE, bytesToWrite, STATUS_PENDING ))
1640 TRACE("FILE_StartAsync failed\n");
1644 ovp = (async_private*) HeapAlloc(GetProcessHeap(), 0, sizeof (async_private));
1647 TRACE("HeapAlloc Failed\n");
1648 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1651 ovp->lpOverlapped = overlapped;
1652 ovp->event = hEvent;
1653 ovp->func = FILE_AsyncWriteService;
1654 ovp->buffer = (LPVOID) buffer;
1655 ovp->count = bytesToWrite;
1656 ovp->completion_func = lpCompletionRoutine;
1657 ovp->fd = FILE_GetUnixHandle( hFile, GENERIC_WRITE );
1658 ovp->type = ASYNC_TYPE_WRITE;
1659 ovp->handle = hFile;
1663 HeapFree(GetProcessHeap(), 0, ovp);
1667 /* hook this overlap into the pending async operation list */
1668 ovp->next = NtCurrentTeb()->pending_list;
1671 ovp->next->prev = ovp;
1672 NtCurrentTeb()->pending_list = ovp;
1677 /***********************************************************************
1678 * WriteFileEx (KERNEL32.@)
1680 BOOL WINAPI WriteFileEx(HANDLE hFile, LPCVOID buffer, DWORD bytesToWrite,
1681 LPOVERLAPPED overlapped,
1682 LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine)
1684 overlapped->Internal = STATUS_PENDING;
1685 overlapped->InternalHigh = 0;
1687 return FILE_WriteFileEx(hFile, buffer, bytesToWrite, overlapped, lpCompletionRoutine, INVALID_HANDLE_VALUE);
1690 /***********************************************************************
1691 * WriteFile (KERNEL32.@)
1693 BOOL WINAPI WriteFile( HANDLE hFile, LPCVOID buffer, DWORD bytesToWrite,
1694 LPDWORD bytesWritten, LPOVERLAPPED overlapped )
1696 int unix_handle, result;
1700 TRACE("%d %p %ld %p %p\n", hFile, buffer, bytesToWrite,
1701 bytesWritten, overlapped );
1703 if (bytesWritten) *bytesWritten = 0; /* Do this before anything else */
1704 if (!bytesToWrite) return TRUE;
1706 unix_handle = FILE_GetUnixHandleType( hFile, GENERIC_WRITE, &type, &flags );
1708 if (flags & FD_FLAG_OVERLAPPED)
1710 if (unix_handle == -1) return FALSE;
1711 if ( (overlapped==NULL) || NtResetEvent( overlapped->hEvent, NULL ) )
1713 TRACE("Overlapped not specified or invalid event flag\n");
1715 SetLastError(ERROR_INVALID_PARAMETER);
1719 /* see if we can write some data already (this shouldn't block) */
1721 result = pwrite( unix_handle, buffer, bytesToWrite, OVERLAPPED_OFFSET (overlapped) );
1722 if ((result < 0) && (errno == ESPIPE))
1723 result = write( unix_handle, buffer, bytesToWrite );
1729 if( (errno!=EAGAIN) && (errno!=EINTR) &&
1730 ((errno != EFAULT) || IsBadReadPtr( buffer, bytesToWrite )) )
1739 /* if we wrote enough to keep the app happy, then return now */
1740 if(result>=bytesToWrite)
1742 *bytesWritten = result;
1746 /* at last resort, do an overlapped read */
1747 overlapped->Internal = STATUS_PENDING;
1748 overlapped->InternalHigh = result;
1750 if(!FILE_WriteFileEx(hFile, buffer, bytesToWrite, overlapped, NULL, overlapped->hEvent))
1753 /* fail on return, with ERROR_IO_PENDING */
1754 SetLastError(ERROR_IO_PENDING);
1760 case FD_TYPE_CONSOLE:
1761 TRACE("%d %s %ld %p %p\n", hFile, debugstr_an(buffer, bytesToWrite), bytesToWrite,
1762 bytesWritten, overlapped );
1763 return WriteConsoleA(hFile, buffer, bytesToWrite, bytesWritten, NULL);
1765 if (unix_handle == -1)
1769 /* synchronous file write */
1770 while ((result = write( unix_handle, buffer, bytesToWrite )) == -1)
1772 if ((errno == EAGAIN) || (errno == EINTR)) continue;
1773 if ((errno == EFAULT) && !IsBadReadPtr( buffer, bytesToWrite )) continue;
1774 if (errno == ENOSPC)
1775 SetLastError( ERROR_DISK_FULL );
1780 close( unix_handle );
1781 if (result == -1) return FALSE;
1782 if (bytesWritten) *bytesWritten = result;
1787 /***********************************************************************
1788 * _hread (KERNEL.349)
1790 LONG WINAPI WIN16_hread( HFILE16 hFile, SEGPTR buffer, LONG count )
1794 TRACE("%d %08lx %ld\n",
1795 hFile, (DWORD)buffer, count );
1797 /* Some programs pass a count larger than the allocated buffer */
1798 maxlen = GetSelectorLimit16( SELECTOROF(buffer) ) - OFFSETOF(buffer) + 1;
1799 if (count > maxlen) count = maxlen;
1800 return _lread(DosFileHandleToWin32Handle(hFile), MapSL(buffer), count );
1804 /***********************************************************************
1805 * _lread (KERNEL.82)
1807 UINT16 WINAPI WIN16_lread( HFILE16 hFile, SEGPTR buffer, UINT16 count )
1809 return (UINT16)WIN16_hread( hFile, buffer, (LONG)count );
1813 /***********************************************************************
1814 * _lread (KERNEL32.@)
1816 UINT WINAPI _lread( HFILE handle, LPVOID buffer, UINT count )
1819 if (!ReadFile( handle, buffer, count, &result, NULL )) return -1;
1824 /***********************************************************************
1825 * _lread16 (KERNEL.82)
1827 UINT16 WINAPI _lread16( HFILE16 hFile, LPVOID buffer, UINT16 count )
1829 return (UINT16)_lread(DosFileHandleToWin32Handle(hFile), buffer, (LONG)count );
1833 /***********************************************************************
1834 * _lcreat (KERNEL.83)
1836 HFILE16 WINAPI _lcreat16( LPCSTR path, INT16 attr )
1838 return Win32HandleToDosFileHandle( _lcreat( path, attr ) );
1842 /***********************************************************************
1843 * _lcreat (KERNEL32.@)
1845 HFILE WINAPI _lcreat( LPCSTR path, INT attr )
1847 /* Mask off all flags not explicitly allowed by the doc */
1848 attr &= FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM;
1849 TRACE("%s %02x\n", path, attr );
1850 return CreateFileA( path, GENERIC_READ | GENERIC_WRITE,
1851 FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
1852 CREATE_ALWAYS, attr, 0 );
1856 /***********************************************************************
1857 * SetFilePointer (KERNEL32.@)
1859 DWORD WINAPI SetFilePointer( HANDLE hFile, LONG distance, LONG *highword,
1862 DWORD ret = 0xffffffff;
1864 TRACE("handle %d offset %ld high %ld origin %ld\n",
1865 hFile, distance, highword?*highword:0, method );
1867 SERVER_START_REQ( set_file_pointer )
1869 req->handle = hFile;
1870 req->low = distance;
1871 req->high = highword ? *highword : (distance >= 0) ? 0 : -1;
1872 /* FIXME: assumes 1:1 mapping between Windows and Unix seek constants */
1873 req->whence = method;
1875 if (!wine_server_call_err( req ))
1877 ret = reply->new_low;
1878 if (highword) *highword = reply->new_high;
1886 /***********************************************************************
1887 * _llseek (KERNEL.84)
1890 * Seeking before the start of the file should be allowed for _llseek16,
1891 * but cause subsequent I/O operations to fail (cf. interrupt list)
1894 LONG WINAPI _llseek16( HFILE16 hFile, LONG lOffset, INT16 nOrigin )
1896 return SetFilePointer( DosFileHandleToWin32Handle(hFile), lOffset, NULL, nOrigin );
1900 /***********************************************************************
1901 * _llseek (KERNEL32.@)
1903 LONG WINAPI _llseek( HFILE hFile, LONG lOffset, INT nOrigin )
1905 return SetFilePointer( hFile, lOffset, NULL, nOrigin );
1909 /***********************************************************************
1910 * _lopen (KERNEL.85)
1912 HFILE16 WINAPI _lopen16( LPCSTR path, INT16 mode )
1914 return Win32HandleToDosFileHandle( _lopen( path, mode ) );
1918 /***********************************************************************
1919 * _lopen (KERNEL32.@)
1921 HFILE WINAPI _lopen( LPCSTR path, INT mode )
1923 DWORD access, sharing;
1925 TRACE("('%s',%04x)\n", path, mode );
1926 FILE_ConvertOFMode( mode, &access, &sharing );
1927 return CreateFileA( path, access, sharing, NULL, OPEN_EXISTING, 0, 0 );
1931 /***********************************************************************
1932 * _lwrite (KERNEL.86)
1934 UINT16 WINAPI _lwrite16( HFILE16 hFile, LPCSTR buffer, UINT16 count )
1936 return (UINT16)_hwrite( DosFileHandleToWin32Handle(hFile), buffer, (LONG)count );
1939 /***********************************************************************
1940 * _lwrite (KERNEL32.@)
1942 UINT WINAPI _lwrite( HFILE hFile, LPCSTR buffer, UINT count )
1944 return (UINT)_hwrite( hFile, buffer, (LONG)count );
1948 /***********************************************************************
1949 * _hread16 (KERNEL.349)
1951 LONG WINAPI _hread16( HFILE16 hFile, LPVOID buffer, LONG count)
1953 return _lread( DosFileHandleToWin32Handle(hFile), buffer, count );
1957 /***********************************************************************
1958 * _hread (KERNEL32.@)
1960 LONG WINAPI _hread( HFILE hFile, LPVOID buffer, LONG count)
1962 return _lread( hFile, buffer, count );
1966 /***********************************************************************
1967 * _hwrite (KERNEL.350)
1969 LONG WINAPI _hwrite16( HFILE16 hFile, LPCSTR buffer, LONG count )
1971 return _hwrite( DosFileHandleToWin32Handle(hFile), buffer, count );
1975 /***********************************************************************
1976 * _hwrite (KERNEL32.@)
1978 * experimentation yields that _lwrite:
1979 * o truncates the file at the current position with
1981 * o returns 0 on a 0 length write
1982 * o works with console handles
1985 LONG WINAPI _hwrite( HFILE handle, LPCSTR buffer, LONG count )
1989 TRACE("%d %p %ld\n", handle, buffer, count );
1993 /* Expand or truncate at current position */
1994 if (!SetEndOfFile( handle )) return HFILE_ERROR;
1997 if (!WriteFile( handle, buffer, count, &result, NULL ))
2003 /***********************************************************************
2004 * SetHandleCount (KERNEL.199)
2006 UINT16 WINAPI SetHandleCount16( UINT16 count )
2008 return SetHandleCount( count );
2012 /*************************************************************************
2013 * SetHandleCount (KERNEL32.@)
2015 UINT WINAPI SetHandleCount( UINT count )
2017 return min( 256, count );
2021 /***********************************************************************
2022 * FlushFileBuffers (KERNEL32.@)
2024 BOOL WINAPI FlushFileBuffers( HANDLE hFile )
2027 SERVER_START_REQ( flush_file )
2029 req->handle = hFile;
2030 ret = !wine_server_call_err( req );
2037 /**************************************************************************
2038 * SetEndOfFile (KERNEL32.@)
2040 BOOL WINAPI SetEndOfFile( HANDLE hFile )
2043 SERVER_START_REQ( truncate_file )
2045 req->handle = hFile;
2046 ret = !wine_server_call_err( req );
2053 /***********************************************************************
2054 * DeleteFile (KERNEL.146)
2056 BOOL16 WINAPI DeleteFile16( LPCSTR path )
2058 return DeleteFileA( path );
2062 /***********************************************************************
2063 * DeleteFileA (KERNEL32.@)
2065 BOOL WINAPI DeleteFileA( LPCSTR path )
2067 DOS_FULL_NAME full_name;
2071 SetLastError(ERROR_INVALID_PARAMETER);
2074 TRACE("'%s'\n", path );
2078 ERR("Empty path passed\n");
2081 if (DOSFS_GetDevice( path ))
2083 WARN("cannot remove DOS device '%s'!\n", path);
2084 SetLastError( ERROR_FILE_NOT_FOUND );
2088 if (!DOSFS_GetFullName( path, TRUE, &full_name )) return FALSE;
2089 if (unlink( full_name.long_name ) == -1)
2098 /***********************************************************************
2099 * DeleteFileW (KERNEL32.@)
2101 BOOL WINAPI DeleteFileW( LPCWSTR path )
2103 LPSTR xpath = HEAP_strdupWtoA( GetProcessHeap(), 0, path );
2104 BOOL ret = DeleteFileA( xpath );
2105 HeapFree( GetProcessHeap(), 0, xpath );
2110 /***********************************************************************
2111 * GetFileType (KERNEL32.@)
2113 DWORD WINAPI GetFileType( HANDLE hFile )
2115 DWORD ret = FILE_TYPE_UNKNOWN;
2116 SERVER_START_REQ( get_file_info )
2118 req->handle = hFile;
2119 if (!wine_server_call_err( req )) ret = reply->type;
2126 /* check if a file name is for an executable file (.exe or .com) */
2127 inline static BOOL is_executable( const char *name )
2129 int len = strlen(name);
2131 if (len < 4) return FALSE;
2132 return (!strcasecmp( name + len - 4, ".exe" ) ||
2133 !strcasecmp( name + len - 4, ".com" ));
2137 /***********************************************************************
2138 * FILE_AddBootRenameEntry
2140 * Adds an entry to the registry that is loaded when windows boots and
2141 * checks if there are some files to be removed or renamed/moved.
2142 * <fn1> has to be valid and <fn2> may be NULL. If both pointers are
2143 * non-NULL then the file is moved, otherwise it is deleted. The
2144 * entry of the registrykey is always appended with two zero
2145 * terminated strings. If <fn2> is NULL then the second entry is
2146 * simply a single 0-byte. Otherwise the second filename goes
2147 * there. The entries are prepended with \??\ before the path and the
2148 * second filename gets also a '!' as the first character if
2149 * MOVEFILE_REPLACE_EXISTING is set. After the final string another
2150 * 0-byte follows to indicate the end of the strings.
2152 * \??\D:\test\file1[0]
2153 * !\??\D:\test\file1_renamed[0]
2154 * \??\D:\Test|delete[0]
2155 * [0] <- file is to be deleted, second string empty
2156 * \??\D:\test\file2[0]
2157 * !\??\D:\test\file2_renamed[0]
2158 * [0] <- indicates end of strings
2161 * \??\D:\test\file1[0]
2162 * !\??\D:\test\file1_renamed[0]
2163 * \??\D:\Test|delete[0]
2164 * [0] <- file is to be deleted, second string empty
2165 * [0] <- indicates end of strings
2168 static BOOL FILE_AddBootRenameEntry( const char *fn1, const char *fn2, DWORD flags )
2170 static const char PreString[] = "\\??\\";
2171 static const char ValueName[] = "PendingFileRenameOperations";
2175 DWORD Type, len1, len2, l;
2177 BYTE *Buffer = NULL;
2179 if(RegCreateKeyA(HKEY_LOCAL_MACHINE, "SYSTEM\\CurrentControlSet\\Control\\Session Manager",
2180 &Reboot) != ERROR_SUCCESS)
2182 WARN("Error creating key for reboot managment [%s]\n",
2183 "SYSTEM\\CurrentControlSet\\Control\\Session Manager");
2187 l = strlen(PreString);
2188 len1 = strlen(fn1) + l + 1;
2191 len2 = strlen(fn2) + l + 1;
2192 if (flags & MOVEFILE_REPLACE_EXISTING) len2++; /* Plus 1 because of the leading '!' */
2194 else len2 = 1; /* minimum is the 0 byte for the empty second string */
2196 /* First we check if the key exists and if so how many bytes it already contains. */
2197 if (RegQueryValueExA(Reboot, ValueName, NULL, &Type, NULL, &DataSize) == ERROR_SUCCESS)
2199 if (Type != REG_MULTI_SZ) goto Quit;
2200 if (!(Buffer = HeapAlloc( GetProcessHeap(), 0, DataSize + len1 + len2 + 1 ))) goto Quit;
2201 if (RegQueryValueExA(Reboot, ValueName, NULL, &Type, Buffer, &DataSize) != ERROR_SUCCESS)
2203 if (DataSize) DataSize--; /* remove terminating null (will be added back later) */
2207 if (!(Buffer = HeapAlloc( GetProcessHeap(), 0, len1 + len2 + 1 ))) goto Quit;
2210 sprintf( Buffer + DataSize, "%s%s", PreString, fn1 );
2214 sprintf( Buffer + DataSize, "%s%s%s",
2215 (flags & MOVEFILE_REPLACE_EXISTING) ? "!" : "", PreString, fn2 );
2218 else Buffer[DataSize++] = 0;
2220 Buffer[DataSize++] = 0; /* add final null */
2221 rc = !RegSetValueExA( Reboot, ValueName, 0, REG_MULTI_SZ, Buffer, DataSize );
2224 if (Reboot) RegCloseKey(Reboot);
2225 if (Buffer) HeapFree( GetProcessHeap(), 0, Buffer );
2230 /**************************************************************************
2231 * MoveFileExA (KERNEL32.@)
2233 BOOL WINAPI MoveFileExA( LPCSTR fn1, LPCSTR fn2, DWORD flag )
2235 DOS_FULL_NAME full_name1, full_name2;
2237 TRACE("(%s,%s,%04lx)\n", fn1, fn2, flag);
2239 /* FIXME: <Gerhard W. Gruber>sparhawk@gmx.at
2240 In case of W9x and lesser this function should return 120 (ERROR_CALL_NOT_IMPLEMENTED)
2241 to be really compatible. Most programs wont have any problems though. In case
2242 you encounter one, this is what you should return here. I don't know what's up
2243 with NT 3.5. Is this function available there or not?
2244 Does anybody really care about 3.5? :)
2247 /* Filename1 has to be always set to a valid path. Filename2 may be NULL
2248 if the source file has to be deleted.
2251 SetLastError(ERROR_INVALID_PARAMETER);
2255 /* This function has to be run through in order to process the name properly.
2256 If the BOOTDELAY flag is set, the file doesn't need to exist though. At least
2257 that is the behaviour on NT 4.0. The operation accepts the filenames as
2258 they are given but it can't reply with a reasonable returncode. Success
2259 means in that case success for entering the values into the registry.
2261 if(!DOSFS_GetFullName( fn1, TRUE, &full_name1 ))
2263 if(!(flag & MOVEFILE_DELAY_UNTIL_REBOOT))
2267 if (fn2) /* !fn2 means delete fn1 */
2269 if (DOSFS_GetFullName( fn2, TRUE, &full_name2 ))
2271 if(!(flag & MOVEFILE_DELAY_UNTIL_REBOOT))
2273 /* target exists, check if we may overwrite */
2274 if (!(flag & MOVEFILE_REPLACE_EXISTING))
2276 /* FIXME: Use right error code */
2277 SetLastError( ERROR_ACCESS_DENIED );
2284 if (!DOSFS_GetFullName( fn2, FALSE, &full_name2 ))
2286 if(!(flag & MOVEFILE_DELAY_UNTIL_REBOOT))
2291 /* Source name and target path are valid */
2293 if (flag & MOVEFILE_DELAY_UNTIL_REBOOT)
2295 /* FIXME: (bon@elektron.ikp.physik.th-darmstadt.de 970706)
2296 Perhaps we should queue these command and execute it
2297 when exiting... What about using on_exit(2)
2299 FIXME("Please move existing file '%s' to file '%s' when Wine has finished\n",
2301 return FILE_AddBootRenameEntry( fn1, fn2, flag );
2304 if (full_name1.drive != full_name2.drive)
2306 /* use copy, if allowed */
2307 if (!(flag & MOVEFILE_COPY_ALLOWED))
2309 /* FIXME: Use right error code */
2310 SetLastError( ERROR_FILE_EXISTS );
2313 return CopyFileA( fn1, fn2, !(flag & MOVEFILE_REPLACE_EXISTING) );
2315 if (rename( full_name1.long_name, full_name2.long_name ) == -1)
2320 if (is_executable( full_name1.long_name ) != is_executable( full_name2.long_name ))
2323 if (stat( full_name2.long_name, &fstat ) != -1)
2325 if (is_executable( full_name2.long_name ))
2326 /* set executable bit where read bit is set */
2327 fstat.st_mode |= (fstat.st_mode & 0444) >> 2;
2329 fstat.st_mode &= ~0111;
2330 chmod( full_name2.long_name, fstat.st_mode );
2335 else /* fn2 == NULL means delete source */
2337 if (flag & MOVEFILE_DELAY_UNTIL_REBOOT)
2339 if (flag & MOVEFILE_COPY_ALLOWED) {
2340 WARN("Illegal flag\n");
2341 SetLastError( ERROR_GEN_FAILURE );
2344 /* FIXME: (bon@elektron.ikp.physik.th-darmstadt.de 970706)
2345 Perhaps we should queue these command and execute it
2346 when exiting... What about using on_exit(2)
2348 FIXME("Please delete file '%s' when Wine has finished\n", fn1);
2349 return FILE_AddBootRenameEntry( fn1, NULL, flag );
2352 if (unlink( full_name1.long_name ) == -1)
2357 return TRUE; /* successfully deleted */
2361 /**************************************************************************
2362 * MoveFileExW (KERNEL32.@)
2364 BOOL WINAPI MoveFileExW( LPCWSTR fn1, LPCWSTR fn2, DWORD flag )
2366 LPSTR afn1 = HEAP_strdupWtoA( GetProcessHeap(), 0, fn1 );
2367 LPSTR afn2 = HEAP_strdupWtoA( GetProcessHeap(), 0, fn2 );
2368 BOOL res = MoveFileExA( afn1, afn2, flag );
2369 HeapFree( GetProcessHeap(), 0, afn1 );
2370 HeapFree( GetProcessHeap(), 0, afn2 );
2375 /**************************************************************************
2376 * MoveFileA (KERNEL32.@)
2378 * Move file or directory
2380 BOOL WINAPI MoveFileA( LPCSTR fn1, LPCSTR fn2 )
2382 DOS_FULL_NAME full_name1, full_name2;
2385 TRACE("(%s,%s)\n", fn1, fn2 );
2387 if (!DOSFS_GetFullName( fn1, TRUE, &full_name1 )) return FALSE;
2388 if (DOSFS_GetFullName( fn2, TRUE, &full_name2 )) {
2389 /* The new name must not already exist */
2390 SetLastError(ERROR_ALREADY_EXISTS);
2393 if (!DOSFS_GetFullName( fn2, FALSE, &full_name2 )) return FALSE;
2395 if (full_name1.drive == full_name2.drive) /* move */
2396 return MoveFileExA( fn1, fn2, MOVEFILE_COPY_ALLOWED );
2399 if (stat( full_name1.long_name, &fstat ))
2401 WARN("Invalid source file %s\n",
2402 full_name1.long_name);
2406 if (S_ISDIR(fstat.st_mode)) {
2407 /* No Move for directories across file systems */
2408 /* FIXME: Use right error code */
2409 SetLastError( ERROR_GEN_FAILURE );
2412 return CopyFileA(fn1, fn2, TRUE); /*fail, if exist */
2416 /**************************************************************************
2417 * MoveFileW (KERNEL32.@)
2419 BOOL WINAPI MoveFileW( LPCWSTR fn1, LPCWSTR fn2 )
2421 LPSTR afn1 = HEAP_strdupWtoA( GetProcessHeap(), 0, fn1 );
2422 LPSTR afn2 = HEAP_strdupWtoA( GetProcessHeap(), 0, fn2 );
2423 BOOL res = MoveFileA( afn1, afn2 );
2424 HeapFree( GetProcessHeap(), 0, afn1 );
2425 HeapFree( GetProcessHeap(), 0, afn2 );
2430 /**************************************************************************
2431 * CopyFileA (KERNEL32.@)
2433 BOOL WINAPI CopyFileA( LPCSTR source, LPCSTR dest, BOOL fail_if_exists )
2436 BY_HANDLE_FILE_INFORMATION info;
2442 if ((h1 = _lopen( source, OF_READ )) == HFILE_ERROR) return FALSE;
2443 if (!GetFileInformationByHandle( h1, &info ))
2448 mode = (info.dwFileAttributes & FILE_ATTRIBUTE_READONLY) ? 0444 : 0666;
2449 if ((h2 = CreateFileA( dest, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
2450 fail_if_exists ? CREATE_NEW : CREATE_ALWAYS,
2451 info.dwFileAttributes, h1 )) == INVALID_HANDLE_VALUE)
2456 while ((count = _lread( h1, buffer, sizeof(buffer) )) > 0)
2461 INT res = _lwrite( h2, p, count );
2462 if (res <= 0) goto done;
2475 /**************************************************************************
2476 * CopyFileW (KERNEL32.@)
2478 BOOL WINAPI CopyFileW( LPCWSTR source, LPCWSTR dest, BOOL fail_if_exists)
2480 LPSTR sourceA = HEAP_strdupWtoA( GetProcessHeap(), 0, source );
2481 LPSTR destA = HEAP_strdupWtoA( GetProcessHeap(), 0, dest );
2482 BOOL ret = CopyFileA( sourceA, destA, fail_if_exists );
2483 HeapFree( GetProcessHeap(), 0, sourceA );
2484 HeapFree( GetProcessHeap(), 0, destA );
2489 /**************************************************************************
2490 * CopyFileExA (KERNEL32.@)
2492 * This implementation ignores most of the extra parameters passed-in into
2493 * the "ex" version of the method and calls the CopyFile method.
2494 * It will have to be fixed eventually.
2496 BOOL WINAPI CopyFileExA(LPCSTR sourceFilename,
2497 LPCSTR destFilename,
2498 LPPROGRESS_ROUTINE progressRoutine,
2500 LPBOOL cancelFlagPointer,
2503 BOOL failIfExists = FALSE;
2506 * Interpret the only flag that CopyFile can interpret.
2508 if ( (copyFlags & COPY_FILE_FAIL_IF_EXISTS) != 0)
2510 failIfExists = TRUE;
2513 return CopyFileA(sourceFilename, destFilename, failIfExists);
2516 /**************************************************************************
2517 * CopyFileExW (KERNEL32.@)
2519 BOOL WINAPI CopyFileExW(LPCWSTR sourceFilename,
2520 LPCWSTR destFilename,
2521 LPPROGRESS_ROUTINE progressRoutine,
2523 LPBOOL cancelFlagPointer,
2526 LPSTR sourceA = HEAP_strdupWtoA( GetProcessHeap(), 0, sourceFilename );
2527 LPSTR destA = HEAP_strdupWtoA( GetProcessHeap(), 0, destFilename );
2529 BOOL ret = CopyFileExA(sourceA,
2536 HeapFree( GetProcessHeap(), 0, sourceA );
2537 HeapFree( GetProcessHeap(), 0, destA );
2543 /***********************************************************************
2544 * SetFileTime (KERNEL32.@)
2546 BOOL WINAPI SetFileTime( HANDLE hFile,
2547 const FILETIME *lpCreationTime,
2548 const FILETIME *lpLastAccessTime,
2549 const FILETIME *lpLastWriteTime )
2552 SERVER_START_REQ( set_file_time )
2554 req->handle = hFile;
2555 if (lpLastAccessTime)
2556 RtlTimeToSecondsSince1970( lpLastAccessTime, (DWORD *)&req->access_time );
2558 req->access_time = 0; /* FIXME */
2559 if (lpLastWriteTime)
2560 RtlTimeToSecondsSince1970( lpLastWriteTime, (DWORD *)&req->write_time );
2562 req->write_time = 0; /* FIXME */
2563 ret = !wine_server_call_err( req );
2570 /**************************************************************************
2571 * LockFile (KERNEL32.@)
2573 BOOL WINAPI LockFile( HANDLE hFile, DWORD dwFileOffsetLow, DWORD dwFileOffsetHigh,
2574 DWORD nNumberOfBytesToLockLow, DWORD nNumberOfBytesToLockHigh )
2577 SERVER_START_REQ( lock_file )
2579 req->handle = hFile;
2580 req->offset_low = dwFileOffsetLow;
2581 req->offset_high = dwFileOffsetHigh;
2582 req->count_low = nNumberOfBytesToLockLow;
2583 req->count_high = nNumberOfBytesToLockHigh;
2584 ret = !wine_server_call_err( req );
2590 /**************************************************************************
2591 * LockFileEx [KERNEL32.@]
2593 * Locks a byte range within an open file for shared or exclusive access.
2600 * Per Microsoft docs, the third parameter (reserved) must be set to 0.
2602 BOOL WINAPI LockFileEx( HANDLE hFile, DWORD flags, DWORD reserved,
2603 DWORD nNumberOfBytesToLockLow, DWORD nNumberOfBytesToLockHigh,
2604 LPOVERLAPPED pOverlapped )
2606 FIXME("hFile=%d,flags=%ld,reserved=%ld,lowbytes=%ld,highbytes=%ld,overlapped=%p: stub.\n",
2607 hFile, flags, reserved, nNumberOfBytesToLockLow, nNumberOfBytesToLockHigh,
2610 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
2613 ERR("reserved == %ld: Supposed to be 0??\n", reserved);
2614 SetLastError(ERROR_INVALID_PARAMETER);
2621 /**************************************************************************
2622 * UnlockFile (KERNEL32.@)
2624 BOOL WINAPI UnlockFile( HANDLE hFile, DWORD dwFileOffsetLow, DWORD dwFileOffsetHigh,
2625 DWORD nNumberOfBytesToUnlockLow, DWORD nNumberOfBytesToUnlockHigh )
2628 SERVER_START_REQ( unlock_file )
2630 req->handle = hFile;
2631 req->offset_low = dwFileOffsetLow;
2632 req->offset_high = dwFileOffsetHigh;
2633 req->count_low = nNumberOfBytesToUnlockLow;
2634 req->count_high = nNumberOfBytesToUnlockHigh;
2635 ret = !wine_server_call_err( req );
2642 /**************************************************************************
2643 * UnlockFileEx (KERNEL32.@)
2645 BOOL WINAPI UnlockFileEx(
2648 DWORD nNumberOfBytesToUnlockLow,
2649 DWORD nNumberOfBytesToUnlockHigh,
2650 LPOVERLAPPED lpOverlapped
2653 FIXME("hFile=%d,reserved=%ld,lowbytes=%ld,highbytes=%ld,overlapped=%p: stub.\n",
2654 hFile, dwReserved, nNumberOfBytesToUnlockLow, nNumberOfBytesToUnlockHigh,
2656 if (dwReserved == 0)
2657 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
2660 ERR("reserved == %ld: Supposed to be 0??\n", dwReserved);
2661 SetLastError(ERROR_INVALID_PARAMETER);
2670 struct DOS_FILE_LOCK {
2671 struct DOS_FILE_LOCK * next;
2675 FILE_OBJECT * dos_file;
2676 /* char * unix_name;*/
2679 typedef struct DOS_FILE_LOCK DOS_FILE_LOCK;
2681 static DOS_FILE_LOCK *locks = NULL;
2682 static void DOS_RemoveFileLocks(FILE_OBJECT *file);
2685 /* Locks need to be mirrored because unix file locking is based
2686 * on the pid. Inside of wine there can be multiple WINE processes
2687 * that share the same unix pid.
2688 * Read's and writes should check these locks also - not sure
2689 * how critical that is at this point (FIXME).
2692 static BOOL DOS_AddLock(FILE_OBJECT *file, struct flock *f)
2694 DOS_FILE_LOCK *curr;
2697 processId = GetCurrentProcessId();
2699 /* check if lock overlaps a current lock for the same file */
2701 for (curr = locks; curr; curr = curr->next) {
2702 if (strcmp(curr->unix_name, file->unix_name) == 0) {
2703 if ((f->l_start == curr->base) && (f->l_len == curr->len))
2704 return TRUE;/* region is identic */
2705 if ((f->l_start < (curr->base + curr->len)) &&
2706 ((f->l_start + f->l_len) > curr->base)) {
2707 /* region overlaps */
2714 curr = HeapAlloc( GetProcessHeap(), 0, sizeof(DOS_FILE_LOCK) );
2715 curr->processId = GetCurrentProcessId();
2716 curr->base = f->l_start;
2717 curr->len = f->l_len;
2718 /* curr->unix_name = HEAP_strdupA( GetProcessHeap(), 0, file->unix_name);*/
2720 curr->dos_file = file;
2725 static void DOS_RemoveFileLocks(FILE_OBJECT *file)
2728 DOS_FILE_LOCK **curr;
2731 processId = GetCurrentProcessId();
2734 if ((*curr)->dos_file == file) {
2736 *curr = (*curr)->next;
2737 /* HeapFree( GetProcessHeap(), 0, rem->unix_name );*/
2738 HeapFree( GetProcessHeap(), 0, rem );
2741 curr = &(*curr)->next;
2745 static BOOL DOS_RemoveLock(FILE_OBJECT *file, struct flock *f)
2748 DOS_FILE_LOCK **curr;
2751 processId = GetCurrentProcessId();
2752 for (curr = &locks; *curr; curr = &(*curr)->next) {
2753 if ((*curr)->processId == processId &&
2754 (*curr)->dos_file == file &&
2755 (*curr)->base == f->l_start &&
2756 (*curr)->len == f->l_len) {
2757 /* this is the same lock */
2759 *curr = (*curr)->next;
2760 /* HeapFree( GetProcessHeap(), 0, rem->unix_name );*/
2761 HeapFree( GetProcessHeap(), 0, rem );
2765 /* no matching lock found */
2770 /**************************************************************************
2771 * LockFile (KERNEL32.@)
2773 BOOL WINAPI LockFile(
2774 HFILE hFile,DWORD dwFileOffsetLow,DWORD dwFileOffsetHigh,
2775 DWORD nNumberOfBytesToLockLow,DWORD nNumberOfBytesToLockHigh )
2780 TRACE("handle %d offsetlow=%ld offsethigh=%ld nbyteslow=%ld nbyteshigh=%ld\n",
2781 hFile, dwFileOffsetLow, dwFileOffsetHigh,
2782 nNumberOfBytesToLockLow, nNumberOfBytesToLockHigh);
2784 if (dwFileOffsetHigh || nNumberOfBytesToLockHigh) {
2785 FIXME("Unimplemented bytes > 32bits\n");
2789 f.l_start = dwFileOffsetLow;
2790 f.l_len = nNumberOfBytesToLockLow;
2791 f.l_whence = SEEK_SET;
2795 if (!(file = FILE_GetFile(hFile,0,NULL))) return FALSE;
2797 /* shadow locks internally */
2798 if (!DOS_AddLock(file, &f)) {
2799 SetLastError( ERROR_LOCK_VIOLATION );
2803 /* FIXME: Unix locking commented out for now, doesn't work with Excel */
2804 #ifdef USE_UNIX_LOCKS
2805 if (fcntl(file->unix_handle, F_SETLK, &f) == -1) {
2806 if (errno == EACCES || errno == EAGAIN) {
2807 SetLastError( ERROR_LOCK_VIOLATION );
2812 /* remove our internal copy of the lock */
2813 DOS_RemoveLock(file, &f);
2821 /**************************************************************************
2822 * UnlockFile (KERNEL32.@)
2824 BOOL WINAPI UnlockFile(
2825 HFILE hFile,DWORD dwFileOffsetLow,DWORD dwFileOffsetHigh,
2826 DWORD nNumberOfBytesToUnlockLow,DWORD nNumberOfBytesToUnlockHigh )
2831 TRACE("handle %d offsetlow=%ld offsethigh=%ld nbyteslow=%ld nbyteshigh=%ld\n",
2832 hFile, dwFileOffsetLow, dwFileOffsetHigh,
2833 nNumberOfBytesToUnlockLow, nNumberOfBytesToUnlockHigh);
2835 if (dwFileOffsetHigh || nNumberOfBytesToUnlockHigh) {
2836 WARN("Unimplemented bytes > 32bits\n");
2840 f.l_start = dwFileOffsetLow;
2841 f.l_len = nNumberOfBytesToUnlockLow;
2842 f.l_whence = SEEK_SET;
2846 if (!(file = FILE_GetFile(hFile,0,NULL))) return FALSE;
2848 DOS_RemoveLock(file, &f); /* ok if fails - may be another wine */
2850 /* FIXME: Unix locking commented out for now, doesn't work with Excel */
2851 #ifdef USE_UNIX_LOCKS
2852 if (fcntl(file->unix_handle, F_SETLK, &f) == -1) {
2861 /**************************************************************************
2862 * GetFileAttributesExA [KERNEL32.@]
2864 BOOL WINAPI GetFileAttributesExA(
2865 LPCSTR lpFileName, GET_FILEEX_INFO_LEVELS fInfoLevelId,
2866 LPVOID lpFileInformation)
2868 DOS_FULL_NAME full_name;
2869 BY_HANDLE_FILE_INFORMATION info;
2871 if (lpFileName == NULL) return FALSE;
2872 if (lpFileInformation == NULL) return FALSE;
2874 if (fInfoLevelId == GetFileExInfoStandard) {
2875 LPWIN32_FILE_ATTRIBUTE_DATA lpFad =
2876 (LPWIN32_FILE_ATTRIBUTE_DATA) lpFileInformation;
2877 if (!DOSFS_GetFullName( lpFileName, TRUE, &full_name )) return FALSE;
2878 if (!FILE_Stat( full_name.long_name, &info )) return FALSE;
2880 lpFad->dwFileAttributes = info.dwFileAttributes;
2881 lpFad->ftCreationTime = info.ftCreationTime;
2882 lpFad->ftLastAccessTime = info.ftLastAccessTime;
2883 lpFad->ftLastWriteTime = info.ftLastWriteTime;
2884 lpFad->nFileSizeHigh = info.nFileSizeHigh;
2885 lpFad->nFileSizeLow = info.nFileSizeLow;
2888 FIXME("invalid info level %d!\n", fInfoLevelId);
2896 /**************************************************************************
2897 * GetFileAttributesExW [KERNEL32.@]
2899 BOOL WINAPI GetFileAttributesExW(
2900 LPCWSTR lpFileName, GET_FILEEX_INFO_LEVELS fInfoLevelId,
2901 LPVOID lpFileInformation)
2903 LPSTR nameA = HEAP_strdupWtoA( GetProcessHeap(), 0, lpFileName );
2905 GetFileAttributesExA( nameA, fInfoLevelId, lpFileInformation);
2906 HeapFree( GetProcessHeap(), 0, nameA );