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, int *flags )
234 ret = wine_server_handle_to_fd( handle, access, &fd, type, flags );
235 if (ret) SetLastError( RtlNtStatusToDosError(ret) );
239 /***********************************************************************
242 * Retrieve the Unix handle corresponding to a file handle.
243 * Returns -1 on failure.
245 int FILE_GetUnixHandle( HANDLE handle, DWORD access )
247 return FILE_GetUnixHandleType( handle, access, NULL, NULL );
250 /*************************************************************************
253 * Open a handle to the current process console.
254 * Returns 0 on failure.
256 static HANDLE FILE_OpenConsole( BOOL output, DWORD access, DWORD sharing, LPSECURITY_ATTRIBUTES sa )
260 SERVER_START_REQ( open_console )
263 req->access = access;
264 req->share = sharing;
265 req->inherit = (sa && (sa->nLength>=sizeof(*sa)) && sa->bInheritHandle);
267 wine_server_call_err( req );
275 /***********************************************************************
278 * Implementation of CreateFile. Takes a Unix path name.
279 * Returns 0 on failure.
281 HANDLE FILE_CreateFile( LPCSTR filename, DWORD access, DWORD sharing,
282 LPSECURITY_ATTRIBUTES sa, DWORD creation,
283 DWORD attributes, HANDLE template, BOOL fail_read_only,
291 SERVER_START_REQ( create_file )
293 req->access = access;
294 req->inherit = (sa && (sa->nLength>=sizeof(*sa)) && sa->bInheritHandle);
295 req->sharing = sharing;
296 req->create = creation;
297 req->attrs = attributes;
298 req->drive_type = drive_type;
299 wine_server_add_data( req, filename, strlen(filename) );
301 err = wine_server_call( req );
306 /* If write access failed, retry without GENERIC_WRITE */
308 if (!ret && !fail_read_only && (access & GENERIC_WRITE))
310 if ((err == STATUS_MEDIA_WRITE_PROTECTED) || (err == STATUS_ACCESS_DENIED))
312 TRACE("Write access failed for file '%s', trying without "
313 "write access\n", filename);
314 access &= ~GENERIC_WRITE;
319 if (err) SetLastError( RtlNtStatusToDosError(err) );
321 if (!ret) WARN("Unable to create file '%s' (GLE %ld)\n", filename, GetLastError());
327 /***********************************************************************
330 * Same as FILE_CreateFile but for a device
331 * Returns 0 on failure.
333 HANDLE FILE_CreateDevice( int client_id, DWORD access, LPSECURITY_ATTRIBUTES sa )
336 SERVER_START_REQ( create_device )
338 req->access = access;
339 req->inherit = (sa && (sa->nLength>=sizeof(*sa)) && sa->bInheritHandle);
342 wine_server_call_err( req );
349 static HANDLE FILE_OpenPipe(LPCSTR name, DWORD access)
351 WCHAR buffer[MAX_PATH];
355 if (name && !(len = MultiByteToWideChar( CP_ACP, 0, name, strlen(name), buffer, MAX_PATH )))
357 SetLastError( ERROR_FILENAME_EXCED_RANGE );
360 SERVER_START_REQ( open_named_pipe )
362 req->access = access;
364 wine_server_add_data( req, buffer, len * sizeof(WCHAR) );
365 wine_server_call_err( req );
369 TRACE("Returned %d\n",ret);
373 /*************************************************************************
374 * CreateFileA [KERNEL32.@] Creates or opens a file or other object
376 * Creates or opens an object, and returns a handle that can be used to
377 * access that object.
381 * filename [in] pointer to filename to be accessed
382 * access [in] access mode requested
383 * sharing [in] share mode
384 * sa [in] pointer to security attributes
385 * creation [in] how to create the file
386 * attributes [in] attributes for newly created file
387 * template [in] handle to file with extended attributes to copy
390 * Success: Open handle to specified file
391 * Failure: INVALID_HANDLE_VALUE
394 * Should call SetLastError() on failure.
398 * Doesn't support character devices, template files, or a
399 * lot of the 'attributes' flags yet.
401 HANDLE WINAPI CreateFileA( LPCSTR filename, DWORD access, DWORD sharing,
402 LPSECURITY_ATTRIBUTES sa, DWORD creation,
403 DWORD attributes, HANDLE template )
405 DOS_FULL_NAME full_name;
410 SetLastError( ERROR_INVALID_PARAMETER );
411 return INVALID_HANDLE_VALUE;
413 TRACE("%s %s%s%s%s%s%s%s\n",filename,
414 ((access & GENERIC_READ)==GENERIC_READ)?"GENERIC_READ ":"",
415 ((access & GENERIC_WRITE)==GENERIC_WRITE)?"GENERIC_WRITE ":"",
416 (!access)?"QUERY_ACCESS ":"",
417 ((sharing & FILE_SHARE_READ)==FILE_SHARE_READ)?"FILE_SHARE_READ ":"",
418 ((sharing & FILE_SHARE_WRITE)==FILE_SHARE_WRITE)?"FILE_SHARE_WRITE ":"",
419 ((sharing & FILE_SHARE_DELETE)==FILE_SHARE_DELETE)?"FILE_SHARE_DELETE ":"",
420 (creation ==CREATE_NEW)?"CREATE_NEW":
421 (creation ==CREATE_ALWAYS)?"CREATE_ALWAYS ":
422 (creation ==OPEN_EXISTING)?"OPEN_EXISTING ":
423 (creation ==OPEN_ALWAYS)?"OPEN_ALWAYS ":
424 (creation ==TRUNCATE_EXISTING)?"TRUNCATE_EXISTING ":"");
426 /* If the name starts with '\\?\', ignore the first 4 chars. */
427 if (!strncmp(filename, "\\\\?\\", 4))
430 if (!strncmp(filename, "UNC\\", 4))
432 FIXME("UNC name (%s) not supported.\n", filename );
433 SetLastError( ERROR_PATH_NOT_FOUND );
434 return INVALID_HANDLE_VALUE;
438 if (!strncmp(filename, "\\\\.\\", 4)) {
439 if(!strncasecmp(&filename[4],"pipe\\",5))
441 TRACE("Opening a pipe: %s\n",filename);
442 ret = FILE_OpenPipe(filename,access);
445 else if (isalpha(filename[4]) && filename[5] == ':' && filename[6] == '\0')
447 ret = FILE_CreateDevice( (toupper(filename[4]) - 'A') | 0x20000, access, sa );
450 else if (!DOSFS_GetDevice( filename ))
452 ret = DEVICE_Open( filename+4, access, sa );
456 filename+=4; /* fall into DOSFS_Device case below */
459 /* If the name still starts with '\\', it's a UNC name. */
460 if (!strncmp(filename, "\\\\", 2))
462 ret = SMB_CreateFileA(filename, access, sharing, sa, creation, attributes, template );
466 /* If the name contains a DOS wild card (* or ?), do no create a file */
467 if(strchr(filename,'*') || strchr(filename,'?'))
468 return INVALID_HANDLE_VALUE;
470 /* Open a console for CONIN$ or CONOUT$ */
471 if (!strcasecmp(filename, "CONIN$"))
473 ret = FILE_OpenConsole( FALSE, access, sharing, sa );
476 if (!strcasecmp(filename, "CONOUT$"))
478 ret = FILE_OpenConsole( TRUE, access, sharing, sa );
482 if (DOSFS_GetDevice( filename ))
484 TRACE("opening device '%s'\n", filename );
486 if (!(ret = DOSFS_OpenDevice( filename, access, attributes, sa )))
488 /* Do not silence this please. It is a critical error. -MM */
489 ERR("Couldn't open device '%s'!\n",filename);
490 SetLastError( ERROR_FILE_NOT_FOUND );
495 /* check for filename, don't check for last entry if creating */
496 if (!DOSFS_GetFullName( filename,
497 (creation == OPEN_EXISTING) ||
498 (creation == TRUNCATE_EXISTING),
500 WARN("Unable to get full filename from '%s' (GLE %ld)\n",
501 filename, GetLastError());
502 return INVALID_HANDLE_VALUE;
505 ret = FILE_CreateFile( full_name.long_name, access, sharing,
506 sa, creation, attributes, template,
507 DRIVE_GetFlags(full_name.drive) & DRIVE_FAIL_READ_ONLY,
508 GetDriveTypeA( full_name.short_name ) );
510 if (!ret) ret = INVALID_HANDLE_VALUE;
516 /*************************************************************************
517 * CreateFileW (KERNEL32.@)
519 HANDLE WINAPI CreateFileW( LPCWSTR filename, DWORD access, DWORD sharing,
520 LPSECURITY_ATTRIBUTES sa, DWORD creation,
521 DWORD attributes, HANDLE template)
523 LPSTR afn = HEAP_strdupWtoA( GetProcessHeap(), 0, filename );
524 HANDLE res = CreateFileA( afn, access, sharing, sa, creation, attributes, template );
525 HeapFree( GetProcessHeap(), 0, afn );
530 /***********************************************************************
533 * Fill a file information from a struct stat.
535 static void FILE_FillInfo( struct stat *st, BY_HANDLE_FILE_INFORMATION *info )
537 if (S_ISDIR(st->st_mode))
538 info->dwFileAttributes = FILE_ATTRIBUTE_DIRECTORY;
540 info->dwFileAttributes = FILE_ATTRIBUTE_ARCHIVE;
541 if (!(st->st_mode & S_IWUSR))
542 info->dwFileAttributes |= FILE_ATTRIBUTE_READONLY;
544 RtlSecondsSince1970ToTime( st->st_mtime, &info->ftCreationTime );
545 RtlSecondsSince1970ToTime( st->st_mtime, &info->ftLastWriteTime );
546 RtlSecondsSince1970ToTime( st->st_atime, &info->ftLastAccessTime );
548 info->dwVolumeSerialNumber = 0; /* FIXME */
549 info->nFileSizeHigh = 0;
550 info->nFileSizeLow = 0;
551 if (!S_ISDIR(st->st_mode)) {
552 info->nFileSizeHigh = st->st_size >> 32;
553 info->nFileSizeLow = st->st_size & 0xffffffff;
555 info->nNumberOfLinks = st->st_nlink;
556 info->nFileIndexHigh = 0;
557 info->nFileIndexLow = st->st_ino;
561 /***********************************************************************
564 * Stat a Unix path name. Return TRUE if OK.
566 BOOL FILE_Stat( LPCSTR unixName, BY_HANDLE_FILE_INFORMATION *info )
570 if (lstat( unixName, &st ) == -1)
575 if (!S_ISLNK(st.st_mode)) FILE_FillInfo( &st, info );
578 /* do a "real" stat to find out
579 about the type of the symlink destination */
580 if (stat( unixName, &st ) == -1)
585 FILE_FillInfo( &st, info );
586 info->dwFileAttributes |= FILE_ATTRIBUTE_SYMLINK;
592 /***********************************************************************
593 * GetFileInformationByHandle (KERNEL32.@)
595 DWORD WINAPI GetFileInformationByHandle( HANDLE hFile,
596 BY_HANDLE_FILE_INFORMATION *info )
601 SERVER_START_REQ( get_file_info )
604 if ((ret = !wine_server_call_err( req )))
606 /* FIXME: which file types are supported ?
607 * Serial ports (FILE_TYPE_CHAR) are not,
608 * and MSDN also says that pipes are not supported.
609 * FILE_TYPE_REMOTE seems to be supported according to
610 * MSDN q234741.txt */
611 if ((reply->type == FILE_TYPE_DISK) || (reply->type == FILE_TYPE_REMOTE))
613 RtlSecondsSince1970ToTime( reply->write_time, &info->ftCreationTime );
614 RtlSecondsSince1970ToTime( reply->write_time, &info->ftLastWriteTime );
615 RtlSecondsSince1970ToTime( reply->access_time, &info->ftLastAccessTime );
616 info->dwFileAttributes = reply->attr;
617 info->dwVolumeSerialNumber = reply->serial;
618 info->nFileSizeHigh = reply->size_high;
619 info->nFileSizeLow = reply->size_low;
620 info->nNumberOfLinks = reply->links;
621 info->nFileIndexHigh = reply->index_high;
622 info->nFileIndexLow = reply->index_low;
626 SetLastError(ERROR_NOT_SUPPORTED);
636 /**************************************************************************
637 * GetFileAttributes (KERNEL.420)
639 DWORD WINAPI GetFileAttributes16( LPCSTR name )
641 return GetFileAttributesA( name );
645 /**************************************************************************
646 * GetFileAttributesA (KERNEL32.@)
648 DWORD WINAPI GetFileAttributesA( LPCSTR name )
650 DOS_FULL_NAME full_name;
651 BY_HANDLE_FILE_INFORMATION info;
655 SetLastError( ERROR_INVALID_PARAMETER );
658 if (!DOSFS_GetFullName( name, TRUE, &full_name) )
660 if (!FILE_Stat( full_name.long_name, &info )) return -1;
661 return info.dwFileAttributes;
665 /**************************************************************************
666 * GetFileAttributesW (KERNEL32.@)
668 DWORD WINAPI GetFileAttributesW( LPCWSTR name )
670 LPSTR nameA = HEAP_strdupWtoA( GetProcessHeap(), 0, name );
671 DWORD res = GetFileAttributesA( nameA );
672 HeapFree( GetProcessHeap(), 0, nameA );
677 /***********************************************************************
678 * GetFileSize (KERNEL32.@)
680 DWORD WINAPI GetFileSize( HANDLE hFile, LPDWORD filesizehigh )
682 BY_HANDLE_FILE_INFORMATION info;
683 if (!GetFileInformationByHandle( hFile, &info )) return -1;
684 if (filesizehigh) *filesizehigh = info.nFileSizeHigh;
685 return info.nFileSizeLow;
689 /***********************************************************************
690 * GetFileTime (KERNEL32.@)
692 BOOL WINAPI GetFileTime( HANDLE hFile, FILETIME *lpCreationTime,
693 FILETIME *lpLastAccessTime,
694 FILETIME *lpLastWriteTime )
696 BY_HANDLE_FILE_INFORMATION info;
697 if (!GetFileInformationByHandle( hFile, &info )) return FALSE;
698 if (lpCreationTime) *lpCreationTime = info.ftCreationTime;
699 if (lpLastAccessTime) *lpLastAccessTime = info.ftLastAccessTime;
700 if (lpLastWriteTime) *lpLastWriteTime = info.ftLastWriteTime;
704 /***********************************************************************
705 * CompareFileTime (KERNEL32.@)
707 INT WINAPI CompareFileTime( LPFILETIME x, LPFILETIME y )
709 if (!x || !y) return -1;
711 if (x->dwHighDateTime > y->dwHighDateTime)
713 if (x->dwHighDateTime < y->dwHighDateTime)
715 if (x->dwLowDateTime > y->dwLowDateTime)
717 if (x->dwLowDateTime < y->dwLowDateTime)
722 /***********************************************************************
723 * FILE_GetTempFileName : utility for GetTempFileName
725 static UINT FILE_GetTempFileName( LPCSTR path, LPCSTR prefix, UINT unique,
726 LPSTR buffer, BOOL isWin16 )
728 static UINT unique_temp;
729 DOS_FULL_NAME full_name;
734 if ( !path || !prefix || !buffer ) return 0;
736 if (!unique_temp) unique_temp = time(NULL) & 0xffff;
737 num = unique ? (unique & 0xffff) : (unique_temp++ & 0xffff);
739 strcpy( buffer, path );
740 p = buffer + strlen(buffer);
742 /* add a \, if there isn't one and path is more than just the drive letter ... */
743 if ( !((strlen(buffer) == 2) && (buffer[1] == ':'))
744 && ((p == buffer) || (p[-1] != '\\'))) *p++ = '\\';
746 if (isWin16) *p++ = '~';
747 for (i = 3; (i > 0) && (*prefix); i--) *p++ = *prefix++;
748 sprintf( p, "%04x.tmp", num );
750 /* Now try to create it */
756 HFILE handle = CreateFileA( buffer, GENERIC_WRITE, 0, NULL,
757 CREATE_NEW, FILE_ATTRIBUTE_NORMAL, 0 );
758 if (handle != INVALID_HANDLE_VALUE)
759 { /* We created it */
760 TRACE("created %s\n",
762 CloseHandle( handle );
765 if (GetLastError() != ERROR_FILE_EXISTS)
766 break; /* No need to go on */
768 sprintf( p, "%04x.tmp", num );
769 } while (num != (unique & 0xffff));
772 /* Get the full path name */
774 if (DOSFS_GetFullName( buffer, FALSE, &full_name ))
776 /* Check if we have write access in the directory */
777 if ((p = strrchr( full_name.long_name, '/' ))) *p = '\0';
778 if (access( full_name.long_name, W_OK ) == -1)
779 WARN("returns '%s', which doesn't seem to be writeable.\n",
782 TRACE("returning %s\n", buffer );
783 return unique ? unique : num;
787 /***********************************************************************
788 * GetTempFileNameA (KERNEL32.@)
790 UINT WINAPI GetTempFileNameA( LPCSTR path, LPCSTR prefix, UINT unique,
793 return FILE_GetTempFileName(path, prefix, unique, buffer, FALSE);
796 /***********************************************************************
797 * GetTempFileNameW (KERNEL32.@)
799 UINT WINAPI GetTempFileNameW( LPCWSTR path, LPCWSTR prefix, UINT unique,
807 patha = HEAP_strdupWtoA( GetProcessHeap(), 0, path );
808 prefixa = HEAP_strdupWtoA( GetProcessHeap(), 0, prefix );
809 ret = FILE_GetTempFileName( patha, prefixa, unique, buffera, FALSE );
810 MultiByteToWideChar( CP_ACP, 0, buffera, -1, buffer, MAX_PATH );
811 HeapFree( GetProcessHeap(), 0, patha );
812 HeapFree( GetProcessHeap(), 0, prefixa );
817 /***********************************************************************
818 * GetTempFileName (KERNEL.97)
820 UINT16 WINAPI GetTempFileName16( BYTE drive, LPCSTR prefix, UINT16 unique,
825 if (!(drive & ~TF_FORCEDRIVE)) /* drive 0 means current default drive */
826 drive |= DRIVE_GetCurrentDrive() + 'A';
828 if ((drive & TF_FORCEDRIVE) &&
829 !DRIVE_IsValid( toupper(drive & ~TF_FORCEDRIVE) - 'A' ))
831 drive &= ~TF_FORCEDRIVE;
832 WARN("invalid drive %d specified\n", drive );
835 if (drive & TF_FORCEDRIVE)
836 sprintf(temppath,"%c:", drive & ~TF_FORCEDRIVE );
838 GetTempPathA( 132, temppath );
839 return (UINT16)FILE_GetTempFileName( temppath, prefix, unique, buffer, TRUE );
842 /***********************************************************************
845 * Implementation of OpenFile16() and OpenFile32().
847 static HFILE FILE_DoOpenFile( LPCSTR name, OFSTRUCT *ofs, UINT mode,
852 WORD filedatetime[2];
853 DOS_FULL_NAME full_name;
854 DWORD access, sharing;
857 if (!ofs) return HFILE_ERROR;
859 TRACE("%s %s %s %s%s%s%s%s%s%s%s%s\n",name,
860 ((mode & 0x3 )==OF_READ)?"OF_READ":
861 ((mode & 0x3 )==OF_WRITE)?"OF_WRITE":
862 ((mode & 0x3 )==OF_READWRITE)?"OF_READWRITE":"unknown",
863 ((mode & 0x70 )==OF_SHARE_COMPAT)?"OF_SHARE_COMPAT":
864 ((mode & 0x70 )==OF_SHARE_DENY_NONE)?"OF_SHARE_DENY_NONE":
865 ((mode & 0x70 )==OF_SHARE_DENY_READ)?"OF_SHARE_DENY_READ":
866 ((mode & 0x70 )==OF_SHARE_DENY_WRITE)?"OF_SHARE_DENY_WRITE":
867 ((mode & 0x70 )==OF_SHARE_EXCLUSIVE)?"OF_SHARE_EXCLUSIVE":"unknown",
868 ((mode & OF_PARSE )==OF_PARSE)?"OF_PARSE ":"",
869 ((mode & OF_DELETE )==OF_DELETE)?"OF_DELETE ":"",
870 ((mode & OF_VERIFY )==OF_VERIFY)?"OF_VERIFY ":"",
871 ((mode & OF_SEARCH )==OF_SEARCH)?"OF_SEARCH ":"",
872 ((mode & OF_CANCEL )==OF_CANCEL)?"OF_CANCEL ":"",
873 ((mode & OF_CREATE )==OF_CREATE)?"OF_CREATE ":"",
874 ((mode & OF_PROMPT )==OF_PROMPT)?"OF_PROMPT ":"",
875 ((mode & OF_EXIST )==OF_EXIST)?"OF_EXIST ":"",
876 ((mode & OF_REOPEN )==OF_REOPEN)?"OF_REOPEN ":""
880 ofs->cBytes = sizeof(OFSTRUCT);
882 if (mode & OF_REOPEN) name = ofs->szPathName;
885 ERR("called with `name' set to NULL ! Please debug.\n");
889 TRACE("%s %04x\n", name, mode );
891 /* the watcom 10.6 IDE relies on a valid path returned in ofs->szPathName
892 Are there any cases where getting the path here is wrong?
893 Uwe Bonnes 1997 Apr 2 */
894 if (!GetFullPathNameA( name, sizeof(ofs->szPathName),
895 ofs->szPathName, NULL )) goto error;
896 FILE_ConvertOFMode( mode, &access, &sharing );
898 /* OF_PARSE simply fills the structure */
902 ofs->fFixedDisk = (GetDriveType16( ofs->szPathName[0]-'A' )
904 TRACE("(%s): OF_PARSE, res = '%s'\n",
905 name, ofs->szPathName );
909 /* OF_CREATE is completely different from all other options, so
912 if (mode & OF_CREATE)
914 if ((hFileRet = CreateFileA( name, GENERIC_READ | GENERIC_WRITE,
915 sharing, NULL, CREATE_ALWAYS,
916 FILE_ATTRIBUTE_NORMAL, 0 ))== INVALID_HANDLE_VALUE)
921 /* If OF_SEARCH is set, ignore the given path */
923 if ((mode & OF_SEARCH) && !(mode & OF_REOPEN))
925 /* First try the file name as is */
926 if (DOSFS_GetFullName( name, TRUE, &full_name )) goto found;
927 /* Now remove the path */
928 if (name[0] && (name[1] == ':')) name += 2;
929 if ((p = strrchr( name, '\\' ))) name = p + 1;
930 if ((p = strrchr( name, '/' ))) name = p + 1;
931 if (!name[0]) goto not_found;
934 /* Now look for the file */
936 if (!DIR_SearchPath( NULL, name, NULL, &full_name, win32 )) goto not_found;
939 TRACE("found %s = %s\n",
940 full_name.long_name, full_name.short_name );
941 lstrcpynA( ofs->szPathName, full_name.short_name,
942 sizeof(ofs->szPathName) );
944 if (mode & OF_SHARE_EXCLUSIVE)
945 /* Some InstallShield version uses OF_SHARE_EXCLUSIVE
946 on the file <tempdir>/_ins0432._mp to determine how
947 far installation has proceeded.
948 _ins0432._mp is an executable and while running the
949 application expects the open with OF_SHARE_ to fail*/
951 As our loader closes the files after loading the executable,
952 we can't find the running executable with FILE_InUse.
953 The loader should keep the file open, as Windows does that, too.
956 char *last = strrchr(full_name.long_name,'/');
958 last = full_name.long_name - 1;
959 if (GetModuleHandle16(last+1))
961 TRACE("Denying shared open for %s\n",full_name.long_name);
966 if (mode & OF_DELETE)
968 if (unlink( full_name.long_name ) == -1) goto not_found;
969 TRACE("(%s): OF_DELETE return = OK\n", name);
973 hFileRet = FILE_CreateFile( full_name.long_name, access, sharing,
974 NULL, OPEN_EXISTING, 0, 0,
975 DRIVE_GetFlags(full_name.drive) & DRIVE_FAIL_READ_ONLY,
976 GetDriveTypeA( full_name.short_name ) );
977 if (!hFileRet) goto not_found;
979 GetFileTime( hFileRet, NULL, NULL, &filetime );
980 FileTimeToDosDateTime( &filetime, &filedatetime[0], &filedatetime[1] );
981 if ((mode & OF_VERIFY) && (mode & OF_REOPEN))
983 if (memcmp( ofs->reserved, filedatetime, sizeof(ofs->reserved) ))
985 CloseHandle( hFileRet );
986 WARN("(%s): OF_VERIFY failed\n", name );
987 /* FIXME: what error here? */
988 SetLastError( ERROR_FILE_NOT_FOUND );
992 memcpy( ofs->reserved, filedatetime, sizeof(ofs->reserved) );
994 success: /* We get here if the open was successful */
995 TRACE("(%s): OK, return = %d\n", name, hFileRet );
998 if (mode & OF_EXIST) /* Return the handle, but close it first */
999 CloseHandle( hFileRet );
1003 hFileRet = Win32HandleToDosFileHandle( hFileRet );
1004 if (hFileRet == HFILE_ERROR16) goto error;
1005 if (mode & OF_EXIST) /* Return the handle, but close it first */
1006 _lclose16( hFileRet );
1010 not_found: /* We get here if the file does not exist */
1011 WARN("'%s' not found or sharing violation\n", name );
1012 SetLastError( ERROR_FILE_NOT_FOUND );
1015 error: /* We get here if there was an error opening the file */
1016 ofs->nErrCode = GetLastError();
1017 WARN("(%s): return = HFILE_ERROR error= %d\n",
1018 name,ofs->nErrCode );
1023 /***********************************************************************
1024 * OpenFile (KERNEL.74)
1025 * OpenFileEx (KERNEL.360)
1027 HFILE16 WINAPI OpenFile16( LPCSTR name, OFSTRUCT *ofs, UINT16 mode )
1029 return FILE_DoOpenFile( name, ofs, mode, FALSE );
1033 /***********************************************************************
1034 * OpenFile (KERNEL32.@)
1036 HFILE WINAPI OpenFile( LPCSTR name, OFSTRUCT *ofs, UINT mode )
1038 return FILE_DoOpenFile( name, ofs, mode, TRUE );
1042 /***********************************************************************
1043 * FILE_InitProcessDosHandles
1045 * Allocates the default DOS handles for a process. Called either by
1046 * Win32HandleToDosFileHandle below or by the DOSVM stuff.
1048 static void FILE_InitProcessDosHandles( void )
1050 dos_handles[0] = GetStdHandle(STD_INPUT_HANDLE);
1051 dos_handles[1] = GetStdHandle(STD_OUTPUT_HANDLE);
1052 dos_handles[2] = GetStdHandle(STD_ERROR_HANDLE);
1053 dos_handles[3] = GetStdHandle(STD_ERROR_HANDLE);
1054 dos_handles[4] = GetStdHandle(STD_ERROR_HANDLE);
1057 /***********************************************************************
1058 * Win32HandleToDosFileHandle (KERNEL32.21)
1060 * Allocate a DOS handle for a Win32 handle. The Win32 handle is no
1061 * longer valid after this function (even on failure).
1063 * Note: this is not exactly right, since on Win95 the Win32 handles
1064 * are on top of DOS handles and we do it the other way
1065 * around. Should be good enough though.
1067 HFILE WINAPI Win32HandleToDosFileHandle( HANDLE handle )
1071 if (!handle || (handle == INVALID_HANDLE_VALUE))
1074 for (i = 5; i < DOS_TABLE_SIZE; i++)
1075 if (!dos_handles[i])
1077 dos_handles[i] = handle;
1078 TRACE("Got %d for h32 %d\n", i, handle );
1081 CloseHandle( handle );
1082 SetLastError( ERROR_TOO_MANY_OPEN_FILES );
1087 /***********************************************************************
1088 * DosFileHandleToWin32Handle (KERNEL32.20)
1090 * Return the Win32 handle for a DOS handle.
1092 * Note: this is not exactly right, since on Win95 the Win32 handles
1093 * are on top of DOS handles and we do it the other way
1094 * around. Should be good enough though.
1096 HANDLE WINAPI DosFileHandleToWin32Handle( HFILE handle )
1098 HFILE16 hfile = (HFILE16)handle;
1099 if (hfile < 5 && !dos_handles[hfile]) FILE_InitProcessDosHandles();
1100 if ((hfile >= DOS_TABLE_SIZE) || !dos_handles[hfile])
1102 SetLastError( ERROR_INVALID_HANDLE );
1103 return INVALID_HANDLE_VALUE;
1105 return dos_handles[hfile];
1109 /***********************************************************************
1110 * DisposeLZ32Handle (KERNEL32.22)
1112 * Note: this is not entirely correct, we should only close the
1113 * 32-bit handle and not the 16-bit one, but we cannot do
1114 * this because of the way our DOS handles are implemented.
1115 * It shouldn't break anything though.
1117 void WINAPI DisposeLZ32Handle( HANDLE handle )
1121 if (!handle || (handle == INVALID_HANDLE_VALUE)) return;
1123 for (i = 5; i < DOS_TABLE_SIZE; i++)
1124 if (dos_handles[i] == handle)
1127 CloseHandle( handle );
1133 /***********************************************************************
1136 * dup2() function for DOS handles.
1138 HFILE16 FILE_Dup2( HFILE16 hFile1, HFILE16 hFile2 )
1142 if (hFile1 < 5 && !dos_handles[hFile1]) FILE_InitProcessDosHandles();
1144 if ((hFile1 >= DOS_TABLE_SIZE) || (hFile2 >= DOS_TABLE_SIZE) || !dos_handles[hFile1])
1146 SetLastError( ERROR_INVALID_HANDLE );
1147 return HFILE_ERROR16;
1151 FIXME("stdio handle closed, need proper conversion\n" );
1152 SetLastError( ERROR_INVALID_HANDLE );
1153 return HFILE_ERROR16;
1155 if (!DuplicateHandle( GetCurrentProcess(), dos_handles[hFile1],
1156 GetCurrentProcess(), &new_handle,
1157 0, FALSE, DUPLICATE_SAME_ACCESS ))
1158 return HFILE_ERROR16;
1159 if (dos_handles[hFile2]) CloseHandle( dos_handles[hFile2] );
1160 dos_handles[hFile2] = new_handle;
1165 /***********************************************************************
1166 * _lclose (KERNEL.81)
1168 HFILE16 WINAPI _lclose16( HFILE16 hFile )
1172 FIXME("stdio handle closed, need proper conversion\n" );
1173 SetLastError( ERROR_INVALID_HANDLE );
1174 return HFILE_ERROR16;
1176 if ((hFile >= DOS_TABLE_SIZE) || !dos_handles[hFile])
1178 SetLastError( ERROR_INVALID_HANDLE );
1179 return HFILE_ERROR16;
1181 TRACE("%d (handle32=%d)\n", hFile, dos_handles[hFile] );
1182 CloseHandle( dos_handles[hFile] );
1183 dos_handles[hFile] = 0;
1188 /***********************************************************************
1189 * _lclose (KERNEL32.@)
1191 HFILE WINAPI _lclose( HFILE hFile )
1193 TRACE("handle %d\n", hFile );
1194 return CloseHandle( hFile ) ? 0 : HFILE_ERROR;
1197 /***********************************************************************
1198 * GetOverlappedResult (KERNEL32.@)
1200 * Check the result of an Asynchronous data transfer from a file.
1206 * If successful (and relevant) lpTransferred will hold the number of
1207 * bytes transferred during the async operation.
1211 * Currently only works for WaitCommEvent, ReadFile, WriteFile
1212 * with communications ports.
1215 BOOL WINAPI GetOverlappedResult(
1216 HANDLE hFile, /* [in] handle of file to check on */
1217 LPOVERLAPPED lpOverlapped, /* [in/out] pointer to overlapped */
1218 LPDWORD lpTransferred, /* [in/out] number of bytes transferred */
1219 BOOL bWait /* [in] wait for the transfer to complete ? */
1223 TRACE("(%d %p %p %x)\n", hFile, lpOverlapped, lpTransferred, bWait);
1225 if(lpOverlapped==NULL)
1227 ERR("lpOverlapped was null\n");
1230 if(!lpOverlapped->hEvent)
1232 ERR("lpOverlapped->hEvent was null\n");
1237 TRACE("waiting on %p\n",lpOverlapped);
1238 r = WaitForSingleObjectEx(lpOverlapped->hEvent, bWait?INFINITE:0, TRUE);
1239 TRACE("wait on %p returned %ld\n",lpOverlapped,r);
1240 } while (r==STATUS_USER_APC);
1243 *lpTransferred = lpOverlapped->InternalHigh;
1245 SetLastError(lpOverlapped->Internal);
1247 return (r==WAIT_OBJECT_0);
1251 /***********************************************************************
1252 * FILE_StartAsync (INTERNAL)
1254 * type==ASYNC_TYPE_NONE means cancel the indicated overlapped operation
1255 * lpOverlapped==NULL means all overlappeds match
1257 BOOL FILE_StartAsync(HANDLE hFile, LPOVERLAPPED lpOverlapped, DWORD type, DWORD count, DWORD status)
1260 SERVER_START_REQ(register_async)
1262 req->handle = hFile;
1263 req->overlapped = lpOverlapped;
1266 req->func = check_async_list;
1267 req->status = status;
1268 ret = wine_server_call( req );
1274 /***********************************************************************
1275 * CancelIo (KERNEL32.@)
1277 BOOL WINAPI CancelIo(HANDLE handle)
1279 async_private *ovp,*t;
1281 TRACE("handle = %x\n",handle);
1283 ovp = NtCurrentTeb()->pending_list;
1287 if(FILE_StartAsync(handle, ovp->lpOverlapped, ovp->type, 0, STATUS_CANCELLED))
1289 TRACE("overlapped = %p\n",ovp->lpOverlapped);
1290 finish_async(ovp, STATUS_CANCELLED);
1294 WaitForMultipleObjectsEx(0,NULL,FALSE,1,TRUE);
1298 /***********************************************************************
1299 * FILE_AsyncReadService (INTERNAL)
1301 * This function is called while the client is waiting on the
1302 * server, so we can't make any server calls here.
1304 static void FILE_AsyncReadService(async_private *ovp)
1306 LPOVERLAPPED lpOverlapped = ovp->lpOverlapped;
1308 int already = lpOverlapped->InternalHigh;
1310 TRACE("%p %p\n", lpOverlapped, ovp->buffer );
1312 /* check to see if the data is ready (non-blocking) */
1314 result = pread (ovp->fd, &ovp->buffer[already], ovp->count - already,
1315 OVERLAPPED_OFFSET (lpOverlapped) + already);
1316 if ((result < 0) && (errno == ESPIPE))
1317 result = read (ovp->fd, &ovp->buffer[already], ovp->count - already);
1319 if ( (result<0) && ((errno == EAGAIN) || (errno == EINTR)))
1321 TRACE("Deferred read %d\n",errno);
1326 /* check to see if the transfer is complete */
1329 TRACE("read returned errno %d\n",errno);
1330 r = STATUS_UNSUCCESSFUL;
1334 lpOverlapped->InternalHigh += result;
1335 TRACE("read %d more bytes %ld/%d so far\n",result,lpOverlapped->InternalHigh,ovp->count);
1337 if(lpOverlapped->InternalHigh < ovp->count)
1343 lpOverlapped->Internal = r;
1346 /***********************************************************************
1347 * FILE_ReadFileEx (INTERNAL)
1349 static BOOL FILE_ReadFileEx(HANDLE hFile, LPVOID buffer, DWORD bytesToRead,
1350 LPOVERLAPPED overlapped,
1351 LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine,
1357 TRACE("file %d to buf %p num %ld %p func %p\n",
1358 hFile, buffer, bytesToRead, overlapped, lpCompletionRoutine);
1360 /* check that there is an overlapped struct */
1361 if (overlapped==NULL)
1363 SetLastError(ERROR_INVALID_PARAMETER);
1367 fd = FILE_GetUnixHandle( hFile, GENERIC_READ );
1370 TRACE("Couldn't get FD\n");
1374 ovp = (async_private *) HeapAlloc(GetProcessHeap(), 0, sizeof (async_private));
1377 TRACE("HeapAlloc Failed\n");
1378 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1382 ovp->event = hEvent;
1383 ovp->lpOverlapped = overlapped;
1384 ovp->count = bytesToRead;
1385 ovp->completion_func = lpCompletionRoutine;
1386 ovp->func = FILE_AsyncReadService;
1387 ovp->buffer = buffer;
1389 ovp->type = ASYNC_TYPE_READ;
1390 ovp->handle = hFile;
1392 /* hook this overlap into the pending async operation list */
1393 ovp->next = NtCurrentTeb()->pending_list;
1396 ovp->next->prev = ovp;
1397 NtCurrentTeb()->pending_list = ovp;
1399 if ( !FILE_StartAsync(hFile, overlapped, ASYNC_TYPE_READ, bytesToRead, STATUS_PENDING) )
1401 /* FIXME: remove async_private and release memory */
1402 ERR("FILE_StartAsync failed\n");
1409 /***********************************************************************
1410 * ReadFileEx (KERNEL32.@)
1412 BOOL WINAPI ReadFileEx(HANDLE hFile, LPVOID buffer, DWORD bytesToRead,
1413 LPOVERLAPPED overlapped,
1414 LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine)
1416 overlapped->Internal = STATUS_PENDING;
1417 overlapped->InternalHigh = 0;
1418 return FILE_ReadFileEx(hFile,buffer,bytesToRead,overlapped,lpCompletionRoutine, INVALID_HANDLE_VALUE);
1421 static BOOL FILE_TimeoutRead(HANDLE hFile, LPVOID buffer, DWORD bytesToRead, LPDWORD bytesRead)
1426 TRACE("%d %p %ld %p\n", hFile, buffer, bytesToRead, bytesRead );
1428 ZeroMemory(&ov, sizeof (OVERLAPPED));
1429 if(STATUS_SUCCESS==NtCreateEvent(&ov.hEvent, SYNCHRONIZE, NULL, 0, 0))
1431 if(FILE_ReadFileEx(hFile, buffer, bytesToRead, &ov, NULL, ov.hEvent))
1433 r = GetOverlappedResult(hFile, &ov, bytesRead, TRUE);
1436 CloseHandle(ov.hEvent);
1440 /***********************************************************************
1441 * ReadFile (KERNEL32.@)
1443 BOOL WINAPI ReadFile( HANDLE hFile, LPVOID buffer, DWORD bytesToRead,
1444 LPDWORD bytesRead, LPOVERLAPPED overlapped )
1446 int unix_handle, result, flags;
1449 TRACE("%d %p %ld %p %p\n", hFile, buffer, bytesToRead,
1450 bytesRead, overlapped );
1452 if (bytesRead) *bytesRead = 0; /* Do this before anything else */
1453 if (!bytesToRead) return TRUE;
1455 unix_handle = FILE_GetUnixHandleType( hFile, GENERIC_READ, &type, &flags );
1457 if (flags & FD_FLAG_OVERLAPPED)
1459 if (unix_handle == -1) return FALSE;
1460 if ( (overlapped==NULL) || NtResetEvent( overlapped->hEvent, NULL ) )
1462 TRACE("Overlapped not specified or invalid event flag\n");
1464 SetLastError(ERROR_INVALID_PARAMETER);
1468 /* see if we can read some data already (this shouldn't block) */
1469 result = pread( unix_handle, buffer, bytesToRead, OVERLAPPED_OFFSET(overlapped) );
1470 if ((result < 0) && (errno == ESPIPE))
1471 result = read( unix_handle, buffer, bytesToRead );
1476 if( (errno!=EAGAIN) && (errno!=EINTR) &&
1477 ((errno != EFAULT) || IsBadWritePtr( buffer, bytesToRead )) )
1486 /* if we read enough to keep the app happy, then return now */
1487 if(result>=bytesToRead)
1489 *bytesRead = result;
1493 /* at last resort, do an overlapped read */
1494 overlapped->Internal = STATUS_PENDING;
1495 overlapped->InternalHigh = result;
1497 if(!FILE_ReadFileEx(hFile, buffer, bytesToRead, overlapped, NULL, overlapped->hEvent))
1500 /* fail on return, with ERROR_IO_PENDING */
1501 SetLastError(ERROR_IO_PENDING);
1504 if (flags & FD_FLAG_TIMEOUT)
1507 return FILE_TimeoutRead(hFile, buffer, bytesToRead, bytesRead);
1512 return SMB_ReadFile(hFile, buffer, bytesToRead, bytesRead, NULL);
1513 case FD_TYPE_CONSOLE:
1514 return ReadConsoleA(hFile, buffer, bytesToRead, bytesRead, NULL);
1517 /* normal unix files */
1518 if (unix_handle == -1)
1523 SetLastError(ERROR_INVALID_PARAMETER);
1529 /* code for synchronous reads */
1530 while ((result = read( unix_handle, buffer, bytesToRead )) == -1)
1532 if ((errno == EAGAIN) || (errno == EINTR)) continue;
1533 if ((errno == EFAULT) && !IsBadWritePtr( buffer, bytesToRead )) continue;
1537 close( unix_handle );
1538 if (result == -1) return FALSE;
1539 if (bytesRead) *bytesRead = result;
1544 /***********************************************************************
1545 * FILE_AsyncWriteService (INTERNAL)
1547 * This function is called while the client is waiting on the
1548 * server, so we can't make any server calls here.
1550 static void FILE_AsyncWriteService(struct async_private *ovp)
1552 LPOVERLAPPED lpOverlapped = ovp->lpOverlapped;
1554 int already = lpOverlapped->InternalHigh;
1556 TRACE("(%p %p)\n",lpOverlapped,ovp->buffer);
1558 /* write some data (non-blocking) */
1560 result = pwrite(ovp->fd, &ovp->buffer[already], ovp->count - already,
1561 OVERLAPPED_OFFSET (lpOverlapped) + already);
1562 if ((result < 0) && (errno == ESPIPE))
1563 result = write(ovp->fd, &ovp->buffer[already], ovp->count - already);
1565 if ( (result<0) && ((errno == EAGAIN) || (errno == EINTR)))
1571 /* check to see if the transfer is complete */
1574 r = STATUS_UNSUCCESSFUL;
1578 lpOverlapped->InternalHigh += result;
1580 TRACE("wrote %d more bytes %ld/%d so far\n",result,lpOverlapped->InternalHigh,ovp->count);
1582 if(lpOverlapped->InternalHigh < ovp->count)
1588 lpOverlapped->Internal = r;
1591 /***********************************************************************
1594 static BOOL FILE_WriteFileEx(HANDLE hFile, LPCVOID buffer, DWORD bytesToWrite,
1595 LPOVERLAPPED overlapped,
1596 LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine,
1601 TRACE("file %d to buf %p num %ld %p func %p stub\n",
1602 hFile, buffer, bytesToWrite, overlapped, lpCompletionRoutine);
1604 if (overlapped == NULL)
1606 SetLastError(ERROR_INVALID_PARAMETER);
1610 overlapped->Internal = STATUS_PENDING;
1611 overlapped->InternalHigh = 0;
1613 if (!FILE_StartAsync(hFile, overlapped, ASYNC_TYPE_WRITE, bytesToWrite, STATUS_PENDING ))
1615 TRACE("FILE_StartAsync failed\n");
1619 ovp = (async_private*) HeapAlloc(GetProcessHeap(), 0, sizeof (async_private));
1622 TRACE("HeapAlloc Failed\n");
1623 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1626 ovp->lpOverlapped = overlapped;
1627 ovp->event = hEvent;
1628 ovp->func = FILE_AsyncWriteService;
1629 ovp->buffer = (LPVOID) buffer;
1630 ovp->count = bytesToWrite;
1631 ovp->completion_func = lpCompletionRoutine;
1632 ovp->fd = FILE_GetUnixHandle( hFile, GENERIC_WRITE );
1633 ovp->type = ASYNC_TYPE_WRITE;
1634 ovp->handle = hFile;
1638 HeapFree(GetProcessHeap(), 0, ovp);
1642 /* hook this overlap into the pending async operation list */
1643 ovp->next = NtCurrentTeb()->pending_list;
1646 ovp->next->prev = ovp;
1647 NtCurrentTeb()->pending_list = ovp;
1652 /***********************************************************************
1653 * WriteFileEx (KERNEL32.@)
1655 BOOL WINAPI WriteFileEx(HANDLE hFile, LPCVOID buffer, DWORD bytesToWrite,
1656 LPOVERLAPPED overlapped,
1657 LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine)
1659 overlapped->Internal = STATUS_PENDING;
1660 overlapped->InternalHigh = 0;
1662 return FILE_WriteFileEx(hFile, buffer, bytesToWrite, overlapped, lpCompletionRoutine, INVALID_HANDLE_VALUE);
1665 /***********************************************************************
1666 * WriteFile (KERNEL32.@)
1668 BOOL WINAPI WriteFile( HANDLE hFile, LPCVOID buffer, DWORD bytesToWrite,
1669 LPDWORD bytesWritten, LPOVERLAPPED overlapped )
1671 int unix_handle, result, flags;
1674 TRACE("%d %p %ld %p %p\n", hFile, buffer, bytesToWrite,
1675 bytesWritten, overlapped );
1677 if (bytesWritten) *bytesWritten = 0; /* Do this before anything else */
1678 if (!bytesToWrite) return TRUE;
1680 unix_handle = FILE_GetUnixHandleType( hFile, GENERIC_WRITE, &type, &flags );
1682 if (flags & FD_FLAG_OVERLAPPED)
1684 if (unix_handle == -1) return FALSE;
1685 if ( (overlapped==NULL) || NtResetEvent( overlapped->hEvent, NULL ) )
1687 TRACE("Overlapped not specified or invalid event flag\n");
1689 SetLastError(ERROR_INVALID_PARAMETER);
1693 /* see if we can write some data already (this shouldn't block) */
1695 result = pwrite( unix_handle, buffer, bytesToWrite, OVERLAPPED_OFFSET (overlapped) );
1696 if ((result < 0) && (errno == ESPIPE))
1697 result = write( unix_handle, buffer, bytesToWrite );
1703 if( (errno!=EAGAIN) && (errno!=EINTR) &&
1704 ((errno != EFAULT) || IsBadReadPtr( buffer, bytesToWrite )) )
1713 /* if we wrote enough to keep the app happy, then return now */
1714 if(result>=bytesToWrite)
1716 *bytesWritten = result;
1720 /* at last resort, do an overlapped read */
1721 overlapped->Internal = STATUS_PENDING;
1722 overlapped->InternalHigh = result;
1724 if(!FILE_WriteFileEx(hFile, buffer, bytesToWrite, overlapped, NULL, overlapped->hEvent))
1727 /* fail on return, with ERROR_IO_PENDING */
1728 SetLastError(ERROR_IO_PENDING);
1734 case FD_TYPE_CONSOLE:
1735 TRACE("%d %s %ld %p %p\n", hFile, debugstr_an(buffer, bytesToWrite), bytesToWrite,
1736 bytesWritten, overlapped );
1737 return WriteConsoleA(hFile, buffer, bytesToWrite, bytesWritten, NULL);
1739 if (unix_handle == -1)
1743 /* synchronous file write */
1744 while ((result = write( unix_handle, buffer, bytesToWrite )) == -1)
1746 if ((errno == EAGAIN) || (errno == EINTR)) continue;
1747 if ((errno == EFAULT) && !IsBadReadPtr( buffer, bytesToWrite )) continue;
1748 if (errno == ENOSPC)
1749 SetLastError( ERROR_DISK_FULL );
1754 close( unix_handle );
1755 if (result == -1) return FALSE;
1756 if (bytesWritten) *bytesWritten = result;
1761 /***********************************************************************
1762 * _hread (KERNEL.349)
1764 LONG WINAPI WIN16_hread( HFILE16 hFile, SEGPTR buffer, LONG count )
1768 TRACE("%d %08lx %ld\n",
1769 hFile, (DWORD)buffer, count );
1771 /* Some programs pass a count larger than the allocated buffer */
1772 maxlen = GetSelectorLimit16( SELECTOROF(buffer) ) - OFFSETOF(buffer) + 1;
1773 if (count > maxlen) count = maxlen;
1774 return _lread(DosFileHandleToWin32Handle(hFile), MapSL(buffer), count );
1778 /***********************************************************************
1779 * _lread (KERNEL.82)
1781 UINT16 WINAPI WIN16_lread( HFILE16 hFile, SEGPTR buffer, UINT16 count )
1783 return (UINT16)WIN16_hread( hFile, buffer, (LONG)count );
1787 /***********************************************************************
1788 * _lread (KERNEL32.@)
1790 UINT WINAPI _lread( HFILE handle, LPVOID buffer, UINT count )
1793 if (!ReadFile( handle, buffer, count, &result, NULL )) return -1;
1798 /***********************************************************************
1799 * _lread16 (KERNEL.82)
1801 UINT16 WINAPI _lread16( HFILE16 hFile, LPVOID buffer, UINT16 count )
1803 return (UINT16)_lread(DosFileHandleToWin32Handle(hFile), buffer, (LONG)count );
1807 /***********************************************************************
1808 * _lcreat (KERNEL.83)
1810 HFILE16 WINAPI _lcreat16( LPCSTR path, INT16 attr )
1812 return Win32HandleToDosFileHandle( _lcreat( path, attr ) );
1816 /***********************************************************************
1817 * _lcreat (KERNEL32.@)
1819 HFILE WINAPI _lcreat( LPCSTR path, INT attr )
1821 /* Mask off all flags not explicitly allowed by the doc */
1822 attr &= FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM;
1823 TRACE("%s %02x\n", path, attr );
1824 return CreateFileA( path, GENERIC_READ | GENERIC_WRITE,
1825 FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
1826 CREATE_ALWAYS, attr, 0 );
1830 /***********************************************************************
1831 * SetFilePointer (KERNEL32.@)
1833 DWORD WINAPI SetFilePointer( HANDLE hFile, LONG distance, LONG *highword,
1836 DWORD ret = 0xffffffff;
1838 TRACE("handle %d offset %ld high %ld origin %ld\n",
1839 hFile, distance, highword?*highword:0, method );
1841 SERVER_START_REQ( set_file_pointer )
1843 req->handle = hFile;
1844 req->low = distance;
1845 req->high = highword ? *highword : (distance >= 0) ? 0 : -1;
1846 /* FIXME: assumes 1:1 mapping between Windows and Unix seek constants */
1847 req->whence = method;
1849 if (!wine_server_call_err( req ))
1851 ret = reply->new_low;
1852 if (highword) *highword = reply->new_high;
1860 /***********************************************************************
1861 * _llseek (KERNEL.84)
1864 * Seeking before the start of the file should be allowed for _llseek16,
1865 * but cause subsequent I/O operations to fail (cf. interrupt list)
1868 LONG WINAPI _llseek16( HFILE16 hFile, LONG lOffset, INT16 nOrigin )
1870 return SetFilePointer( DosFileHandleToWin32Handle(hFile), lOffset, NULL, nOrigin );
1874 /***********************************************************************
1875 * _llseek (KERNEL32.@)
1877 LONG WINAPI _llseek( HFILE hFile, LONG lOffset, INT nOrigin )
1879 return SetFilePointer( hFile, lOffset, NULL, nOrigin );
1883 /***********************************************************************
1884 * _lopen (KERNEL.85)
1886 HFILE16 WINAPI _lopen16( LPCSTR path, INT16 mode )
1888 return Win32HandleToDosFileHandle( _lopen( path, mode ) );
1892 /***********************************************************************
1893 * _lopen (KERNEL32.@)
1895 HFILE WINAPI _lopen( LPCSTR path, INT mode )
1897 DWORD access, sharing;
1899 TRACE("('%s',%04x)\n", path, mode );
1900 FILE_ConvertOFMode( mode, &access, &sharing );
1901 return CreateFileA( path, access, sharing, NULL, OPEN_EXISTING, 0, 0 );
1905 /***********************************************************************
1906 * _lwrite (KERNEL.86)
1908 UINT16 WINAPI _lwrite16( HFILE16 hFile, LPCSTR buffer, UINT16 count )
1910 return (UINT16)_hwrite( DosFileHandleToWin32Handle(hFile), buffer, (LONG)count );
1913 /***********************************************************************
1914 * _lwrite (KERNEL32.@)
1916 UINT WINAPI _lwrite( HFILE hFile, LPCSTR buffer, UINT count )
1918 return (UINT)_hwrite( hFile, buffer, (LONG)count );
1922 /***********************************************************************
1923 * _hread16 (KERNEL.349)
1925 LONG WINAPI _hread16( HFILE16 hFile, LPVOID buffer, LONG count)
1927 return _lread( DosFileHandleToWin32Handle(hFile), buffer, count );
1931 /***********************************************************************
1932 * _hread (KERNEL32.@)
1934 LONG WINAPI _hread( HFILE hFile, LPVOID buffer, LONG count)
1936 return _lread( hFile, buffer, count );
1940 /***********************************************************************
1941 * _hwrite (KERNEL.350)
1943 LONG WINAPI _hwrite16( HFILE16 hFile, LPCSTR buffer, LONG count )
1945 return _hwrite( DosFileHandleToWin32Handle(hFile), buffer, count );
1949 /***********************************************************************
1950 * _hwrite (KERNEL32.@)
1952 * experimentation yields that _lwrite:
1953 * o truncates the file at the current position with
1955 * o returns 0 on a 0 length write
1956 * o works with console handles
1959 LONG WINAPI _hwrite( HFILE handle, LPCSTR buffer, LONG count )
1963 TRACE("%d %p %ld\n", handle, buffer, count );
1967 /* Expand or truncate at current position */
1968 if (!SetEndOfFile( handle )) return HFILE_ERROR;
1971 if (!WriteFile( handle, buffer, count, &result, NULL ))
1977 /***********************************************************************
1978 * SetHandleCount (KERNEL.199)
1980 UINT16 WINAPI SetHandleCount16( UINT16 count )
1982 return SetHandleCount( count );
1986 /*************************************************************************
1987 * SetHandleCount (KERNEL32.@)
1989 UINT WINAPI SetHandleCount( UINT count )
1991 return min( 256, count );
1995 /***********************************************************************
1996 * FlushFileBuffers (KERNEL32.@)
1998 BOOL WINAPI FlushFileBuffers( HANDLE hFile )
2001 SERVER_START_REQ( flush_file )
2003 req->handle = hFile;
2004 ret = !wine_server_call_err( req );
2011 /**************************************************************************
2012 * SetEndOfFile (KERNEL32.@)
2014 BOOL WINAPI SetEndOfFile( HANDLE hFile )
2017 SERVER_START_REQ( truncate_file )
2019 req->handle = hFile;
2020 ret = !wine_server_call_err( req );
2027 /***********************************************************************
2028 * DeleteFile (KERNEL.146)
2030 BOOL16 WINAPI DeleteFile16( LPCSTR path )
2032 return DeleteFileA( path );
2036 /***********************************************************************
2037 * DeleteFileA (KERNEL32.@)
2039 BOOL WINAPI DeleteFileA( LPCSTR path )
2041 DOS_FULL_NAME full_name;
2045 SetLastError(ERROR_INVALID_PARAMETER);
2048 TRACE("'%s'\n", path );
2052 ERR("Empty path passed\n");
2055 if (DOSFS_GetDevice( path ))
2057 WARN("cannot remove DOS device '%s'!\n", path);
2058 SetLastError( ERROR_FILE_NOT_FOUND );
2062 if (!DOSFS_GetFullName( path, TRUE, &full_name )) return FALSE;
2063 if (unlink( full_name.long_name ) == -1)
2072 /***********************************************************************
2073 * DeleteFileW (KERNEL32.@)
2075 BOOL WINAPI DeleteFileW( LPCWSTR path )
2077 LPSTR xpath = HEAP_strdupWtoA( GetProcessHeap(), 0, path );
2078 BOOL ret = DeleteFileA( xpath );
2079 HeapFree( GetProcessHeap(), 0, xpath );
2084 /***********************************************************************
2085 * GetFileType (KERNEL32.@)
2087 DWORD WINAPI GetFileType( HANDLE hFile )
2089 DWORD ret = FILE_TYPE_UNKNOWN;
2090 SERVER_START_REQ( get_file_info )
2092 req->handle = hFile;
2093 if (!wine_server_call_err( req )) ret = reply->type;
2100 /* check if a file name is for an executable file (.exe or .com) */
2101 inline static BOOL is_executable( const char *name )
2103 int len = strlen(name);
2105 if (len < 4) return FALSE;
2106 return (!strcasecmp( name + len - 4, ".exe" ) ||
2107 !strcasecmp( name + len - 4, ".com" ));
2111 /***********************************************************************
2112 * FILE_AddBootRenameEntry
2114 * Adds an entry to the registry that is loaded when windows boots and
2115 * checks if there are some files to be removed or renamed/moved.
2116 * <fn1> has to be valid and <fn2> may be NULL. If both pointers are
2117 * non-NULL then the file is moved, otherwise it is deleted. The
2118 * entry of the registrykey is always appended with two zero
2119 * terminated strings. If <fn2> is NULL then the second entry is
2120 * simply a single 0-byte. Otherwise the second filename goes
2121 * there. The entries are prepended with \??\ before the path and the
2122 * second filename gets also a '!' as the first character if
2123 * MOVEFILE_REPLACE_EXISTING is set. After the final string another
2124 * 0-byte follows to indicate the end of the strings.
2126 * \??\D:\test\file1[0]
2127 * !\??\D:\test\file1_renamed[0]
2128 * \??\D:\Test|delete[0]
2129 * [0] <- file is to be deleted, second string empty
2130 * \??\D:\test\file2[0]
2131 * !\??\D:\test\file2_renamed[0]
2132 * [0] <- indicates end of strings
2135 * \??\D:\test\file1[0]
2136 * !\??\D:\test\file1_renamed[0]
2137 * \??\D:\Test|delete[0]
2138 * [0] <- file is to be deleted, second string empty
2139 * [0] <- indicates end of strings
2142 static BOOL FILE_AddBootRenameEntry( const char *fn1, const char *fn2, DWORD flags )
2144 static const char PreString[] = "\\??\\";
2145 static const char ValueName[] = "PendingFileRenameOperations";
2149 DWORD Type, len1, len2, l;
2151 BYTE *Buffer = NULL;
2153 if(RegCreateKeyA(HKEY_LOCAL_MACHINE, "SYSTEM\\CurrentControlSet\\Control\\Session Manager",
2154 &Reboot) != ERROR_SUCCESS)
2156 WARN("Error creating key for reboot managment [%s]\n",
2157 "SYSTEM\\CurrentControlSet\\Control\\Session Manager");
2161 l = strlen(PreString);
2162 len1 = strlen(fn1) + l + 1;
2165 len2 = strlen(fn2) + l + 1;
2166 if (flags & MOVEFILE_REPLACE_EXISTING) len2++; /* Plus 1 because of the leading '!' */
2168 else len2 = 1; /* minimum is the 0 byte for the empty second string */
2170 /* First we check if the key exists and if so how many bytes it already contains. */
2171 if (RegQueryValueExA(Reboot, ValueName, NULL, &Type, NULL, &DataSize) == ERROR_SUCCESS)
2173 if (Type != REG_MULTI_SZ) goto Quit;
2174 if (!(Buffer = HeapAlloc( GetProcessHeap(), 0, DataSize + len1 + len2 + 1 ))) goto Quit;
2175 if (RegQueryValueExA(Reboot, ValueName, NULL, &Type, Buffer, &DataSize) != ERROR_SUCCESS)
2177 if (DataSize) DataSize--; /* remove terminating null (will be added back later) */
2181 if (!(Buffer = HeapAlloc( GetProcessHeap(), 0, len1 + len2 + 1 ))) goto Quit;
2184 sprintf( Buffer + DataSize, "%s%s", PreString, fn1 );
2188 sprintf( Buffer + DataSize, "%s%s%s",
2189 (flags & MOVEFILE_REPLACE_EXISTING) ? "!" : "", PreString, fn2 );
2192 else Buffer[DataSize++] = 0;
2194 Buffer[DataSize++] = 0; /* add final null */
2195 rc = !RegSetValueExA( Reboot, ValueName, 0, REG_MULTI_SZ, Buffer, DataSize );
2198 if (Reboot) RegCloseKey(Reboot);
2199 if (Buffer) HeapFree( GetProcessHeap(), 0, Buffer );
2204 /**************************************************************************
2205 * MoveFileExA (KERNEL32.@)
2207 BOOL WINAPI MoveFileExA( LPCSTR fn1, LPCSTR fn2, DWORD flag )
2209 DOS_FULL_NAME full_name1, full_name2;
2211 TRACE("(%s,%s,%04lx)\n", fn1, fn2, flag);
2213 /* FIXME: <Gerhard W. Gruber>sparhawk@gmx.at
2214 In case of W9x and lesser this function should return 120 (ERROR_CALL_NOT_IMPLEMENTED)
2215 to be really compatible. Most programs wont have any problems though. In case
2216 you encounter one, this is what you should return here. I don't know what's up
2217 with NT 3.5. Is this function available there or not?
2218 Does anybody really care about 3.5? :)
2221 /* Filename1 has to be always set to a valid path. Filename2 may be NULL
2222 if the source file has to be deleted.
2225 SetLastError(ERROR_INVALID_PARAMETER);
2229 /* This function has to be run through in order to process the name properly.
2230 If the BOOTDELAY flag is set, the file doesn't need to exist though. At least
2231 that is the behaviour on NT 4.0. The operation accepts the filenames as
2232 they are given but it can't reply with a reasonable returncode. Success
2233 means in that case success for entering the values into the registry.
2235 if(!DOSFS_GetFullName( fn1, TRUE, &full_name1 ))
2237 if(!(flag & MOVEFILE_DELAY_UNTIL_REBOOT))
2241 if (fn2) /* !fn2 means delete fn1 */
2243 if (DOSFS_GetFullName( fn2, TRUE, &full_name2 ))
2245 if(!(flag & MOVEFILE_DELAY_UNTIL_REBOOT))
2247 /* target exists, check if we may overwrite */
2248 if (!(flag & MOVEFILE_REPLACE_EXISTING))
2250 /* FIXME: Use right error code */
2251 SetLastError( ERROR_ACCESS_DENIED );
2258 if (!DOSFS_GetFullName( fn2, FALSE, &full_name2 ))
2260 if(!(flag & MOVEFILE_DELAY_UNTIL_REBOOT))
2265 /* Source name and target path are valid */
2267 if (flag & MOVEFILE_DELAY_UNTIL_REBOOT)
2269 /* FIXME: (bon@elektron.ikp.physik.th-darmstadt.de 970706)
2270 Perhaps we should queue these command and execute it
2271 when exiting... What about using on_exit(2)
2273 FIXME("Please move existing file '%s' to file '%s' when Wine has finished\n",
2275 return FILE_AddBootRenameEntry( fn1, fn2, flag );
2278 if (full_name1.drive != full_name2.drive)
2280 /* use copy, if allowed */
2281 if (!(flag & MOVEFILE_COPY_ALLOWED))
2283 /* FIXME: Use right error code */
2284 SetLastError( ERROR_FILE_EXISTS );
2287 return CopyFileA( fn1, fn2, !(flag & MOVEFILE_REPLACE_EXISTING) );
2289 if (rename( full_name1.long_name, full_name2.long_name ) == -1)
2294 if (is_executable( full_name1.long_name ) != is_executable( full_name2.long_name ))
2297 if (stat( full_name2.long_name, &fstat ) != -1)
2299 if (is_executable( full_name2.long_name ))
2300 /* set executable bit where read bit is set */
2301 fstat.st_mode |= (fstat.st_mode & 0444) >> 2;
2303 fstat.st_mode &= ~0111;
2304 chmod( full_name2.long_name, fstat.st_mode );
2309 else /* fn2 == NULL means delete source */
2311 if (flag & MOVEFILE_DELAY_UNTIL_REBOOT)
2313 if (flag & MOVEFILE_COPY_ALLOWED) {
2314 WARN("Illegal flag\n");
2315 SetLastError( ERROR_GEN_FAILURE );
2318 /* FIXME: (bon@elektron.ikp.physik.th-darmstadt.de 970706)
2319 Perhaps we should queue these command and execute it
2320 when exiting... What about using on_exit(2)
2322 FIXME("Please delete file '%s' when Wine has finished\n", fn1);
2323 return FILE_AddBootRenameEntry( fn1, NULL, flag );
2326 if (unlink( full_name1.long_name ) == -1)
2331 return TRUE; /* successfully deleted */
2335 /**************************************************************************
2336 * MoveFileExW (KERNEL32.@)
2338 BOOL WINAPI MoveFileExW( LPCWSTR fn1, LPCWSTR fn2, DWORD flag )
2340 LPSTR afn1 = HEAP_strdupWtoA( GetProcessHeap(), 0, fn1 );
2341 LPSTR afn2 = HEAP_strdupWtoA( GetProcessHeap(), 0, fn2 );
2342 BOOL res = MoveFileExA( afn1, afn2, flag );
2343 HeapFree( GetProcessHeap(), 0, afn1 );
2344 HeapFree( GetProcessHeap(), 0, afn2 );
2349 /**************************************************************************
2350 * MoveFileA (KERNEL32.@)
2352 * Move file or directory
2354 BOOL WINAPI MoveFileA( LPCSTR fn1, LPCSTR fn2 )
2356 DOS_FULL_NAME full_name1, full_name2;
2359 TRACE("(%s,%s)\n", fn1, fn2 );
2361 if (!DOSFS_GetFullName( fn1, TRUE, &full_name1 )) return FALSE;
2362 if (DOSFS_GetFullName( fn2, TRUE, &full_name2 )) {
2363 /* The new name must not already exist */
2364 SetLastError(ERROR_ALREADY_EXISTS);
2367 if (!DOSFS_GetFullName( fn2, FALSE, &full_name2 )) return FALSE;
2369 if (full_name1.drive == full_name2.drive) /* move */
2370 return MoveFileExA( fn1, fn2, MOVEFILE_COPY_ALLOWED );
2373 if (stat( full_name1.long_name, &fstat ))
2375 WARN("Invalid source file %s\n",
2376 full_name1.long_name);
2380 if (S_ISDIR(fstat.st_mode)) {
2381 /* No Move for directories across file systems */
2382 /* FIXME: Use right error code */
2383 SetLastError( ERROR_GEN_FAILURE );
2386 return CopyFileA(fn1, fn2, TRUE); /*fail, if exist */
2390 /**************************************************************************
2391 * MoveFileW (KERNEL32.@)
2393 BOOL WINAPI MoveFileW( LPCWSTR fn1, LPCWSTR fn2 )
2395 LPSTR afn1 = HEAP_strdupWtoA( GetProcessHeap(), 0, fn1 );
2396 LPSTR afn2 = HEAP_strdupWtoA( GetProcessHeap(), 0, fn2 );
2397 BOOL res = MoveFileA( afn1, afn2 );
2398 HeapFree( GetProcessHeap(), 0, afn1 );
2399 HeapFree( GetProcessHeap(), 0, afn2 );
2404 /**************************************************************************
2405 * CopyFileA (KERNEL32.@)
2407 BOOL WINAPI CopyFileA( LPCSTR source, LPCSTR dest, BOOL fail_if_exists )
2410 BY_HANDLE_FILE_INFORMATION info;
2416 if ((h1 = _lopen( source, OF_READ )) == HFILE_ERROR) return FALSE;
2417 if (!GetFileInformationByHandle( h1, &info ))
2422 mode = (info.dwFileAttributes & FILE_ATTRIBUTE_READONLY) ? 0444 : 0666;
2423 if ((h2 = CreateFileA( dest, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
2424 fail_if_exists ? CREATE_NEW : CREATE_ALWAYS,
2425 info.dwFileAttributes, h1 )) == INVALID_HANDLE_VALUE)
2430 while ((count = _lread( h1, buffer, sizeof(buffer) )) > 0)
2435 INT res = _lwrite( h2, p, count );
2436 if (res <= 0) goto done;
2449 /**************************************************************************
2450 * CopyFileW (KERNEL32.@)
2452 BOOL WINAPI CopyFileW( LPCWSTR source, LPCWSTR dest, BOOL fail_if_exists)
2454 LPSTR sourceA = HEAP_strdupWtoA( GetProcessHeap(), 0, source );
2455 LPSTR destA = HEAP_strdupWtoA( GetProcessHeap(), 0, dest );
2456 BOOL ret = CopyFileA( sourceA, destA, fail_if_exists );
2457 HeapFree( GetProcessHeap(), 0, sourceA );
2458 HeapFree( GetProcessHeap(), 0, destA );
2463 /**************************************************************************
2464 * CopyFileExA (KERNEL32.@)
2466 * This implementation ignores most of the extra parameters passed-in into
2467 * the "ex" version of the method and calls the CopyFile method.
2468 * It will have to be fixed eventually.
2470 BOOL WINAPI CopyFileExA(LPCSTR sourceFilename,
2471 LPCSTR destFilename,
2472 LPPROGRESS_ROUTINE progressRoutine,
2474 LPBOOL cancelFlagPointer,
2477 BOOL failIfExists = FALSE;
2480 * Interpret the only flag that CopyFile can interpret.
2482 if ( (copyFlags & COPY_FILE_FAIL_IF_EXISTS) != 0)
2484 failIfExists = TRUE;
2487 return CopyFileA(sourceFilename, destFilename, failIfExists);
2490 /**************************************************************************
2491 * CopyFileExW (KERNEL32.@)
2493 BOOL WINAPI CopyFileExW(LPCWSTR sourceFilename,
2494 LPCWSTR destFilename,
2495 LPPROGRESS_ROUTINE progressRoutine,
2497 LPBOOL cancelFlagPointer,
2500 LPSTR sourceA = HEAP_strdupWtoA( GetProcessHeap(), 0, sourceFilename );
2501 LPSTR destA = HEAP_strdupWtoA( GetProcessHeap(), 0, destFilename );
2503 BOOL ret = CopyFileExA(sourceA,
2510 HeapFree( GetProcessHeap(), 0, sourceA );
2511 HeapFree( GetProcessHeap(), 0, destA );
2517 /***********************************************************************
2518 * SetFileTime (KERNEL32.@)
2520 BOOL WINAPI SetFileTime( HANDLE hFile,
2521 const FILETIME *lpCreationTime,
2522 const FILETIME *lpLastAccessTime,
2523 const FILETIME *lpLastWriteTime )
2526 SERVER_START_REQ( set_file_time )
2528 req->handle = hFile;
2529 if (lpLastAccessTime)
2530 RtlTimeToSecondsSince1970( lpLastAccessTime, (DWORD *)&req->access_time );
2532 req->access_time = 0; /* FIXME */
2533 if (lpLastWriteTime)
2534 RtlTimeToSecondsSince1970( lpLastWriteTime, (DWORD *)&req->write_time );
2536 req->write_time = 0; /* FIXME */
2537 ret = !wine_server_call_err( req );
2544 /**************************************************************************
2545 * LockFile (KERNEL32.@)
2547 BOOL WINAPI LockFile( HANDLE hFile, DWORD dwFileOffsetLow, DWORD dwFileOffsetHigh,
2548 DWORD nNumberOfBytesToLockLow, DWORD nNumberOfBytesToLockHigh )
2551 SERVER_START_REQ( lock_file )
2553 req->handle = hFile;
2554 req->offset_low = dwFileOffsetLow;
2555 req->offset_high = dwFileOffsetHigh;
2556 req->count_low = nNumberOfBytesToLockLow;
2557 req->count_high = nNumberOfBytesToLockHigh;
2558 ret = !wine_server_call_err( req );
2564 /**************************************************************************
2565 * LockFileEx [KERNEL32.@]
2567 * Locks a byte range within an open file for shared or exclusive access.
2574 * Per Microsoft docs, the third parameter (reserved) must be set to 0.
2576 BOOL WINAPI LockFileEx( HANDLE hFile, DWORD flags, DWORD reserved,
2577 DWORD nNumberOfBytesToLockLow, DWORD nNumberOfBytesToLockHigh,
2578 LPOVERLAPPED pOverlapped )
2580 FIXME("hFile=%d,flags=%ld,reserved=%ld,lowbytes=%ld,highbytes=%ld,overlapped=%p: stub.\n",
2581 hFile, flags, reserved, nNumberOfBytesToLockLow, nNumberOfBytesToLockHigh,
2584 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
2587 ERR("reserved == %ld: Supposed to be 0??\n", reserved);
2588 SetLastError(ERROR_INVALID_PARAMETER);
2595 /**************************************************************************
2596 * UnlockFile (KERNEL32.@)
2598 BOOL WINAPI UnlockFile( HANDLE hFile, DWORD dwFileOffsetLow, DWORD dwFileOffsetHigh,
2599 DWORD nNumberOfBytesToUnlockLow, DWORD nNumberOfBytesToUnlockHigh )
2602 SERVER_START_REQ( unlock_file )
2604 req->handle = hFile;
2605 req->offset_low = dwFileOffsetLow;
2606 req->offset_high = dwFileOffsetHigh;
2607 req->count_low = nNumberOfBytesToUnlockLow;
2608 req->count_high = nNumberOfBytesToUnlockHigh;
2609 ret = !wine_server_call_err( req );
2616 /**************************************************************************
2617 * UnlockFileEx (KERNEL32.@)
2619 BOOL WINAPI UnlockFileEx(
2622 DWORD nNumberOfBytesToUnlockLow,
2623 DWORD nNumberOfBytesToUnlockHigh,
2624 LPOVERLAPPED lpOverlapped
2627 FIXME("hFile=%d,reserved=%ld,lowbytes=%ld,highbytes=%ld,overlapped=%p: stub.\n",
2628 hFile, dwReserved, nNumberOfBytesToUnlockLow, nNumberOfBytesToUnlockHigh,
2630 if (dwReserved == 0)
2631 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
2634 ERR("reserved == %ld: Supposed to be 0??\n", dwReserved);
2635 SetLastError(ERROR_INVALID_PARAMETER);
2644 struct DOS_FILE_LOCK {
2645 struct DOS_FILE_LOCK * next;
2649 FILE_OBJECT * dos_file;
2650 /* char * unix_name;*/
2653 typedef struct DOS_FILE_LOCK DOS_FILE_LOCK;
2655 static DOS_FILE_LOCK *locks = NULL;
2656 static void DOS_RemoveFileLocks(FILE_OBJECT *file);
2659 /* Locks need to be mirrored because unix file locking is based
2660 * on the pid. Inside of wine there can be multiple WINE processes
2661 * that share the same unix pid.
2662 * Read's and writes should check these locks also - not sure
2663 * how critical that is at this point (FIXME).
2666 static BOOL DOS_AddLock(FILE_OBJECT *file, struct flock *f)
2668 DOS_FILE_LOCK *curr;
2671 processId = GetCurrentProcessId();
2673 /* check if lock overlaps a current lock for the same file */
2675 for (curr = locks; curr; curr = curr->next) {
2676 if (strcmp(curr->unix_name, file->unix_name) == 0) {
2677 if ((f->l_start == curr->base) && (f->l_len == curr->len))
2678 return TRUE;/* region is identic */
2679 if ((f->l_start < (curr->base + curr->len)) &&
2680 ((f->l_start + f->l_len) > curr->base)) {
2681 /* region overlaps */
2688 curr = HeapAlloc( GetProcessHeap(), 0, sizeof(DOS_FILE_LOCK) );
2689 curr->processId = GetCurrentProcessId();
2690 curr->base = f->l_start;
2691 curr->len = f->l_len;
2692 /* curr->unix_name = HEAP_strdupA( GetProcessHeap(), 0, file->unix_name);*/
2694 curr->dos_file = file;
2699 static void DOS_RemoveFileLocks(FILE_OBJECT *file)
2702 DOS_FILE_LOCK **curr;
2705 processId = GetCurrentProcessId();
2708 if ((*curr)->dos_file == file) {
2710 *curr = (*curr)->next;
2711 /* HeapFree( GetProcessHeap(), 0, rem->unix_name );*/
2712 HeapFree( GetProcessHeap(), 0, rem );
2715 curr = &(*curr)->next;
2719 static BOOL DOS_RemoveLock(FILE_OBJECT *file, struct flock *f)
2722 DOS_FILE_LOCK **curr;
2725 processId = GetCurrentProcessId();
2726 for (curr = &locks; *curr; curr = &(*curr)->next) {
2727 if ((*curr)->processId == processId &&
2728 (*curr)->dos_file == file &&
2729 (*curr)->base == f->l_start &&
2730 (*curr)->len == f->l_len) {
2731 /* this is the same lock */
2733 *curr = (*curr)->next;
2734 /* HeapFree( GetProcessHeap(), 0, rem->unix_name );*/
2735 HeapFree( GetProcessHeap(), 0, rem );
2739 /* no matching lock found */
2744 /**************************************************************************
2745 * LockFile (KERNEL32.@)
2747 BOOL WINAPI LockFile(
2748 HFILE hFile,DWORD dwFileOffsetLow,DWORD dwFileOffsetHigh,
2749 DWORD nNumberOfBytesToLockLow,DWORD nNumberOfBytesToLockHigh )
2754 TRACE("handle %d offsetlow=%ld offsethigh=%ld nbyteslow=%ld nbyteshigh=%ld\n",
2755 hFile, dwFileOffsetLow, dwFileOffsetHigh,
2756 nNumberOfBytesToLockLow, nNumberOfBytesToLockHigh);
2758 if (dwFileOffsetHigh || nNumberOfBytesToLockHigh) {
2759 FIXME("Unimplemented bytes > 32bits\n");
2763 f.l_start = dwFileOffsetLow;
2764 f.l_len = nNumberOfBytesToLockLow;
2765 f.l_whence = SEEK_SET;
2769 if (!(file = FILE_GetFile(hFile,0,NULL))) return FALSE;
2771 /* shadow locks internally */
2772 if (!DOS_AddLock(file, &f)) {
2773 SetLastError( ERROR_LOCK_VIOLATION );
2777 /* FIXME: Unix locking commented out for now, doesn't work with Excel */
2778 #ifdef USE_UNIX_LOCKS
2779 if (fcntl(file->unix_handle, F_SETLK, &f) == -1) {
2780 if (errno == EACCES || errno == EAGAIN) {
2781 SetLastError( ERROR_LOCK_VIOLATION );
2786 /* remove our internal copy of the lock */
2787 DOS_RemoveLock(file, &f);
2795 /**************************************************************************
2796 * UnlockFile (KERNEL32.@)
2798 BOOL WINAPI UnlockFile(
2799 HFILE hFile,DWORD dwFileOffsetLow,DWORD dwFileOffsetHigh,
2800 DWORD nNumberOfBytesToUnlockLow,DWORD nNumberOfBytesToUnlockHigh )
2805 TRACE("handle %d offsetlow=%ld offsethigh=%ld nbyteslow=%ld nbyteshigh=%ld\n",
2806 hFile, dwFileOffsetLow, dwFileOffsetHigh,
2807 nNumberOfBytesToUnlockLow, nNumberOfBytesToUnlockHigh);
2809 if (dwFileOffsetHigh || nNumberOfBytesToUnlockHigh) {
2810 WARN("Unimplemented bytes > 32bits\n");
2814 f.l_start = dwFileOffsetLow;
2815 f.l_len = nNumberOfBytesToUnlockLow;
2816 f.l_whence = SEEK_SET;
2820 if (!(file = FILE_GetFile(hFile,0,NULL))) return FALSE;
2822 DOS_RemoveLock(file, &f); /* ok if fails - may be another wine */
2824 /* FIXME: Unix locking commented out for now, doesn't work with Excel */
2825 #ifdef USE_UNIX_LOCKS
2826 if (fcntl(file->unix_handle, F_SETLK, &f) == -1) {
2835 /**************************************************************************
2836 * GetFileAttributesExA [KERNEL32.@]
2838 BOOL WINAPI GetFileAttributesExA(
2839 LPCSTR lpFileName, GET_FILEEX_INFO_LEVELS fInfoLevelId,
2840 LPVOID lpFileInformation)
2842 DOS_FULL_NAME full_name;
2843 BY_HANDLE_FILE_INFORMATION info;
2845 if (lpFileName == NULL) return FALSE;
2846 if (lpFileInformation == NULL) return FALSE;
2848 if (fInfoLevelId == GetFileExInfoStandard) {
2849 LPWIN32_FILE_ATTRIBUTE_DATA lpFad =
2850 (LPWIN32_FILE_ATTRIBUTE_DATA) lpFileInformation;
2851 if (!DOSFS_GetFullName( lpFileName, TRUE, &full_name )) return FALSE;
2852 if (!FILE_Stat( full_name.long_name, &info )) return FALSE;
2854 lpFad->dwFileAttributes = info.dwFileAttributes;
2855 lpFad->ftCreationTime = info.ftCreationTime;
2856 lpFad->ftLastAccessTime = info.ftLastAccessTime;
2857 lpFad->ftLastWriteTime = info.ftLastWriteTime;
2858 lpFad->nFileSizeHigh = info.nFileSizeHigh;
2859 lpFad->nFileSizeLow = info.nFileSizeLow;
2862 FIXME("invalid info level %d!\n", fInfoLevelId);
2870 /**************************************************************************
2871 * GetFileAttributesExW [KERNEL32.@]
2873 BOOL WINAPI GetFileAttributesExW(
2874 LPCWSTR lpFileName, GET_FILEEX_INFO_LEVELS fInfoLevelId,
2875 LPVOID lpFileInformation)
2877 LPSTR nameA = HEAP_strdupWtoA( GetProcessHeap(), 0, lpFileName );
2879 GetFileAttributesExA( nameA, fInfoLevelId, lpFileInformation);
2880 HeapFree( GetProcessHeap(), 0, nameA );