2 * File handling functions
4 * Copyright 1993 John Burton
5 * Copyright 1996 Alexandre Julliard
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 * Fix the CopyFileEx methods to implement the "extended" functionality.
23 * Right now, they simply call the CopyFile method.
27 #include "wine/port.h"
36 #ifdef HAVE_SYS_ERRNO_H
37 #include <sys/errno.h>
39 #include <sys/types.h>
41 #ifdef HAVE_SYS_MMAN_H
53 #include "wine/winbase16.h"
54 #include "wine/server.h"
64 #include "wine/debug.h"
66 WINE_DEFAULT_DEBUG_CHANNEL(file);
68 #if defined(MAP_ANONYMOUS) && !defined(MAP_ANON)
69 #define MAP_ANON MAP_ANONYMOUS
72 /* Size of per-process table of DOS handles */
73 #define DOS_TABLE_SIZE 256
75 /* Macro to derive file offset from OVERLAPPED struct */
76 #define OVERLAPPED_OFFSET(overlapped) ((off_t) (overlapped)->Offset + ((off_t) (overlapped)->OffsetHigh << 32))
78 static HANDLE dos_handles[DOS_TABLE_SIZE];
82 extern WINAPI HANDLE FILE_SmbOpen(LPCSTR name);
84 /***********************************************************************
85 * Asynchronous file I/O *
87 static DWORD fileio_get_async_status (const async_private *ovp);
88 static DWORD fileio_get_async_count (const async_private *ovp);
89 static void fileio_set_async_status (async_private *ovp, const DWORD status);
90 static void CALLBACK fileio_call_completion_func (ULONG_PTR data);
92 static async_ops fileio_async_ops =
94 fileio_get_async_status, /* get_status */
95 fileio_set_async_status, /* set_status */
96 fileio_get_async_count, /* get_count */
97 fileio_call_completion_func /* call_completion */
100 typedef struct async_fileio
102 struct async_private async;
103 LPOVERLAPPED lpOverlapped;
104 LPOVERLAPPED_COMPLETION_ROUTINE completion_func;
109 static DWORD fileio_get_async_status (const struct async_private *ovp)
111 return ((async_fileio*) ovp)->lpOverlapped->Internal;
114 static void fileio_set_async_status (async_private *ovp, const DWORD status)
116 ((async_fileio*) ovp)->lpOverlapped->Internal = status;
119 static DWORD fileio_get_async_count (const struct async_private *ovp)
121 async_fileio *fileio = (async_fileio*) ovp;
122 DWORD ret = fileio->count - fileio->lpOverlapped->InternalHigh;
123 return (ret < 0 ? 0 : ret);
126 static void CALLBACK fileio_call_completion_func (ULONG_PTR data)
128 async_fileio *ovp = (async_fileio*) data;
129 TRACE ("data: %p\n", ovp);
131 if (ovp->completion_func)
132 ovp->completion_func(ovp->lpOverlapped->Internal,
133 ovp->lpOverlapped->InternalHigh,
136 HeapFree(GetProcessHeap(), 0, ovp);
139 /***********************************************************************
142 * Convert OF_* mode into flags for CreateFile.
144 static void FILE_ConvertOFMode( INT mode, DWORD *access, DWORD *sharing )
148 case OF_READ: *access = GENERIC_READ; break;
149 case OF_WRITE: *access = GENERIC_WRITE; break;
150 case OF_READWRITE: *access = GENERIC_READ | GENERIC_WRITE; break;
151 default: *access = 0; break;
155 case OF_SHARE_EXCLUSIVE: *sharing = 0; break;
156 case OF_SHARE_DENY_WRITE: *sharing = FILE_SHARE_READ; break;
157 case OF_SHARE_DENY_READ: *sharing = FILE_SHARE_WRITE; break;
158 case OF_SHARE_DENY_NONE:
159 case OF_SHARE_COMPAT:
160 default: *sharing = FILE_SHARE_READ | FILE_SHARE_WRITE; break;
165 /***********************************************************************
168 * locale-independent case conversion for file I/O
170 int FILE_strcasecmp( const char *str1, const char *str2 )
174 int ret = FILE_toupper(*str1) - FILE_toupper(*str2);
175 if (ret || !*str1) return ret;
182 /***********************************************************************
185 * locale-independent case conversion for file I/O
187 int FILE_strncasecmp( const char *str1, const char *str2, int len )
190 for ( ; len > 0; len--, str1++, str2++)
191 if ((ret = FILE_toupper(*str1) - FILE_toupper(*str2)) || !*str1) break;
196 /***********************************************************************
199 * Set the DOS error code from errno.
201 void FILE_SetDosError(void)
203 int save_errno = errno; /* errno gets overwritten by printf */
205 TRACE("errno = %d %s\n", errno, strerror(errno));
209 SetLastError( ERROR_SHARING_VIOLATION );
212 SetLastError( ERROR_INVALID_HANDLE );
215 SetLastError( ERROR_HANDLE_DISK_FULL );
220 SetLastError( ERROR_ACCESS_DENIED );
223 SetLastError( ERROR_LOCK_VIOLATION );
226 SetLastError( ERROR_FILE_NOT_FOUND );
229 SetLastError( ERROR_CANNOT_MAKE );
233 SetLastError( ERROR_NO_MORE_FILES );
236 SetLastError( ERROR_FILE_EXISTS );
240 SetLastError( ERROR_SEEK );
243 SetLastError( ERROR_DIR_NOT_EMPTY );
246 SetLastError( ERROR_BAD_FORMAT );
249 WARN("unknown file error: %s\n", strerror(save_errno) );
250 SetLastError( ERROR_GEN_FAILURE );
257 /***********************************************************************
260 * Duplicate a Unix handle into a task handle.
261 * Returns 0 on failure.
263 HANDLE FILE_DupUnixHandle( int fd, DWORD access, BOOL inherit )
267 wine_server_send_fd( fd );
269 SERVER_START_REQ( alloc_file_handle )
271 req->access = access;
272 req->inherit = inherit;
274 wine_server_call( req );
282 /***********************************************************************
283 * FILE_GetUnixHandleType
285 * Retrieve the Unix handle corresponding to a file handle.
286 * Returns -1 on failure.
288 static int FILE_GetUnixHandleType( HANDLE handle, DWORD access, enum fd_type *type, int *flags )
292 ret = wine_server_handle_to_fd( handle, access, &fd, type, flags );
293 if (ret) SetLastError( RtlNtStatusToDosError(ret) );
297 /***********************************************************************
300 * Retrieve the Unix handle corresponding to a file handle.
301 * Returns -1 on failure.
303 int FILE_GetUnixHandle( HANDLE handle, DWORD access )
305 return FILE_GetUnixHandleType( handle, access, NULL, NULL );
308 /*************************************************************************
311 * Open a handle to the current process console.
312 * Returns 0 on failure.
314 static HANDLE FILE_OpenConsole( BOOL output, DWORD access, DWORD sharing, LPSECURITY_ATTRIBUTES sa )
318 SERVER_START_REQ( open_console )
321 req->access = access;
322 req->share = sharing;
323 req->inherit = (sa && (sa->nLength>=sizeof(*sa)) && sa->bInheritHandle);
325 wine_server_call_err( req );
333 /***********************************************************************
336 * Implementation of CreateFile. Takes a Unix path name.
337 * Returns 0 on failure.
339 HANDLE FILE_CreateFile( LPCSTR filename, DWORD access, DWORD sharing,
340 LPSECURITY_ATTRIBUTES sa, DWORD creation,
341 DWORD attributes, HANDLE template, BOOL fail_read_only,
349 SERVER_START_REQ( create_file )
351 req->access = access;
352 req->inherit = (sa && (sa->nLength>=sizeof(*sa)) && sa->bInheritHandle);
353 req->sharing = sharing;
354 req->create = creation;
355 req->attrs = attributes;
356 req->drive_type = drive_type;
357 wine_server_add_data( req, filename, strlen(filename) );
359 err = wine_server_call( req );
364 /* If write access failed, retry without GENERIC_WRITE */
366 if (!ret && !fail_read_only && (access & GENERIC_WRITE))
368 if ((err == STATUS_MEDIA_WRITE_PROTECTED) || (err == STATUS_ACCESS_DENIED))
370 TRACE("Write access failed for file '%s', trying without "
371 "write access\n", filename);
372 access &= ~GENERIC_WRITE;
377 if (err) SetLastError( RtlNtStatusToDosError(err) );
379 if (!ret) WARN("Unable to create file '%s' (GLE %ld)\n", filename, GetLastError());
385 /***********************************************************************
388 * Same as FILE_CreateFile but for a device
389 * Returns 0 on failure.
391 HANDLE FILE_CreateDevice( int client_id, DWORD access, LPSECURITY_ATTRIBUTES sa )
394 SERVER_START_REQ( create_device )
396 req->access = access;
397 req->inherit = (sa && (sa->nLength>=sizeof(*sa)) && sa->bInheritHandle);
400 wine_server_call_err( req );
407 static HANDLE FILE_OpenPipe(LPCSTR name, DWORD access)
409 WCHAR buffer[MAX_PATH];
413 if (name && !(len = MultiByteToWideChar( CP_ACP, 0, name, strlen(name), buffer, MAX_PATH )))
415 SetLastError( ERROR_FILENAME_EXCED_RANGE );
418 SERVER_START_REQ( open_named_pipe )
420 req->access = access;
422 wine_server_add_data( req, buffer, len * sizeof(WCHAR) );
423 wine_server_call_err( req );
427 TRACE("Returned %d\n",ret);
431 /*************************************************************************
432 * CreateFileA [KERNEL32.@] Creates or opens a file or other object
434 * Creates or opens an object, and returns a handle that can be used to
435 * access that object.
439 * filename [in] pointer to filename to be accessed
440 * access [in] access mode requested
441 * sharing [in] share mode
442 * sa [in] pointer to security attributes
443 * creation [in] how to create the file
444 * attributes [in] attributes for newly created file
445 * template [in] handle to file with extended attributes to copy
448 * Success: Open handle to specified file
449 * Failure: INVALID_HANDLE_VALUE
452 * Should call SetLastError() on failure.
456 * Doesn't support character devices, template files, or a
457 * lot of the 'attributes' flags yet.
459 HANDLE WINAPI CreateFileA( LPCSTR filename, DWORD access, DWORD sharing,
460 LPSECURITY_ATTRIBUTES sa, DWORD creation,
461 DWORD attributes, HANDLE template )
463 DOS_FULL_NAME full_name;
468 SetLastError( ERROR_INVALID_PARAMETER );
469 return INVALID_HANDLE_VALUE;
471 TRACE("%s %s%s%s%s%s%s%s\n",filename,
472 ((access & GENERIC_READ)==GENERIC_READ)?"GENERIC_READ ":"",
473 ((access & GENERIC_WRITE)==GENERIC_WRITE)?"GENERIC_WRITE ":"",
474 (!access)?"QUERY_ACCESS ":"",
475 ((sharing & FILE_SHARE_READ)==FILE_SHARE_READ)?"FILE_SHARE_READ ":"",
476 ((sharing & FILE_SHARE_WRITE)==FILE_SHARE_WRITE)?"FILE_SHARE_WRITE ":"",
477 ((sharing & FILE_SHARE_DELETE)==FILE_SHARE_DELETE)?"FILE_SHARE_DELETE ":"",
478 (creation ==CREATE_NEW)?"CREATE_NEW":
479 (creation ==CREATE_ALWAYS)?"CREATE_ALWAYS ":
480 (creation ==OPEN_EXISTING)?"OPEN_EXISTING ":
481 (creation ==OPEN_ALWAYS)?"OPEN_ALWAYS ":
482 (creation ==TRUNCATE_EXISTING)?"TRUNCATE_EXISTING ":"");
484 /* If the name starts with '\\?\', ignore the first 4 chars. */
485 if (!strncmp(filename, "\\\\?\\", 4))
488 if (!strncmp(filename, "UNC\\", 4))
490 FIXME("UNC name (%s) not supported.\n", filename );
491 SetLastError( ERROR_PATH_NOT_FOUND );
492 return INVALID_HANDLE_VALUE;
496 if (!strncmp(filename, "\\\\.\\", 4)) {
497 if(!strncasecmp(&filename[4],"pipe\\",5))
499 TRACE("Opening a pipe: %s\n",filename);
500 ret = FILE_OpenPipe(filename,access);
503 else if (isalpha(filename[4]) && filename[5] == ':' && filename[6] == '\0')
505 ret = FILE_CreateDevice( (toupper(filename[4]) - 'A') | 0x20000, access, sa );
508 else if (!DOSFS_GetDevice( filename ))
510 ret = DEVICE_Open( filename+4, access, sa );
514 filename+=4; /* fall into DOSFS_Device case below */
517 /* If the name still starts with '\\', it's a UNC name. */
518 if (!strncmp(filename, "\\\\", 2))
520 ret = SMB_CreateFileA(filename, access, sharing, sa, creation, attributes, template );
524 /* If the name contains a DOS wild card (* or ?), do no create a file */
525 if(strchr(filename,'*') || strchr(filename,'?'))
526 return INVALID_HANDLE_VALUE;
528 /* Open a console for CONIN$ or CONOUT$ */
529 if (!strcasecmp(filename, "CONIN$"))
531 ret = FILE_OpenConsole( FALSE, access, sharing, sa );
534 if (!strcasecmp(filename, "CONOUT$"))
536 ret = FILE_OpenConsole( TRUE, access, sharing, sa );
540 if (DOSFS_GetDevice( filename ))
542 TRACE("opening device '%s'\n", filename );
544 if (!(ret = DOSFS_OpenDevice( filename, access, attributes, sa )))
546 /* Do not silence this please. It is a critical error. -MM */
547 ERR("Couldn't open device '%s'!\n",filename);
548 SetLastError( ERROR_FILE_NOT_FOUND );
553 /* check for filename, don't check for last entry if creating */
554 if (!DOSFS_GetFullName( filename,
555 (creation == OPEN_EXISTING) ||
556 (creation == TRUNCATE_EXISTING),
558 WARN("Unable to get full filename from '%s' (GLE %ld)\n",
559 filename, GetLastError());
560 return INVALID_HANDLE_VALUE;
563 ret = FILE_CreateFile( full_name.long_name, access, sharing,
564 sa, creation, attributes, template,
565 DRIVE_GetFlags(full_name.drive) & DRIVE_FAIL_READ_ONLY,
566 GetDriveTypeA( full_name.short_name ) );
568 if (!ret) ret = INVALID_HANDLE_VALUE;
574 /*************************************************************************
575 * CreateFileW (KERNEL32.@)
577 HANDLE WINAPI CreateFileW( LPCWSTR filename, DWORD access, DWORD sharing,
578 LPSECURITY_ATTRIBUTES sa, DWORD creation,
579 DWORD attributes, HANDLE template)
581 LPSTR afn = HEAP_strdupWtoA( GetProcessHeap(), 0, filename );
582 HANDLE res = CreateFileA( afn, access, sharing, sa, creation, attributes, template );
583 HeapFree( GetProcessHeap(), 0, afn );
588 /***********************************************************************
591 * Fill a file information from a struct stat.
593 static void FILE_FillInfo( struct stat *st, BY_HANDLE_FILE_INFORMATION *info )
595 if (S_ISDIR(st->st_mode))
596 info->dwFileAttributes = FILE_ATTRIBUTE_DIRECTORY;
598 info->dwFileAttributes = FILE_ATTRIBUTE_ARCHIVE;
599 if (!(st->st_mode & S_IWUSR))
600 info->dwFileAttributes |= FILE_ATTRIBUTE_READONLY;
602 RtlSecondsSince1970ToTime( st->st_mtime, &info->ftCreationTime );
603 RtlSecondsSince1970ToTime( st->st_mtime, &info->ftLastWriteTime );
604 RtlSecondsSince1970ToTime( st->st_atime, &info->ftLastAccessTime );
606 info->dwVolumeSerialNumber = 0; /* FIXME */
607 info->nFileSizeHigh = 0;
608 info->nFileSizeLow = 0;
609 if (!S_ISDIR(st->st_mode)) {
610 info->nFileSizeHigh = st->st_size >> 32;
611 info->nFileSizeLow = st->st_size & 0xffffffff;
613 info->nNumberOfLinks = st->st_nlink;
614 info->nFileIndexHigh = 0;
615 info->nFileIndexLow = st->st_ino;
619 /***********************************************************************
622 * Stat a Unix path name. Return TRUE if OK.
624 BOOL FILE_Stat( LPCSTR unixName, BY_HANDLE_FILE_INFORMATION *info )
628 if (lstat( unixName, &st ) == -1)
633 if (!S_ISLNK(st.st_mode)) FILE_FillInfo( &st, info );
636 /* do a "real" stat to find out
637 about the type of the symlink destination */
638 if (stat( unixName, &st ) == -1)
643 FILE_FillInfo( &st, info );
644 info->dwFileAttributes |= FILE_ATTRIBUTE_SYMLINK;
650 /***********************************************************************
651 * GetFileInformationByHandle (KERNEL32.@)
653 DWORD WINAPI GetFileInformationByHandle( HANDLE hFile,
654 BY_HANDLE_FILE_INFORMATION *info )
659 SERVER_START_REQ( get_file_info )
662 if ((ret = !wine_server_call_err( req )))
664 /* FIXME: which file types are supported ?
665 * Serial ports (FILE_TYPE_CHAR) are not,
666 * and MSDN also says that pipes are not supported.
667 * FILE_TYPE_REMOTE seems to be supported according to
668 * MSDN q234741.txt */
669 if ((reply->type == FILE_TYPE_DISK) || (reply->type == FILE_TYPE_REMOTE))
671 RtlSecondsSince1970ToTime( reply->write_time, &info->ftCreationTime );
672 RtlSecondsSince1970ToTime( reply->write_time, &info->ftLastWriteTime );
673 RtlSecondsSince1970ToTime( reply->access_time, &info->ftLastAccessTime );
674 info->dwFileAttributes = reply->attr;
675 info->dwVolumeSerialNumber = reply->serial;
676 info->nFileSizeHigh = reply->size_high;
677 info->nFileSizeLow = reply->size_low;
678 info->nNumberOfLinks = reply->links;
679 info->nFileIndexHigh = reply->index_high;
680 info->nFileIndexLow = reply->index_low;
684 SetLastError(ERROR_NOT_SUPPORTED);
694 /**************************************************************************
695 * GetFileAttributes (KERNEL.420)
697 DWORD WINAPI GetFileAttributes16( LPCSTR name )
699 return GetFileAttributesA( name );
703 /**************************************************************************
704 * GetFileAttributesA (KERNEL32.@)
706 DWORD WINAPI GetFileAttributesA( LPCSTR name )
708 DOS_FULL_NAME full_name;
709 BY_HANDLE_FILE_INFORMATION info;
713 SetLastError( ERROR_INVALID_PARAMETER );
716 if (!DOSFS_GetFullName( name, TRUE, &full_name) )
718 if (!FILE_Stat( full_name.long_name, &info )) return -1;
719 return info.dwFileAttributes;
723 /**************************************************************************
724 * GetFileAttributesW (KERNEL32.@)
726 DWORD WINAPI GetFileAttributesW( LPCWSTR name )
728 LPSTR nameA = HEAP_strdupWtoA( GetProcessHeap(), 0, name );
729 DWORD res = GetFileAttributesA( nameA );
730 HeapFree( GetProcessHeap(), 0, nameA );
735 /**************************************************************************
736 * SetFileAttributes (KERNEL.421)
738 BOOL16 WINAPI SetFileAttributes16( LPCSTR lpFileName, DWORD attributes )
740 return SetFileAttributesA( lpFileName, attributes );
744 /**************************************************************************
745 * SetFileAttributesA (KERNEL32.@)
747 BOOL WINAPI SetFileAttributesA(LPCSTR lpFileName, DWORD attributes)
750 DOS_FULL_NAME full_name;
752 if (!DOSFS_GetFullName( lpFileName, TRUE, &full_name ))
755 TRACE("(%s,%lx)\n",lpFileName,attributes);
756 if (attributes & FILE_ATTRIBUTE_NORMAL) {
757 attributes &= ~FILE_ATTRIBUTE_NORMAL;
759 FIXME("(%s):%lx illegal combination with FILE_ATTRIBUTE_NORMAL.\n", lpFileName,attributes);
761 if(stat(full_name.long_name,&buf)==-1)
766 if (attributes & FILE_ATTRIBUTE_READONLY)
768 if(S_ISDIR(buf.st_mode))
770 WARN("FILE_ATTRIBUTE_READONLY ignored for directory.\n");
772 buf.st_mode &= ~0222; /* octal!, clear write permission bits */
773 attributes &= ~FILE_ATTRIBUTE_READONLY;
777 /* add write permission */
778 buf.st_mode |= (0600 | ((buf.st_mode & 044) >> 1)) & (~FILE_umask);
780 if (attributes & FILE_ATTRIBUTE_DIRECTORY)
782 if (!S_ISDIR(buf.st_mode))
783 FIXME("SetFileAttributes expected the file '%s' to be a directory",
785 attributes &= ~FILE_ATTRIBUTE_DIRECTORY;
787 attributes &= ~(FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_HIDDEN|FILE_ATTRIBUTE_SYSTEM);
789 FIXME("(%s):%lx attribute(s) not implemented.\n", lpFileName,attributes);
790 if (-1==chmod(full_name.long_name,buf.st_mode))
792 if(GetDriveTypeA(lpFileName) == DRIVE_CDROM) {
793 SetLastError( ERROR_ACCESS_DENIED );
798 * FIXME: We don't return FALSE here because of differences between
799 * Linux and Windows privileges. Under Linux only the owner of
800 * the file is allowed to change file attributes. Under Windows,
801 * applications expect that if you can write to a file, you can also
802 * change its attributes (see GENERIC_WRITE). We could try to be
803 * clever here but that would break multi-user installations where
804 * users share read-only DLLs. This is because some installers like
805 * to change attributes of already installed DLLs.
807 FIXME("Couldn't set file attributes for existing file \"%s\".\n"
808 "Check permissions or set VFAT \"quiet\" mount flag\n", full_name.long_name);
814 /**************************************************************************
815 * SetFileAttributesW (KERNEL32.@)
817 BOOL WINAPI SetFileAttributesW(LPCWSTR lpFileName, DWORD attributes)
820 DWORD len = WideCharToMultiByte( CP_ACP, 0, lpFileName, -1, NULL, 0, NULL, NULL );
821 LPSTR afn = HeapAlloc( GetProcessHeap(), 0, len );
823 WideCharToMultiByte( CP_ACP, 0, lpFileName, -1, afn, len, NULL, NULL );
824 res = SetFileAttributesA( afn, attributes );
825 HeapFree( GetProcessHeap(), 0, afn );
830 /***********************************************************************
831 * GetFileSize (KERNEL32.@)
833 DWORD WINAPI GetFileSize( HANDLE hFile, LPDWORD filesizehigh )
835 BY_HANDLE_FILE_INFORMATION info;
836 if (!GetFileInformationByHandle( hFile, &info )) return -1;
837 if (filesizehigh) *filesizehigh = info.nFileSizeHigh;
838 return info.nFileSizeLow;
842 /***********************************************************************
843 * GetFileTime (KERNEL32.@)
845 BOOL WINAPI GetFileTime( HANDLE hFile, FILETIME *lpCreationTime,
846 FILETIME *lpLastAccessTime,
847 FILETIME *lpLastWriteTime )
849 BY_HANDLE_FILE_INFORMATION info;
850 if (!GetFileInformationByHandle( hFile, &info )) return FALSE;
851 if (lpCreationTime) *lpCreationTime = info.ftCreationTime;
852 if (lpLastAccessTime) *lpLastAccessTime = info.ftLastAccessTime;
853 if (lpLastWriteTime) *lpLastWriteTime = info.ftLastWriteTime;
857 /***********************************************************************
858 * CompareFileTime (KERNEL32.@)
860 INT WINAPI CompareFileTime( LPFILETIME x, LPFILETIME y )
862 if (!x || !y) return -1;
864 if (x->dwHighDateTime > y->dwHighDateTime)
866 if (x->dwHighDateTime < y->dwHighDateTime)
868 if (x->dwLowDateTime > y->dwLowDateTime)
870 if (x->dwLowDateTime < y->dwLowDateTime)
875 /***********************************************************************
876 * FILE_GetTempFileName : utility for GetTempFileName
878 static UINT FILE_GetTempFileName( LPCSTR path, LPCSTR prefix, UINT unique,
879 LPSTR buffer, BOOL isWin16 )
881 static UINT unique_temp;
882 DOS_FULL_NAME full_name;
887 if ( !path || !prefix || !buffer ) return 0;
889 if (!unique_temp) unique_temp = time(NULL) & 0xffff;
890 num = unique ? (unique & 0xffff) : (unique_temp++ & 0xffff);
892 strcpy( buffer, path );
893 p = buffer + strlen(buffer);
895 /* add a \, if there isn't one and path is more than just the drive letter ... */
896 if ( !((strlen(buffer) == 2) && (buffer[1] == ':'))
897 && ((p == buffer) || (p[-1] != '\\'))) *p++ = '\\';
899 if (isWin16) *p++ = '~';
900 for (i = 3; (i > 0) && (*prefix); i--) *p++ = *prefix++;
901 sprintf( p, "%04x.tmp", num );
903 /* Now try to create it */
909 HFILE handle = CreateFileA( buffer, GENERIC_WRITE, 0, NULL,
910 CREATE_NEW, FILE_ATTRIBUTE_NORMAL, 0 );
911 if (handle != INVALID_HANDLE_VALUE)
912 { /* We created it */
913 TRACE("created %s\n",
915 CloseHandle( handle );
918 if (GetLastError() != ERROR_FILE_EXISTS)
919 break; /* No need to go on */
921 sprintf( p, "%04x.tmp", num );
922 } while (num != (unique & 0xffff));
925 /* Get the full path name */
927 if (DOSFS_GetFullName( buffer, FALSE, &full_name ))
929 /* Check if we have write access in the directory */
930 if ((p = strrchr( full_name.long_name, '/' ))) *p = '\0';
931 if (access( full_name.long_name, W_OK ) == -1)
932 WARN("returns '%s', which doesn't seem to be writeable.\n",
935 TRACE("returning %s\n", buffer );
936 return unique ? unique : num;
940 /***********************************************************************
941 * GetTempFileNameA (KERNEL32.@)
943 UINT WINAPI GetTempFileNameA( LPCSTR path, LPCSTR prefix, UINT unique,
946 return FILE_GetTempFileName(path, prefix, unique, buffer, FALSE);
949 /***********************************************************************
950 * GetTempFileNameW (KERNEL32.@)
952 UINT WINAPI GetTempFileNameW( LPCWSTR path, LPCWSTR prefix, UINT unique,
960 patha = HEAP_strdupWtoA( GetProcessHeap(), 0, path );
961 prefixa = HEAP_strdupWtoA( GetProcessHeap(), 0, prefix );
962 ret = FILE_GetTempFileName( patha, prefixa, unique, buffera, FALSE );
963 MultiByteToWideChar( CP_ACP, 0, buffera, -1, buffer, MAX_PATH );
964 HeapFree( GetProcessHeap(), 0, patha );
965 HeapFree( GetProcessHeap(), 0, prefixa );
970 /***********************************************************************
971 * GetTempFileName (KERNEL.97)
973 UINT16 WINAPI GetTempFileName16( BYTE drive, LPCSTR prefix, UINT16 unique,
978 if (!(drive & ~TF_FORCEDRIVE)) /* drive 0 means current default drive */
979 drive |= DRIVE_GetCurrentDrive() + 'A';
981 if ((drive & TF_FORCEDRIVE) &&
982 !DRIVE_IsValid( toupper(drive & ~TF_FORCEDRIVE) - 'A' ))
984 drive &= ~TF_FORCEDRIVE;
985 WARN("invalid drive %d specified\n", drive );
988 if (drive & TF_FORCEDRIVE)
989 sprintf(temppath,"%c:", drive & ~TF_FORCEDRIVE );
991 GetTempPathA( 132, temppath );
992 return (UINT16)FILE_GetTempFileName( temppath, prefix, unique, buffer, TRUE );
995 /***********************************************************************
998 * Implementation of OpenFile16() and OpenFile32().
1000 static HFILE FILE_DoOpenFile( LPCSTR name, OFSTRUCT *ofs, UINT mode,
1005 WORD filedatetime[2];
1006 DOS_FULL_NAME full_name;
1007 DWORD access, sharing;
1010 if (!ofs) return HFILE_ERROR;
1012 TRACE("%s %s %s %s%s%s%s%s%s%s%s%s\n",name,
1013 ((mode & 0x3 )==OF_READ)?"OF_READ":
1014 ((mode & 0x3 )==OF_WRITE)?"OF_WRITE":
1015 ((mode & 0x3 )==OF_READWRITE)?"OF_READWRITE":"unknown",
1016 ((mode & 0x70 )==OF_SHARE_COMPAT)?"OF_SHARE_COMPAT":
1017 ((mode & 0x70 )==OF_SHARE_DENY_NONE)?"OF_SHARE_DENY_NONE":
1018 ((mode & 0x70 )==OF_SHARE_DENY_READ)?"OF_SHARE_DENY_READ":
1019 ((mode & 0x70 )==OF_SHARE_DENY_WRITE)?"OF_SHARE_DENY_WRITE":
1020 ((mode & 0x70 )==OF_SHARE_EXCLUSIVE)?"OF_SHARE_EXCLUSIVE":"unknown",
1021 ((mode & OF_PARSE )==OF_PARSE)?"OF_PARSE ":"",
1022 ((mode & OF_DELETE )==OF_DELETE)?"OF_DELETE ":"",
1023 ((mode & OF_VERIFY )==OF_VERIFY)?"OF_VERIFY ":"",
1024 ((mode & OF_SEARCH )==OF_SEARCH)?"OF_SEARCH ":"",
1025 ((mode & OF_CANCEL )==OF_CANCEL)?"OF_CANCEL ":"",
1026 ((mode & OF_CREATE )==OF_CREATE)?"OF_CREATE ":"",
1027 ((mode & OF_PROMPT )==OF_PROMPT)?"OF_PROMPT ":"",
1028 ((mode & OF_EXIST )==OF_EXIST)?"OF_EXIST ":"",
1029 ((mode & OF_REOPEN )==OF_REOPEN)?"OF_REOPEN ":""
1033 ofs->cBytes = sizeof(OFSTRUCT);
1035 if (mode & OF_REOPEN) name = ofs->szPathName;
1038 ERR("called with `name' set to NULL ! Please debug.\n");
1042 TRACE("%s %04x\n", name, mode );
1044 /* the watcom 10.6 IDE relies on a valid path returned in ofs->szPathName
1045 Are there any cases where getting the path here is wrong?
1046 Uwe Bonnes 1997 Apr 2 */
1047 if (!GetFullPathNameA( name, sizeof(ofs->szPathName),
1048 ofs->szPathName, NULL )) goto error;
1049 FILE_ConvertOFMode( mode, &access, &sharing );
1051 /* OF_PARSE simply fills the structure */
1053 if (mode & OF_PARSE)
1055 ofs->fFixedDisk = (GetDriveType16( ofs->szPathName[0]-'A' )
1056 != DRIVE_REMOVABLE);
1057 TRACE("(%s): OF_PARSE, res = '%s'\n",
1058 name, ofs->szPathName );
1062 /* OF_CREATE is completely different from all other options, so
1065 if (mode & OF_CREATE)
1067 if ((hFileRet = CreateFileA( name, GENERIC_READ | GENERIC_WRITE,
1068 sharing, NULL, CREATE_ALWAYS,
1069 FILE_ATTRIBUTE_NORMAL, 0 ))== INVALID_HANDLE_VALUE)
1074 /* If OF_SEARCH is set, ignore the given path */
1076 if ((mode & OF_SEARCH) && !(mode & OF_REOPEN))
1078 /* First try the file name as is */
1079 if (DOSFS_GetFullName( name, TRUE, &full_name )) goto found;
1080 /* Now remove the path */
1081 if (name[0] && (name[1] == ':')) name += 2;
1082 if ((p = strrchr( name, '\\' ))) name = p + 1;
1083 if ((p = strrchr( name, '/' ))) name = p + 1;
1084 if (!name[0]) goto not_found;
1087 /* Now look for the file */
1089 if (!DIR_SearchPath( NULL, name, NULL, &full_name, win32 )) goto not_found;
1092 TRACE("found %s = %s\n",
1093 full_name.long_name, full_name.short_name );
1094 lstrcpynA( ofs->szPathName, full_name.short_name,
1095 sizeof(ofs->szPathName) );
1097 if (mode & OF_SHARE_EXCLUSIVE)
1098 /* Some InstallShield version uses OF_SHARE_EXCLUSIVE
1099 on the file <tempdir>/_ins0432._mp to determine how
1100 far installation has proceeded.
1101 _ins0432._mp is an executable and while running the
1102 application expects the open with OF_SHARE_ to fail*/
1104 As our loader closes the files after loading the executable,
1105 we can't find the running executable with FILE_InUse.
1106 The loader should keep the file open, as Windows does that, too.
1109 char *last = strrchr(full_name.long_name,'/');
1111 last = full_name.long_name - 1;
1112 if (GetModuleHandle16(last+1))
1114 TRACE("Denying shared open for %s\n",full_name.long_name);
1119 if (mode & OF_DELETE)
1121 if (unlink( full_name.long_name ) == -1) goto not_found;
1122 TRACE("(%s): OF_DELETE return = OK\n", name);
1126 hFileRet = FILE_CreateFile( full_name.long_name, access, sharing,
1127 NULL, OPEN_EXISTING, 0, 0,
1128 DRIVE_GetFlags(full_name.drive) & DRIVE_FAIL_READ_ONLY,
1129 GetDriveTypeA( full_name.short_name ) );
1130 if (!hFileRet) goto not_found;
1132 GetFileTime( hFileRet, NULL, NULL, &filetime );
1133 FileTimeToDosDateTime( &filetime, &filedatetime[0], &filedatetime[1] );
1134 if ((mode & OF_VERIFY) && (mode & OF_REOPEN))
1136 if (memcmp( ofs->reserved, filedatetime, sizeof(ofs->reserved) ))
1138 CloseHandle( hFileRet );
1139 WARN("(%s): OF_VERIFY failed\n", name );
1140 /* FIXME: what error here? */
1141 SetLastError( ERROR_FILE_NOT_FOUND );
1145 memcpy( ofs->reserved, filedatetime, sizeof(ofs->reserved) );
1147 success: /* We get here if the open was successful */
1148 TRACE("(%s): OK, return = %d\n", name, hFileRet );
1151 if (mode & OF_EXIST) /* Return the handle, but close it first */
1152 CloseHandle( hFileRet );
1156 hFileRet = Win32HandleToDosFileHandle( hFileRet );
1157 if (hFileRet == HFILE_ERROR16) goto error;
1158 if (mode & OF_EXIST) /* Return the handle, but close it first */
1159 _lclose16( hFileRet );
1163 not_found: /* We get here if the file does not exist */
1164 WARN("'%s' not found or sharing violation\n", name );
1165 SetLastError( ERROR_FILE_NOT_FOUND );
1168 error: /* We get here if there was an error opening the file */
1169 ofs->nErrCode = GetLastError();
1170 WARN("(%s): return = HFILE_ERROR error= %d\n",
1171 name,ofs->nErrCode );
1176 /***********************************************************************
1177 * OpenFile (KERNEL.74)
1178 * OpenFileEx (KERNEL.360)
1180 HFILE16 WINAPI OpenFile16( LPCSTR name, OFSTRUCT *ofs, UINT16 mode )
1182 return FILE_DoOpenFile( name, ofs, mode, FALSE );
1186 /***********************************************************************
1187 * OpenFile (KERNEL32.@)
1189 HFILE WINAPI OpenFile( LPCSTR name, OFSTRUCT *ofs, UINT mode )
1191 return FILE_DoOpenFile( name, ofs, mode, TRUE );
1195 /***********************************************************************
1196 * FILE_InitProcessDosHandles
1198 * Allocates the default DOS handles for a process. Called either by
1199 * Win32HandleToDosFileHandle below or by the DOSVM stuff.
1201 static void FILE_InitProcessDosHandles( void )
1203 dos_handles[0] = GetStdHandle(STD_INPUT_HANDLE);
1204 dos_handles[1] = GetStdHandle(STD_OUTPUT_HANDLE);
1205 dos_handles[2] = GetStdHandle(STD_ERROR_HANDLE);
1206 dos_handles[3] = GetStdHandle(STD_ERROR_HANDLE);
1207 dos_handles[4] = GetStdHandle(STD_ERROR_HANDLE);
1210 /***********************************************************************
1211 * Win32HandleToDosFileHandle (KERNEL32.21)
1213 * Allocate a DOS handle for a Win32 handle. The Win32 handle is no
1214 * longer valid after this function (even on failure).
1216 * Note: this is not exactly right, since on Win95 the Win32 handles
1217 * are on top of DOS handles and we do it the other way
1218 * around. Should be good enough though.
1220 HFILE WINAPI Win32HandleToDosFileHandle( HANDLE handle )
1224 if (!handle || (handle == INVALID_HANDLE_VALUE))
1227 for (i = 5; i < DOS_TABLE_SIZE; i++)
1228 if (!dos_handles[i])
1230 dos_handles[i] = handle;
1231 TRACE("Got %d for h32 %d\n", i, handle );
1234 CloseHandle( handle );
1235 SetLastError( ERROR_TOO_MANY_OPEN_FILES );
1240 /***********************************************************************
1241 * DosFileHandleToWin32Handle (KERNEL32.20)
1243 * Return the Win32 handle for a DOS handle.
1245 * Note: this is not exactly right, since on Win95 the Win32 handles
1246 * are on top of DOS handles and we do it the other way
1247 * around. Should be good enough though.
1249 HANDLE WINAPI DosFileHandleToWin32Handle( HFILE handle )
1251 HFILE16 hfile = (HFILE16)handle;
1252 if (hfile < 5 && !dos_handles[hfile]) FILE_InitProcessDosHandles();
1253 if ((hfile >= DOS_TABLE_SIZE) || !dos_handles[hfile])
1255 SetLastError( ERROR_INVALID_HANDLE );
1256 return INVALID_HANDLE_VALUE;
1258 return dos_handles[hfile];
1262 /***********************************************************************
1263 * DisposeLZ32Handle (KERNEL32.22)
1265 * Note: this is not entirely correct, we should only close the
1266 * 32-bit handle and not the 16-bit one, but we cannot do
1267 * this because of the way our DOS handles are implemented.
1268 * It shouldn't break anything though.
1270 void WINAPI DisposeLZ32Handle( HANDLE handle )
1274 if (!handle || (handle == INVALID_HANDLE_VALUE)) return;
1276 for (i = 5; i < DOS_TABLE_SIZE; i++)
1277 if (dos_handles[i] == handle)
1280 CloseHandle( handle );
1286 /***********************************************************************
1289 * dup2() function for DOS handles.
1291 HFILE16 FILE_Dup2( HFILE16 hFile1, HFILE16 hFile2 )
1295 if (hFile1 < 5 && !dos_handles[hFile1]) FILE_InitProcessDosHandles();
1297 if ((hFile1 >= DOS_TABLE_SIZE) || (hFile2 >= DOS_TABLE_SIZE) || !dos_handles[hFile1])
1299 SetLastError( ERROR_INVALID_HANDLE );
1300 return HFILE_ERROR16;
1304 FIXME("stdio handle closed, need proper conversion\n" );
1305 SetLastError( ERROR_INVALID_HANDLE );
1306 return HFILE_ERROR16;
1308 if (!DuplicateHandle( GetCurrentProcess(), dos_handles[hFile1],
1309 GetCurrentProcess(), &new_handle,
1310 0, FALSE, DUPLICATE_SAME_ACCESS ))
1311 return HFILE_ERROR16;
1312 if (dos_handles[hFile2]) CloseHandle( dos_handles[hFile2] );
1313 dos_handles[hFile2] = new_handle;
1318 /***********************************************************************
1319 * _lclose (KERNEL.81)
1321 HFILE16 WINAPI _lclose16( HFILE16 hFile )
1325 FIXME("stdio handle closed, need proper conversion\n" );
1326 SetLastError( ERROR_INVALID_HANDLE );
1327 return HFILE_ERROR16;
1329 if ((hFile >= DOS_TABLE_SIZE) || !dos_handles[hFile])
1331 SetLastError( ERROR_INVALID_HANDLE );
1332 return HFILE_ERROR16;
1334 TRACE("%d (handle32=%d)\n", hFile, dos_handles[hFile] );
1335 CloseHandle( dos_handles[hFile] );
1336 dos_handles[hFile] = 0;
1341 /***********************************************************************
1342 * _lclose (KERNEL32.@)
1344 HFILE WINAPI _lclose( HFILE hFile )
1346 TRACE("handle %d\n", hFile );
1347 return CloseHandle( hFile ) ? 0 : HFILE_ERROR;
1350 /***********************************************************************
1351 * GetOverlappedResult (KERNEL32.@)
1353 * Check the result of an Asynchronous data transfer from a file.
1359 * If successful (and relevant) lpTransferred will hold the number of
1360 * bytes transferred during the async operation.
1364 * Currently only works for WaitCommEvent, ReadFile, WriteFile
1365 * with communications ports.
1368 BOOL WINAPI GetOverlappedResult(
1369 HANDLE hFile, /* [in] handle of file to check on */
1370 LPOVERLAPPED lpOverlapped, /* [in/out] pointer to overlapped */
1371 LPDWORD lpTransferred, /* [in/out] number of bytes transferred */
1372 BOOL bWait /* [in] wait for the transfer to complete ? */
1376 TRACE("(%d %p %p %x)\n", hFile, lpOverlapped, lpTransferred, bWait);
1378 if(lpOverlapped==NULL)
1380 ERR("lpOverlapped was null\n");
1383 if(!lpOverlapped->hEvent)
1385 ERR("lpOverlapped->hEvent was null\n");
1390 TRACE("waiting on %p\n",lpOverlapped);
1391 r = WaitForSingleObjectEx(lpOverlapped->hEvent, bWait?INFINITE:0, TRUE);
1392 TRACE("wait on %p returned %ld\n",lpOverlapped,r);
1393 } while (r==STATUS_USER_APC);
1396 *lpTransferred = lpOverlapped->InternalHigh;
1398 SetLastError(lpOverlapped->Internal);
1400 return (r==WAIT_OBJECT_0);
1403 /***********************************************************************
1404 * CancelIo (KERNEL32.@)
1406 BOOL WINAPI CancelIo(HANDLE handle)
1408 async_private *ovp,*t;
1410 TRACE("handle = %x\n",handle);
1412 for (ovp = NtCurrentTeb()->pending_list; ovp; ovp = t)
1415 if ( ovp->handle == handle )
1416 cancel_async ( ovp );
1418 WaitForMultipleObjectsEx(0,NULL,FALSE,1,TRUE);
1422 /***********************************************************************
1423 * FILE_AsyncReadService (INTERNAL)
1425 * This function is called while the client is waiting on the
1426 * server, so we can't make any server calls here.
1428 static void FILE_AsyncReadService(async_private *ovp)
1430 async_fileio *fileio = (async_fileio*) ovp;
1431 LPOVERLAPPED lpOverlapped = fileio->lpOverlapped;
1433 int already = lpOverlapped->InternalHigh;
1435 TRACE("%p %p\n", lpOverlapped, fileio->buffer );
1437 /* check to see if the data is ready (non-blocking) */
1439 result = pread (ovp->fd, &fileio->buffer[already], fileio->count - already,
1440 OVERLAPPED_OFFSET (lpOverlapped) + already);
1441 if ((result < 0) && (errno == ESPIPE))
1442 result = read (ovp->fd, &fileio->buffer[already], fileio->count - already);
1444 if ( (result<0) && ((errno == EAGAIN) || (errno == EINTR)))
1446 TRACE("Deferred read %d\n",errno);
1451 /* check to see if the transfer is complete */
1454 TRACE("read returned errno %d\n",errno);
1455 r = STATUS_UNSUCCESSFUL;
1459 lpOverlapped->InternalHigh += result;
1460 TRACE("read %d more bytes %ld/%d so far\n",result,lpOverlapped->InternalHigh,fileio->count);
1462 if(lpOverlapped->InternalHigh < fileio->count)
1468 lpOverlapped->Internal = r;
1471 /***********************************************************************
1472 * FILE_ReadFileEx (INTERNAL)
1474 static BOOL FILE_ReadFileEx(HANDLE hFile, LPVOID buffer, DWORD bytesToRead,
1475 LPOVERLAPPED overlapped,
1476 LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine,
1482 TRACE("file %d to buf %p num %ld %p func %p\n",
1483 hFile, buffer, bytesToRead, overlapped, lpCompletionRoutine);
1485 /* check that there is an overlapped struct */
1486 if (overlapped==NULL)
1488 SetLastError(ERROR_INVALID_PARAMETER);
1492 fd = FILE_GetUnixHandle( hFile, GENERIC_READ );
1495 TRACE("Couldn't get FD\n");
1499 ovp = (async_fileio*) HeapAlloc(GetProcessHeap(), 0, sizeof (async_fileio));
1502 TRACE("HeapAlloc Failed\n");
1503 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1508 ovp->async.ops = &fileio_async_ops;
1509 ovp->async.handle = hFile;
1511 ovp->async.type = ASYNC_TYPE_READ;
1512 ovp->async.func = FILE_AsyncReadService;
1513 ovp->async.event = hEvent;
1514 ovp->lpOverlapped = overlapped;
1515 ovp->count = bytesToRead;
1516 ovp->completion_func = lpCompletionRoutine;
1517 ovp->buffer = buffer;
1519 return !register_new_async (&ovp->async);
1522 /***********************************************************************
1523 * ReadFileEx (KERNEL32.@)
1525 BOOL WINAPI ReadFileEx(HANDLE hFile, LPVOID buffer, DWORD bytesToRead,
1526 LPOVERLAPPED overlapped,
1527 LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine)
1529 overlapped->InternalHigh = 0;
1530 return FILE_ReadFileEx(hFile,buffer,bytesToRead,overlapped,lpCompletionRoutine, INVALID_HANDLE_VALUE);
1533 static BOOL FILE_TimeoutRead(HANDLE hFile, LPVOID buffer, DWORD bytesToRead, LPDWORD bytesRead)
1538 TRACE("%d %p %ld %p\n", hFile, buffer, bytesToRead, bytesRead );
1540 ZeroMemory(&ov, sizeof (OVERLAPPED));
1541 if(STATUS_SUCCESS==NtCreateEvent(&ov.hEvent, SYNCHRONIZE, NULL, 0, 0))
1543 if(FILE_ReadFileEx(hFile, buffer, bytesToRead, &ov, NULL, ov.hEvent))
1545 r = GetOverlappedResult(hFile, &ov, bytesRead, TRUE);
1548 CloseHandle(ov.hEvent);
1552 /***********************************************************************
1553 * ReadFile (KERNEL32.@)
1555 BOOL WINAPI ReadFile( HANDLE hFile, LPVOID buffer, DWORD bytesToRead,
1556 LPDWORD bytesRead, LPOVERLAPPED overlapped )
1558 int unix_handle, result, flags;
1561 TRACE("%d %p %ld %p %p\n", hFile, buffer, bytesToRead,
1562 bytesRead, overlapped );
1564 if (bytesRead) *bytesRead = 0; /* Do this before anything else */
1565 if (!bytesToRead) return TRUE;
1567 unix_handle = FILE_GetUnixHandleType( hFile, GENERIC_READ, &type, &flags );
1569 if (flags & FD_FLAG_OVERLAPPED)
1571 if (unix_handle == -1) return FALSE;
1572 if ( (overlapped==NULL) || NtResetEvent( overlapped->hEvent, NULL ) )
1574 TRACE("Overlapped not specified or invalid event flag\n");
1576 SetLastError(ERROR_INVALID_PARAMETER);
1580 /* see if we can read some data already (this shouldn't block) */
1581 result = pread( unix_handle, buffer, bytesToRead, OVERLAPPED_OFFSET(overlapped) );
1582 if ((result < 0) && (errno == ESPIPE))
1583 result = read( unix_handle, buffer, bytesToRead );
1588 if( (errno!=EAGAIN) && (errno!=EINTR) &&
1589 ((errno != EFAULT) || IsBadWritePtr( buffer, bytesToRead )) )
1598 /* if we read enough to keep the app happy, then return now */
1599 if(result>=bytesToRead)
1601 *bytesRead = result;
1605 /* at last resort, do an overlapped read */
1606 overlapped->InternalHigh = result;
1608 if(!FILE_ReadFileEx(hFile, buffer, bytesToRead, overlapped, NULL, overlapped->hEvent))
1611 /* fail on return, with ERROR_IO_PENDING */
1612 SetLastError(ERROR_IO_PENDING);
1615 if (flags & FD_FLAG_TIMEOUT)
1618 return FILE_TimeoutRead(hFile, buffer, bytesToRead, bytesRead);
1623 return SMB_ReadFile(hFile, buffer, bytesToRead, bytesRead, NULL);
1624 case FD_TYPE_CONSOLE:
1625 return ReadConsoleA(hFile, buffer, bytesToRead, bytesRead, NULL);
1628 /* normal unix files */
1629 if (unix_handle == -1)
1634 SetLastError(ERROR_INVALID_PARAMETER);
1640 /* code for synchronous reads */
1641 while ((result = read( unix_handle, buffer, bytesToRead )) == -1)
1643 if ((errno == EAGAIN) || (errno == EINTR)) continue;
1644 if ((errno == EFAULT) && !IsBadWritePtr( buffer, bytesToRead )) continue;
1648 close( unix_handle );
1649 if (result == -1) return FALSE;
1650 if (bytesRead) *bytesRead = result;
1655 /***********************************************************************
1656 * FILE_AsyncWriteService (INTERNAL)
1658 * This function is called while the client is waiting on the
1659 * server, so we can't make any server calls here.
1661 static void FILE_AsyncWriteService(struct async_private *ovp)
1663 async_fileio *fileio = (async_fileio *) ovp;
1664 LPOVERLAPPED lpOverlapped = fileio->lpOverlapped;
1666 int already = lpOverlapped->InternalHigh;
1668 TRACE("(%p %p)\n",lpOverlapped,fileio->buffer);
1670 /* write some data (non-blocking) */
1672 result = pwrite(ovp->fd, &fileio->buffer[already], fileio->count - already,
1673 OVERLAPPED_OFFSET (lpOverlapped) + already);
1674 if ((result < 0) && (errno == ESPIPE))
1675 result = write(ovp->fd, &fileio->buffer[already], fileio->count - already);
1677 if ( (result<0) && ((errno == EAGAIN) || (errno == EINTR)))
1683 /* check to see if the transfer is complete */
1686 r = STATUS_UNSUCCESSFUL;
1690 lpOverlapped->InternalHigh += result;
1692 TRACE("wrote %d more bytes %ld/%d so far\n",result,lpOverlapped->InternalHigh,fileio->count);
1694 if(lpOverlapped->InternalHigh < fileio->count)
1700 lpOverlapped->Internal = r;
1703 /***********************************************************************
1706 static BOOL FILE_WriteFileEx(HANDLE hFile, LPCVOID buffer, DWORD bytesToWrite,
1707 LPOVERLAPPED overlapped,
1708 LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine,
1714 TRACE("file %d to buf %p num %ld %p func %p stub\n",
1715 hFile, buffer, bytesToWrite, overlapped, lpCompletionRoutine);
1717 if (overlapped == NULL)
1719 SetLastError(ERROR_INVALID_PARAMETER);
1723 fd = FILE_GetUnixHandle( hFile, GENERIC_WRITE );
1726 TRACE( "Couldn't get FD\n" );
1730 ovp = (async_fileio*) HeapAlloc(GetProcessHeap(), 0, sizeof (async_fileio));
1733 TRACE("HeapAlloc Failed\n");
1734 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1739 ovp->async.ops = &fileio_async_ops;
1740 ovp->async.handle = hFile;
1741 ovp->async.fd = FILE_GetUnixHandle( hFile, GENERIC_WRITE );
1742 ovp->async.type = ASYNC_TYPE_WRITE;
1743 ovp->async.func = FILE_AsyncWriteService;
1744 ovp->lpOverlapped = overlapped;
1745 ovp->async.event = hEvent;
1746 ovp->buffer = (LPVOID) buffer;
1747 ovp->count = bytesToWrite;
1748 ovp->completion_func = lpCompletionRoutine;
1750 return !register_new_async (&ovp->async);
1753 /***********************************************************************
1754 * WriteFileEx (KERNEL32.@)
1756 BOOL WINAPI WriteFileEx(HANDLE hFile, LPCVOID buffer, DWORD bytesToWrite,
1757 LPOVERLAPPED overlapped,
1758 LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine)
1760 overlapped->InternalHigh = 0;
1762 return FILE_WriteFileEx(hFile, buffer, bytesToWrite, overlapped, lpCompletionRoutine, INVALID_HANDLE_VALUE);
1765 /***********************************************************************
1766 * WriteFile (KERNEL32.@)
1768 BOOL WINAPI WriteFile( HANDLE hFile, LPCVOID buffer, DWORD bytesToWrite,
1769 LPDWORD bytesWritten, LPOVERLAPPED overlapped )
1771 int unix_handle, result, flags;
1774 TRACE("%d %p %ld %p %p\n", hFile, buffer, bytesToWrite,
1775 bytesWritten, overlapped );
1777 if (bytesWritten) *bytesWritten = 0; /* Do this before anything else */
1778 if (!bytesToWrite) return TRUE;
1780 unix_handle = FILE_GetUnixHandleType( hFile, GENERIC_WRITE, &type, &flags );
1782 if (flags & FD_FLAG_OVERLAPPED)
1784 if (unix_handle == -1) return FALSE;
1785 if ( (overlapped==NULL) || NtResetEvent( overlapped->hEvent, NULL ) )
1787 TRACE("Overlapped not specified or invalid event flag\n");
1789 SetLastError(ERROR_INVALID_PARAMETER);
1793 /* see if we can write some data already (this shouldn't block) */
1795 result = pwrite( unix_handle, buffer, bytesToWrite, OVERLAPPED_OFFSET (overlapped) );
1796 if ((result < 0) && (errno == ESPIPE))
1797 result = write( unix_handle, buffer, bytesToWrite );
1803 if( (errno!=EAGAIN) && (errno!=EINTR) &&
1804 ((errno != EFAULT) || IsBadReadPtr( buffer, bytesToWrite )) )
1813 /* if we wrote enough to keep the app happy, then return now */
1814 if(result>=bytesToWrite)
1816 *bytesWritten = result;
1820 /* at last resort, do an overlapped read */
1821 overlapped->Internal = STATUS_PENDING;
1822 overlapped->InternalHigh = result;
1824 if(!FILE_WriteFileEx(hFile, buffer, bytesToWrite, overlapped, NULL, overlapped->hEvent))
1827 /* fail on return, with ERROR_IO_PENDING */
1828 SetLastError(ERROR_IO_PENDING);
1834 case FD_TYPE_CONSOLE:
1835 TRACE("%d %s %ld %p %p\n", hFile, debugstr_an(buffer, bytesToWrite), bytesToWrite,
1836 bytesWritten, overlapped );
1837 return WriteConsoleA(hFile, buffer, bytesToWrite, bytesWritten, NULL);
1839 if (unix_handle == -1)
1843 /* synchronous file write */
1844 while ((result = write( unix_handle, buffer, bytesToWrite )) == -1)
1846 if ((errno == EAGAIN) || (errno == EINTR)) continue;
1847 if ((errno == EFAULT) && !IsBadReadPtr( buffer, bytesToWrite )) continue;
1848 if (errno == ENOSPC)
1849 SetLastError( ERROR_DISK_FULL );
1854 close( unix_handle );
1855 if (result == -1) return FALSE;
1856 if (bytesWritten) *bytesWritten = result;
1861 /***********************************************************************
1862 * _hread (KERNEL.349)
1864 LONG WINAPI WIN16_hread( HFILE16 hFile, SEGPTR buffer, LONG count )
1868 TRACE("%d %08lx %ld\n",
1869 hFile, (DWORD)buffer, count );
1871 /* Some programs pass a count larger than the allocated buffer */
1872 maxlen = GetSelectorLimit16( SELECTOROF(buffer) ) - OFFSETOF(buffer) + 1;
1873 if (count > maxlen) count = maxlen;
1874 return _lread(DosFileHandleToWin32Handle(hFile), MapSL(buffer), count );
1878 /***********************************************************************
1879 * _lread (KERNEL.82)
1881 UINT16 WINAPI WIN16_lread( HFILE16 hFile, SEGPTR buffer, UINT16 count )
1883 return (UINT16)WIN16_hread( hFile, buffer, (LONG)count );
1887 /***********************************************************************
1888 * _lread (KERNEL32.@)
1890 UINT WINAPI _lread( HFILE handle, LPVOID buffer, UINT count )
1893 if (!ReadFile( handle, buffer, count, &result, NULL )) return -1;
1898 /***********************************************************************
1899 * _lread16 (KERNEL.82)
1901 UINT16 WINAPI _lread16( HFILE16 hFile, LPVOID buffer, UINT16 count )
1903 return (UINT16)_lread(DosFileHandleToWin32Handle(hFile), buffer, (LONG)count );
1907 /***********************************************************************
1908 * _lcreat (KERNEL.83)
1910 HFILE16 WINAPI _lcreat16( LPCSTR path, INT16 attr )
1912 return Win32HandleToDosFileHandle( _lcreat( path, attr ) );
1916 /***********************************************************************
1917 * _lcreat (KERNEL32.@)
1919 HFILE WINAPI _lcreat( LPCSTR path, INT attr )
1921 /* Mask off all flags not explicitly allowed by the doc */
1922 attr &= FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM;
1923 TRACE("%s %02x\n", path, attr );
1924 return CreateFileA( path, GENERIC_READ | GENERIC_WRITE,
1925 FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
1926 CREATE_ALWAYS, attr, 0 );
1930 /***********************************************************************
1931 * SetFilePointer (KERNEL32.@)
1933 DWORD WINAPI SetFilePointer( HANDLE hFile, LONG distance, LONG *highword,
1936 DWORD ret = 0xffffffff;
1938 TRACE("handle %d offset %ld high %ld origin %ld\n",
1939 hFile, distance, highword?*highword:0, method );
1941 SERVER_START_REQ( set_file_pointer )
1943 req->handle = hFile;
1944 req->low = distance;
1945 req->high = highword ? *highword : (distance >= 0) ? 0 : -1;
1946 /* FIXME: assumes 1:1 mapping between Windows and Unix seek constants */
1947 req->whence = method;
1949 if (!wine_server_call_err( req ))
1951 ret = reply->new_low;
1952 if (highword) *highword = reply->new_high;
1960 /***********************************************************************
1961 * _llseek (KERNEL.84)
1964 * Seeking before the start of the file should be allowed for _llseek16,
1965 * but cause subsequent I/O operations to fail (cf. interrupt list)
1968 LONG WINAPI _llseek16( HFILE16 hFile, LONG lOffset, INT16 nOrigin )
1970 return SetFilePointer( DosFileHandleToWin32Handle(hFile), lOffset, NULL, nOrigin );
1974 /***********************************************************************
1975 * _llseek (KERNEL32.@)
1977 LONG WINAPI _llseek( HFILE hFile, LONG lOffset, INT nOrigin )
1979 return SetFilePointer( hFile, lOffset, NULL, nOrigin );
1983 /***********************************************************************
1984 * _lopen (KERNEL.85)
1986 HFILE16 WINAPI _lopen16( LPCSTR path, INT16 mode )
1988 return Win32HandleToDosFileHandle( _lopen( path, mode ) );
1992 /***********************************************************************
1993 * _lopen (KERNEL32.@)
1995 HFILE WINAPI _lopen( LPCSTR path, INT mode )
1997 DWORD access, sharing;
1999 TRACE("('%s',%04x)\n", path, mode );
2000 FILE_ConvertOFMode( mode, &access, &sharing );
2001 return CreateFileA( path, access, sharing, NULL, OPEN_EXISTING, 0, 0 );
2005 /***********************************************************************
2006 * _lwrite (KERNEL.86)
2008 UINT16 WINAPI _lwrite16( HFILE16 hFile, LPCSTR buffer, UINT16 count )
2010 return (UINT16)_hwrite( DosFileHandleToWin32Handle(hFile), buffer, (LONG)count );
2013 /***********************************************************************
2014 * _lwrite (KERNEL32.@)
2016 UINT WINAPI _lwrite( HFILE hFile, LPCSTR buffer, UINT count )
2018 return (UINT)_hwrite( hFile, buffer, (LONG)count );
2022 /***********************************************************************
2023 * _hread16 (KERNEL.349)
2025 LONG WINAPI _hread16( HFILE16 hFile, LPVOID buffer, LONG count)
2027 return _lread( DosFileHandleToWin32Handle(hFile), buffer, count );
2031 /***********************************************************************
2032 * _hread (KERNEL32.@)
2034 LONG WINAPI _hread( HFILE hFile, LPVOID buffer, LONG count)
2036 return _lread( hFile, buffer, count );
2040 /***********************************************************************
2041 * _hwrite (KERNEL.350)
2043 LONG WINAPI _hwrite16( HFILE16 hFile, LPCSTR buffer, LONG count )
2045 return _hwrite( DosFileHandleToWin32Handle(hFile), buffer, count );
2049 /***********************************************************************
2050 * _hwrite (KERNEL32.@)
2052 * experimentation yields that _lwrite:
2053 * o truncates the file at the current position with
2055 * o returns 0 on a 0 length write
2056 * o works with console handles
2059 LONG WINAPI _hwrite( HFILE handle, LPCSTR buffer, LONG count )
2063 TRACE("%d %p %ld\n", handle, buffer, count );
2067 /* Expand or truncate at current position */
2068 if (!SetEndOfFile( handle )) return HFILE_ERROR;
2071 if (!WriteFile( handle, buffer, count, &result, NULL ))
2077 /***********************************************************************
2078 * SetHandleCount (KERNEL.199)
2080 UINT16 WINAPI SetHandleCount16( UINT16 count )
2082 return SetHandleCount( count );
2086 /*************************************************************************
2087 * SetHandleCount (KERNEL32.@)
2089 UINT WINAPI SetHandleCount( UINT count )
2091 return min( 256, count );
2095 /***********************************************************************
2096 * FlushFileBuffers (KERNEL32.@)
2098 BOOL WINAPI FlushFileBuffers( HANDLE hFile )
2101 SERVER_START_REQ( flush_file )
2103 req->handle = hFile;
2104 ret = !wine_server_call_err( req );
2111 /**************************************************************************
2112 * SetEndOfFile (KERNEL32.@)
2114 BOOL WINAPI SetEndOfFile( HANDLE hFile )
2117 SERVER_START_REQ( truncate_file )
2119 req->handle = hFile;
2120 ret = !wine_server_call_err( req );
2127 /***********************************************************************
2128 * DeleteFile (KERNEL.146)
2130 BOOL16 WINAPI DeleteFile16( LPCSTR path )
2132 return DeleteFileA( path );
2136 /***********************************************************************
2137 * DeleteFileA (KERNEL32.@)
2139 BOOL WINAPI DeleteFileA( LPCSTR path )
2141 DOS_FULL_NAME full_name;
2145 SetLastError(ERROR_INVALID_PARAMETER);
2148 TRACE("'%s'\n", path );
2152 ERR("Empty path passed\n");
2155 if (DOSFS_GetDevice( path ))
2157 WARN("cannot remove DOS device '%s'!\n", path);
2158 SetLastError( ERROR_FILE_NOT_FOUND );
2162 if (!DOSFS_GetFullName( path, TRUE, &full_name )) return FALSE;
2163 if (unlink( full_name.long_name ) == -1)
2172 /***********************************************************************
2173 * DeleteFileW (KERNEL32.@)
2175 BOOL WINAPI DeleteFileW( LPCWSTR path )
2177 LPSTR xpath = HEAP_strdupWtoA( GetProcessHeap(), 0, path );
2178 BOOL ret = DeleteFileA( xpath );
2179 HeapFree( GetProcessHeap(), 0, xpath );
2184 /***********************************************************************
2185 * GetFileType (KERNEL32.@)
2187 DWORD WINAPI GetFileType( HANDLE hFile )
2189 DWORD ret = FILE_TYPE_UNKNOWN;
2190 SERVER_START_REQ( get_file_info )
2192 req->handle = hFile;
2193 if (!wine_server_call_err( req )) ret = reply->type;
2200 /* check if a file name is for an executable file (.exe or .com) */
2201 inline static BOOL is_executable( const char *name )
2203 int len = strlen(name);
2205 if (len < 4) return FALSE;
2206 return (!strcasecmp( name + len - 4, ".exe" ) ||
2207 !strcasecmp( name + len - 4, ".com" ));
2211 /***********************************************************************
2212 * FILE_AddBootRenameEntry
2214 * Adds an entry to the registry that is loaded when windows boots and
2215 * checks if there are some files to be removed or renamed/moved.
2216 * <fn1> has to be valid and <fn2> may be NULL. If both pointers are
2217 * non-NULL then the file is moved, otherwise it is deleted. The
2218 * entry of the registrykey is always appended with two zero
2219 * terminated strings. If <fn2> is NULL then the second entry is
2220 * simply a single 0-byte. Otherwise the second filename goes
2221 * there. The entries are prepended with \??\ before the path and the
2222 * second filename gets also a '!' as the first character if
2223 * MOVEFILE_REPLACE_EXISTING is set. After the final string another
2224 * 0-byte follows to indicate the end of the strings.
2226 * \??\D:\test\file1[0]
2227 * !\??\D:\test\file1_renamed[0]
2228 * \??\D:\Test|delete[0]
2229 * [0] <- file is to be deleted, second string empty
2230 * \??\D:\test\file2[0]
2231 * !\??\D:\test\file2_renamed[0]
2232 * [0] <- indicates end of strings
2235 * \??\D:\test\file1[0]
2236 * !\??\D:\test\file1_renamed[0]
2237 * \??\D:\Test|delete[0]
2238 * [0] <- file is to be deleted, second string empty
2239 * [0] <- indicates end of strings
2242 static BOOL FILE_AddBootRenameEntry( const char *fn1, const char *fn2, DWORD flags )
2244 static const char PreString[] = "\\??\\";
2245 static const char ValueName[] = "PendingFileRenameOperations";
2249 DWORD Type, len1, len2, l;
2251 BYTE *Buffer = NULL;
2253 if(RegCreateKeyA(HKEY_LOCAL_MACHINE, "SYSTEM\\CurrentControlSet\\Control\\Session Manager",
2254 &Reboot) != ERROR_SUCCESS)
2256 WARN("Error creating key for reboot managment [%s]\n",
2257 "SYSTEM\\CurrentControlSet\\Control\\Session Manager");
2261 l = strlen(PreString);
2262 len1 = strlen(fn1) + l + 1;
2265 len2 = strlen(fn2) + l + 1;
2266 if (flags & MOVEFILE_REPLACE_EXISTING) len2++; /* Plus 1 because of the leading '!' */
2268 else len2 = 1; /* minimum is the 0 byte for the empty second string */
2270 /* First we check if the key exists and if so how many bytes it already contains. */
2271 if (RegQueryValueExA(Reboot, ValueName, NULL, &Type, NULL, &DataSize) == ERROR_SUCCESS)
2273 if (Type != REG_MULTI_SZ) goto Quit;
2274 if (!(Buffer = HeapAlloc( GetProcessHeap(), 0, DataSize + len1 + len2 + 1 ))) goto Quit;
2275 if (RegQueryValueExA(Reboot, ValueName, NULL, &Type, Buffer, &DataSize) != ERROR_SUCCESS)
2277 if (DataSize) DataSize--; /* remove terminating null (will be added back later) */
2281 if (!(Buffer = HeapAlloc( GetProcessHeap(), 0, len1 + len2 + 1 ))) goto Quit;
2284 sprintf( Buffer + DataSize, "%s%s", PreString, fn1 );
2288 sprintf( Buffer + DataSize, "%s%s%s",
2289 (flags & MOVEFILE_REPLACE_EXISTING) ? "!" : "", PreString, fn2 );
2292 else Buffer[DataSize++] = 0;
2294 Buffer[DataSize++] = 0; /* add final null */
2295 rc = !RegSetValueExA( Reboot, ValueName, 0, REG_MULTI_SZ, Buffer, DataSize );
2298 if (Reboot) RegCloseKey(Reboot);
2299 if (Buffer) HeapFree( GetProcessHeap(), 0, Buffer );
2304 /**************************************************************************
2305 * MoveFileExA (KERNEL32.@)
2307 BOOL WINAPI MoveFileExA( LPCSTR fn1, LPCSTR fn2, DWORD flag )
2309 DOS_FULL_NAME full_name1, full_name2;
2311 TRACE("(%s,%s,%04lx)\n", fn1, fn2, flag);
2313 /* FIXME: <Gerhard W. Gruber>sparhawk@gmx.at
2314 In case of W9x and lesser this function should return 120 (ERROR_CALL_NOT_IMPLEMENTED)
2315 to be really compatible. Most programs wont have any problems though. In case
2316 you encounter one, this is what you should return here. I don't know what's up
2317 with NT 3.5. Is this function available there or not?
2318 Does anybody really care about 3.5? :)
2321 /* Filename1 has to be always set to a valid path. Filename2 may be NULL
2322 if the source file has to be deleted.
2325 SetLastError(ERROR_INVALID_PARAMETER);
2329 /* This function has to be run through in order to process the name properly.
2330 If the BOOTDELAY flag is set, the file doesn't need to exist though. At least
2331 that is the behaviour on NT 4.0. The operation accepts the filenames as
2332 they are given but it can't reply with a reasonable returncode. Success
2333 means in that case success for entering the values into the registry.
2335 if(!DOSFS_GetFullName( fn1, TRUE, &full_name1 ))
2337 if(!(flag & MOVEFILE_DELAY_UNTIL_REBOOT))
2341 if (fn2) /* !fn2 means delete fn1 */
2343 if (DOSFS_GetFullName( fn2, TRUE, &full_name2 ))
2345 if(!(flag & MOVEFILE_DELAY_UNTIL_REBOOT))
2347 /* target exists, check if we may overwrite */
2348 if (!(flag & MOVEFILE_REPLACE_EXISTING))
2350 /* FIXME: Use right error code */
2351 SetLastError( ERROR_ACCESS_DENIED );
2358 if (!DOSFS_GetFullName( fn2, FALSE, &full_name2 ))
2360 if(!(flag & MOVEFILE_DELAY_UNTIL_REBOOT))
2365 /* Source name and target path are valid */
2367 if (flag & MOVEFILE_DELAY_UNTIL_REBOOT)
2369 /* FIXME: (bon@elektron.ikp.physik.th-darmstadt.de 970706)
2370 Perhaps we should queue these command and execute it
2371 when exiting... What about using on_exit(2)
2373 FIXME("Please move existing file '%s' to file '%s' when Wine has finished\n",
2375 return FILE_AddBootRenameEntry( fn1, fn2, flag );
2378 if (full_name1.drive != full_name2.drive)
2380 /* use copy, if allowed */
2381 if (!(flag & MOVEFILE_COPY_ALLOWED))
2383 /* FIXME: Use right error code */
2384 SetLastError( ERROR_FILE_EXISTS );
2387 return CopyFileA( fn1, fn2, !(flag & MOVEFILE_REPLACE_EXISTING) );
2389 if (rename( full_name1.long_name, full_name2.long_name ) == -1)
2394 if (is_executable( full_name1.long_name ) != is_executable( full_name2.long_name ))
2397 if (stat( full_name2.long_name, &fstat ) != -1)
2399 if (is_executable( full_name2.long_name ))
2400 /* set executable bit where read bit is set */
2401 fstat.st_mode |= (fstat.st_mode & 0444) >> 2;
2403 fstat.st_mode &= ~0111;
2404 chmod( full_name2.long_name, fstat.st_mode );
2409 else /* fn2 == NULL means delete source */
2411 if (flag & MOVEFILE_DELAY_UNTIL_REBOOT)
2413 if (flag & MOVEFILE_COPY_ALLOWED) {
2414 WARN("Illegal flag\n");
2415 SetLastError( ERROR_GEN_FAILURE );
2418 /* FIXME: (bon@elektron.ikp.physik.th-darmstadt.de 970706)
2419 Perhaps we should queue these command and execute it
2420 when exiting... What about using on_exit(2)
2422 FIXME("Please delete file '%s' when Wine has finished\n", fn1);
2423 return FILE_AddBootRenameEntry( fn1, NULL, flag );
2426 if (unlink( full_name1.long_name ) == -1)
2431 return TRUE; /* successfully deleted */
2435 /**************************************************************************
2436 * MoveFileExW (KERNEL32.@)
2438 BOOL WINAPI MoveFileExW( LPCWSTR fn1, LPCWSTR fn2, DWORD flag )
2440 LPSTR afn1 = HEAP_strdupWtoA( GetProcessHeap(), 0, fn1 );
2441 LPSTR afn2 = HEAP_strdupWtoA( GetProcessHeap(), 0, fn2 );
2442 BOOL res = MoveFileExA( afn1, afn2, flag );
2443 HeapFree( GetProcessHeap(), 0, afn1 );
2444 HeapFree( GetProcessHeap(), 0, afn2 );
2449 /**************************************************************************
2450 * MoveFileA (KERNEL32.@)
2452 * Move file or directory
2454 BOOL WINAPI MoveFileA( LPCSTR fn1, LPCSTR fn2 )
2456 DOS_FULL_NAME full_name1, full_name2;
2459 TRACE("(%s,%s)\n", fn1, fn2 );
2461 if (!DOSFS_GetFullName( fn1, TRUE, &full_name1 )) return FALSE;
2462 if (DOSFS_GetFullName( fn2, TRUE, &full_name2 )) {
2463 /* The new name must not already exist */
2464 SetLastError(ERROR_ALREADY_EXISTS);
2467 if (!DOSFS_GetFullName( fn2, FALSE, &full_name2 )) return FALSE;
2469 if (full_name1.drive == full_name2.drive) /* move */
2470 return MoveFileExA( fn1, fn2, MOVEFILE_COPY_ALLOWED );
2473 if (stat( full_name1.long_name, &fstat ))
2475 WARN("Invalid source file %s\n",
2476 full_name1.long_name);
2480 if (S_ISDIR(fstat.st_mode)) {
2481 /* No Move for directories across file systems */
2482 /* FIXME: Use right error code */
2483 SetLastError( ERROR_GEN_FAILURE );
2486 return CopyFileA(fn1, fn2, TRUE); /*fail, if exist */
2490 /**************************************************************************
2491 * MoveFileW (KERNEL32.@)
2493 BOOL WINAPI MoveFileW( LPCWSTR fn1, LPCWSTR fn2 )
2495 LPSTR afn1 = HEAP_strdupWtoA( GetProcessHeap(), 0, fn1 );
2496 LPSTR afn2 = HEAP_strdupWtoA( GetProcessHeap(), 0, fn2 );
2497 BOOL res = MoveFileA( afn1, afn2 );
2498 HeapFree( GetProcessHeap(), 0, afn1 );
2499 HeapFree( GetProcessHeap(), 0, afn2 );
2504 /**************************************************************************
2505 * CopyFileA (KERNEL32.@)
2507 BOOL WINAPI CopyFileA( LPCSTR source, LPCSTR dest, BOOL fail_if_exists )
2510 BY_HANDLE_FILE_INFORMATION info;
2516 if ((h1 = _lopen( source, OF_READ )) == HFILE_ERROR) return FALSE;
2517 if (!GetFileInformationByHandle( h1, &info ))
2522 mode = (info.dwFileAttributes & FILE_ATTRIBUTE_READONLY) ? 0444 : 0666;
2523 if ((h2 = CreateFileA( dest, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
2524 fail_if_exists ? CREATE_NEW : CREATE_ALWAYS,
2525 info.dwFileAttributes, h1 )) == INVALID_HANDLE_VALUE)
2530 while ((count = _lread( h1, buffer, sizeof(buffer) )) > 0)
2535 INT res = _lwrite( h2, p, count );
2536 if (res <= 0) goto done;
2549 /**************************************************************************
2550 * CopyFileW (KERNEL32.@)
2552 BOOL WINAPI CopyFileW( LPCWSTR source, LPCWSTR dest, BOOL fail_if_exists)
2554 LPSTR sourceA = HEAP_strdupWtoA( GetProcessHeap(), 0, source );
2555 LPSTR destA = HEAP_strdupWtoA( GetProcessHeap(), 0, dest );
2556 BOOL ret = CopyFileA( sourceA, destA, fail_if_exists );
2557 HeapFree( GetProcessHeap(), 0, sourceA );
2558 HeapFree( GetProcessHeap(), 0, destA );
2563 /**************************************************************************
2564 * CopyFileExA (KERNEL32.@)
2566 * This implementation ignores most of the extra parameters passed-in into
2567 * the "ex" version of the method and calls the CopyFile method.
2568 * It will have to be fixed eventually.
2570 BOOL WINAPI CopyFileExA(LPCSTR sourceFilename,
2571 LPCSTR destFilename,
2572 LPPROGRESS_ROUTINE progressRoutine,
2574 LPBOOL cancelFlagPointer,
2577 BOOL failIfExists = FALSE;
2580 * Interpret the only flag that CopyFile can interpret.
2582 if ( (copyFlags & COPY_FILE_FAIL_IF_EXISTS) != 0)
2584 failIfExists = TRUE;
2587 return CopyFileA(sourceFilename, destFilename, failIfExists);
2590 /**************************************************************************
2591 * CopyFileExW (KERNEL32.@)
2593 BOOL WINAPI CopyFileExW(LPCWSTR sourceFilename,
2594 LPCWSTR destFilename,
2595 LPPROGRESS_ROUTINE progressRoutine,
2597 LPBOOL cancelFlagPointer,
2600 LPSTR sourceA = HEAP_strdupWtoA( GetProcessHeap(), 0, sourceFilename );
2601 LPSTR destA = HEAP_strdupWtoA( GetProcessHeap(), 0, destFilename );
2603 BOOL ret = CopyFileExA(sourceA,
2610 HeapFree( GetProcessHeap(), 0, sourceA );
2611 HeapFree( GetProcessHeap(), 0, destA );
2617 /***********************************************************************
2618 * SetFileTime (KERNEL32.@)
2620 BOOL WINAPI SetFileTime( HANDLE hFile,
2621 const FILETIME *lpCreationTime,
2622 const FILETIME *lpLastAccessTime,
2623 const FILETIME *lpLastWriteTime )
2626 SERVER_START_REQ( set_file_time )
2628 req->handle = hFile;
2629 if (lpLastAccessTime)
2630 RtlTimeToSecondsSince1970( lpLastAccessTime, (DWORD *)&req->access_time );
2632 req->access_time = 0; /* FIXME */
2633 if (lpLastWriteTime)
2634 RtlTimeToSecondsSince1970( lpLastWriteTime, (DWORD *)&req->write_time );
2636 req->write_time = 0; /* FIXME */
2637 ret = !wine_server_call_err( req );
2644 /**************************************************************************
2645 * LockFile (KERNEL32.@)
2647 BOOL WINAPI LockFile( HANDLE hFile, DWORD dwFileOffsetLow, DWORD dwFileOffsetHigh,
2648 DWORD nNumberOfBytesToLockLow, DWORD nNumberOfBytesToLockHigh )
2651 SERVER_START_REQ( lock_file )
2653 req->handle = hFile;
2654 req->offset_low = dwFileOffsetLow;
2655 req->offset_high = dwFileOffsetHigh;
2656 req->count_low = nNumberOfBytesToLockLow;
2657 req->count_high = nNumberOfBytesToLockHigh;
2658 ret = !wine_server_call_err( req );
2664 /**************************************************************************
2665 * LockFileEx [KERNEL32.@]
2667 * Locks a byte range within an open file for shared or exclusive access.
2674 * Per Microsoft docs, the third parameter (reserved) must be set to 0.
2676 BOOL WINAPI LockFileEx( HANDLE hFile, DWORD flags, DWORD reserved,
2677 DWORD nNumberOfBytesToLockLow, DWORD nNumberOfBytesToLockHigh,
2678 LPOVERLAPPED pOverlapped )
2680 FIXME("hFile=%d,flags=%ld,reserved=%ld,lowbytes=%ld,highbytes=%ld,overlapped=%p: stub.\n",
2681 hFile, flags, reserved, nNumberOfBytesToLockLow, nNumberOfBytesToLockHigh,
2684 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
2687 ERR("reserved == %ld: Supposed to be 0??\n", reserved);
2688 SetLastError(ERROR_INVALID_PARAMETER);
2695 /**************************************************************************
2696 * UnlockFile (KERNEL32.@)
2698 BOOL WINAPI UnlockFile( HANDLE hFile, DWORD dwFileOffsetLow, DWORD dwFileOffsetHigh,
2699 DWORD nNumberOfBytesToUnlockLow, DWORD nNumberOfBytesToUnlockHigh )
2702 SERVER_START_REQ( unlock_file )
2704 req->handle = hFile;
2705 req->offset_low = dwFileOffsetLow;
2706 req->offset_high = dwFileOffsetHigh;
2707 req->count_low = nNumberOfBytesToUnlockLow;
2708 req->count_high = nNumberOfBytesToUnlockHigh;
2709 ret = !wine_server_call_err( req );
2716 /**************************************************************************
2717 * UnlockFileEx (KERNEL32.@)
2719 BOOL WINAPI UnlockFileEx(
2722 DWORD nNumberOfBytesToUnlockLow,
2723 DWORD nNumberOfBytesToUnlockHigh,
2724 LPOVERLAPPED lpOverlapped
2727 FIXME("hFile=%d,reserved=%ld,lowbytes=%ld,highbytes=%ld,overlapped=%p: stub.\n",
2728 hFile, dwReserved, nNumberOfBytesToUnlockLow, nNumberOfBytesToUnlockHigh,
2730 if (dwReserved == 0)
2731 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
2734 ERR("reserved == %ld: Supposed to be 0??\n", dwReserved);
2735 SetLastError(ERROR_INVALID_PARAMETER);
2744 struct DOS_FILE_LOCK {
2745 struct DOS_FILE_LOCK * next;
2749 FILE_OBJECT * dos_file;
2750 /* char * unix_name;*/
2753 typedef struct DOS_FILE_LOCK DOS_FILE_LOCK;
2755 static DOS_FILE_LOCK *locks = NULL;
2756 static void DOS_RemoveFileLocks(FILE_OBJECT *file);
2759 /* Locks need to be mirrored because unix file locking is based
2760 * on the pid. Inside of wine there can be multiple WINE processes
2761 * that share the same unix pid.
2762 * Read's and writes should check these locks also - not sure
2763 * how critical that is at this point (FIXME).
2766 static BOOL DOS_AddLock(FILE_OBJECT *file, struct flock *f)
2768 DOS_FILE_LOCK *curr;
2771 processId = GetCurrentProcessId();
2773 /* check if lock overlaps a current lock for the same file */
2775 for (curr = locks; curr; curr = curr->next) {
2776 if (strcmp(curr->unix_name, file->unix_name) == 0) {
2777 if ((f->l_start == curr->base) && (f->l_len == curr->len))
2778 return TRUE;/* region is identic */
2779 if ((f->l_start < (curr->base + curr->len)) &&
2780 ((f->l_start + f->l_len) > curr->base)) {
2781 /* region overlaps */
2788 curr = HeapAlloc( GetProcessHeap(), 0, sizeof(DOS_FILE_LOCK) );
2789 curr->processId = GetCurrentProcessId();
2790 curr->base = f->l_start;
2791 curr->len = f->l_len;
2792 /* curr->unix_name = HEAP_strdupA( GetProcessHeap(), 0, file->unix_name);*/
2794 curr->dos_file = file;
2799 static void DOS_RemoveFileLocks(FILE_OBJECT *file)
2802 DOS_FILE_LOCK **curr;
2805 processId = GetCurrentProcessId();
2808 if ((*curr)->dos_file == file) {
2810 *curr = (*curr)->next;
2811 /* HeapFree( GetProcessHeap(), 0, rem->unix_name );*/
2812 HeapFree( GetProcessHeap(), 0, rem );
2815 curr = &(*curr)->next;
2819 static BOOL DOS_RemoveLock(FILE_OBJECT *file, struct flock *f)
2822 DOS_FILE_LOCK **curr;
2825 processId = GetCurrentProcessId();
2826 for (curr = &locks; *curr; curr = &(*curr)->next) {
2827 if ((*curr)->processId == processId &&
2828 (*curr)->dos_file == file &&
2829 (*curr)->base == f->l_start &&
2830 (*curr)->len == f->l_len) {
2831 /* this is the same lock */
2833 *curr = (*curr)->next;
2834 /* HeapFree( GetProcessHeap(), 0, rem->unix_name );*/
2835 HeapFree( GetProcessHeap(), 0, rem );
2839 /* no matching lock found */
2844 /**************************************************************************
2845 * LockFile (KERNEL32.@)
2847 BOOL WINAPI LockFile(
2848 HFILE hFile,DWORD dwFileOffsetLow,DWORD dwFileOffsetHigh,
2849 DWORD nNumberOfBytesToLockLow,DWORD nNumberOfBytesToLockHigh )
2854 TRACE("handle %d offsetlow=%ld offsethigh=%ld nbyteslow=%ld nbyteshigh=%ld\n",
2855 hFile, dwFileOffsetLow, dwFileOffsetHigh,
2856 nNumberOfBytesToLockLow, nNumberOfBytesToLockHigh);
2858 if (dwFileOffsetHigh || nNumberOfBytesToLockHigh) {
2859 FIXME("Unimplemented bytes > 32bits\n");
2863 f.l_start = dwFileOffsetLow;
2864 f.l_len = nNumberOfBytesToLockLow;
2865 f.l_whence = SEEK_SET;
2869 if (!(file = FILE_GetFile(hFile,0,NULL))) return FALSE;
2871 /* shadow locks internally */
2872 if (!DOS_AddLock(file, &f)) {
2873 SetLastError( ERROR_LOCK_VIOLATION );
2877 /* FIXME: Unix locking commented out for now, doesn't work with Excel */
2878 #ifdef USE_UNIX_LOCKS
2879 if (fcntl(file->unix_handle, F_SETLK, &f) == -1) {
2880 if (errno == EACCES || errno == EAGAIN) {
2881 SetLastError( ERROR_LOCK_VIOLATION );
2886 /* remove our internal copy of the lock */
2887 DOS_RemoveLock(file, &f);
2895 /**************************************************************************
2896 * UnlockFile (KERNEL32.@)
2898 BOOL WINAPI UnlockFile(
2899 HFILE hFile,DWORD dwFileOffsetLow,DWORD dwFileOffsetHigh,
2900 DWORD nNumberOfBytesToUnlockLow,DWORD nNumberOfBytesToUnlockHigh )
2905 TRACE("handle %d offsetlow=%ld offsethigh=%ld nbyteslow=%ld nbyteshigh=%ld\n",
2906 hFile, dwFileOffsetLow, dwFileOffsetHigh,
2907 nNumberOfBytesToUnlockLow, nNumberOfBytesToUnlockHigh);
2909 if (dwFileOffsetHigh || nNumberOfBytesToUnlockHigh) {
2910 WARN("Unimplemented bytes > 32bits\n");
2914 f.l_start = dwFileOffsetLow;
2915 f.l_len = nNumberOfBytesToUnlockLow;
2916 f.l_whence = SEEK_SET;
2920 if (!(file = FILE_GetFile(hFile,0,NULL))) return FALSE;
2922 DOS_RemoveLock(file, &f); /* ok if fails - may be another wine */
2924 /* FIXME: Unix locking commented out for now, doesn't work with Excel */
2925 #ifdef USE_UNIX_LOCKS
2926 if (fcntl(file->unix_handle, F_SETLK, &f) == -1) {
2935 /**************************************************************************
2936 * GetFileAttributesExA [KERNEL32.@]
2938 BOOL WINAPI GetFileAttributesExA(
2939 LPCSTR lpFileName, GET_FILEEX_INFO_LEVELS fInfoLevelId,
2940 LPVOID lpFileInformation)
2942 DOS_FULL_NAME full_name;
2943 BY_HANDLE_FILE_INFORMATION info;
2945 if (lpFileName == NULL) return FALSE;
2946 if (lpFileInformation == NULL) return FALSE;
2948 if (fInfoLevelId == GetFileExInfoStandard) {
2949 LPWIN32_FILE_ATTRIBUTE_DATA lpFad =
2950 (LPWIN32_FILE_ATTRIBUTE_DATA) lpFileInformation;
2951 if (!DOSFS_GetFullName( lpFileName, TRUE, &full_name )) return FALSE;
2952 if (!FILE_Stat( full_name.long_name, &info )) return FALSE;
2954 lpFad->dwFileAttributes = info.dwFileAttributes;
2955 lpFad->ftCreationTime = info.ftCreationTime;
2956 lpFad->ftLastAccessTime = info.ftLastAccessTime;
2957 lpFad->ftLastWriteTime = info.ftLastWriteTime;
2958 lpFad->nFileSizeHigh = info.nFileSizeHigh;
2959 lpFad->nFileSizeLow = info.nFileSizeLow;
2962 FIXME("invalid info level %d!\n", fInfoLevelId);
2970 /**************************************************************************
2971 * GetFileAttributesExW [KERNEL32.@]
2973 BOOL WINAPI GetFileAttributesExW(
2974 LPCWSTR lpFileName, GET_FILEEX_INFO_LEVELS fInfoLevelId,
2975 LPVOID lpFileInformation)
2977 LPSTR nameA = HEAP_strdupWtoA( GetProcessHeap(), 0, lpFileName );
2979 GetFileAttributesExA( nameA, fInfoLevelId, lpFileInformation);
2980 HeapFree( GetProcessHeap(), 0, nameA );