2 * File handling functions
4 * Copyright 1993 John Burton
5 * Copyright 1996 Alexandre Julliard
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 * Fix the CopyFileEx methods to implement the "extended" functionality.
23 * Right now, they simply call the CopyFile method.
27 #include "wine/port.h"
36 #ifdef HAVE_SYS_ERRNO_H
37 #include <sys/errno.h>
39 #include <sys/types.h>
41 #ifdef HAVE_SYS_MMAN_H
53 #include "wine/winbase16.h"
54 #include "wine/server.h"
64 #include "wine/debug.h"
66 WINE_DEFAULT_DEBUG_CHANNEL(file);
68 #if defined(MAP_ANONYMOUS) && !defined(MAP_ANON)
69 #define MAP_ANON MAP_ANONYMOUS
72 /* Size of per-process table of DOS handles */
73 #define DOS_TABLE_SIZE 256
75 /* Macro to derive file offset from OVERLAPPED struct */
76 #define OVERLAPPED_OFFSET(overlapped) ((off_t) (overlapped)->Offset + ((off_t) (overlapped)->OffsetHigh << 32))
78 static HANDLE dos_handles[DOS_TABLE_SIZE];
82 extern HANDLE WINAPI FILE_SmbOpen(LPCSTR name);
84 /***********************************************************************
85 * Asynchronous file I/O *
87 static DWORD fileio_get_async_status (const async_private *ovp);
88 static DWORD fileio_get_async_count (const async_private *ovp);
89 static void fileio_set_async_status (async_private *ovp, const DWORD status);
90 static void CALLBACK fileio_call_completion_func (ULONG_PTR data);
91 static void fileio_async_cleanup (async_private *ovp);
93 static async_ops fileio_async_ops =
95 fileio_get_async_status, /* get_status */
96 fileio_set_async_status, /* set_status */
97 fileio_get_async_count, /* get_count */
98 fileio_call_completion_func, /* call_completion */
99 fileio_async_cleanup /* cleanup */
102 static async_ops fileio_nocomp_async_ops =
104 fileio_get_async_status, /* get_status */
105 fileio_set_async_status, /* set_status */
106 fileio_get_async_count, /* get_count */
107 NULL, /* call_completion */
108 fileio_async_cleanup /* cleanup */
111 typedef struct async_fileio
113 struct async_private async;
114 LPOVERLAPPED lpOverlapped;
115 LPOVERLAPPED_COMPLETION_ROUTINE completion_func;
120 static DWORD fileio_get_async_status (const struct async_private *ovp)
122 return ((async_fileio*) ovp)->lpOverlapped->Internal;
125 static void fileio_set_async_status (async_private *ovp, const DWORD status)
127 ((async_fileio*) ovp)->lpOverlapped->Internal = status;
130 static DWORD fileio_get_async_count (const struct async_private *ovp)
132 async_fileio *fileio = (async_fileio*) ovp;
133 DWORD ret = fileio->count - fileio->lpOverlapped->InternalHigh;
134 return (ret < 0 ? 0 : ret);
137 static void CALLBACK fileio_call_completion_func (ULONG_PTR data)
139 async_fileio *ovp = (async_fileio*) data;
140 TRACE ("data: %p\n", ovp);
142 ovp->completion_func( ovp->lpOverlapped->Internal,
143 ovp->lpOverlapped->InternalHigh,
146 fileio_async_cleanup ( &ovp->async );
149 static void fileio_async_cleanup ( struct async_private *ovp )
151 HeapFree ( GetProcessHeap(), 0, ovp );
154 /***********************************************************************
157 * Convert OF_* mode into flags for CreateFile.
159 static void FILE_ConvertOFMode( INT mode, DWORD *access, DWORD *sharing )
163 case OF_READ: *access = GENERIC_READ; break;
164 case OF_WRITE: *access = GENERIC_WRITE; break;
165 case OF_READWRITE: *access = GENERIC_READ | GENERIC_WRITE; break;
166 default: *access = 0; break;
170 case OF_SHARE_EXCLUSIVE: *sharing = 0; break;
171 case OF_SHARE_DENY_WRITE: *sharing = FILE_SHARE_READ; break;
172 case OF_SHARE_DENY_READ: *sharing = FILE_SHARE_WRITE; break;
173 case OF_SHARE_DENY_NONE:
174 case OF_SHARE_COMPAT:
175 default: *sharing = FILE_SHARE_READ | FILE_SHARE_WRITE; break;
180 /***********************************************************************
183 * locale-independent case conversion for file I/O
185 int FILE_strcasecmp( const char *str1, const char *str2 )
189 int ret = FILE_toupper(*str1) - FILE_toupper(*str2);
190 if (ret || !*str1) return ret;
197 /***********************************************************************
200 * locale-independent case conversion for file I/O
202 int FILE_strncasecmp( const char *str1, const char *str2, int len )
205 for ( ; len > 0; len--, str1++, str2++)
206 if ((ret = FILE_toupper(*str1) - FILE_toupper(*str2)) || !*str1) break;
211 /***********************************************************************
214 * Set the DOS error code from errno.
216 void FILE_SetDosError(void)
218 int save_errno = errno; /* errno gets overwritten by printf */
220 TRACE("errno = %d %s\n", errno, strerror(errno));
224 SetLastError( ERROR_SHARING_VIOLATION );
227 SetLastError( ERROR_INVALID_HANDLE );
230 SetLastError( ERROR_HANDLE_DISK_FULL );
235 SetLastError( ERROR_ACCESS_DENIED );
238 SetLastError( ERROR_LOCK_VIOLATION );
241 SetLastError( ERROR_FILE_NOT_FOUND );
244 SetLastError( ERROR_CANNOT_MAKE );
248 SetLastError( ERROR_NO_MORE_FILES );
251 SetLastError( ERROR_FILE_EXISTS );
255 SetLastError( ERROR_SEEK );
258 SetLastError( ERROR_DIR_NOT_EMPTY );
261 SetLastError( ERROR_BAD_FORMAT );
264 WARN("unknown file error: %s\n", strerror(save_errno) );
265 SetLastError( ERROR_GEN_FAILURE );
272 /***********************************************************************
275 * Duplicate a Unix handle into a task handle.
276 * Returns 0 on failure.
278 HANDLE FILE_DupUnixHandle( int fd, DWORD access, BOOL inherit )
282 wine_server_send_fd( fd );
284 SERVER_START_REQ( alloc_file_handle )
286 req->access = access;
287 req->inherit = inherit;
289 wine_server_call( req );
297 /***********************************************************************
298 * FILE_GetUnixHandleType
300 * Retrieve the Unix handle corresponding to a file handle.
301 * Returns -1 on failure.
303 static int FILE_GetUnixHandleType( HANDLE handle, DWORD access, enum fd_type *type, int *flags )
307 ret = wine_server_handle_to_fd( handle, access, &fd, type, flags );
308 if (ret) SetLastError( RtlNtStatusToDosError(ret) );
312 /***********************************************************************
315 * Retrieve the Unix handle corresponding to a file handle.
316 * Returns -1 on failure.
318 int FILE_GetUnixHandle( HANDLE handle, DWORD access )
320 return FILE_GetUnixHandleType( handle, access, NULL, NULL );
323 /*************************************************************************
326 * Open a handle to the current process console.
327 * Returns 0 on failure.
329 static HANDLE FILE_OpenConsole( BOOL output, DWORD access, DWORD sharing, LPSECURITY_ATTRIBUTES sa )
333 SERVER_START_REQ( open_console )
336 req->access = access;
337 req->share = sharing;
338 req->inherit = (sa && (sa->nLength>=sizeof(*sa)) && sa->bInheritHandle);
340 wine_server_call_err( req );
348 /***********************************************************************
351 * Implementation of CreateFile. Takes a Unix path name.
352 * Returns 0 on failure.
354 HANDLE FILE_CreateFile( LPCSTR filename, DWORD access, DWORD sharing,
355 LPSECURITY_ATTRIBUTES sa, DWORD creation,
356 DWORD attributes, HANDLE template, BOOL fail_read_only,
364 SERVER_START_REQ( create_file )
366 req->access = access;
367 req->inherit = (sa && (sa->nLength>=sizeof(*sa)) && sa->bInheritHandle);
368 req->sharing = sharing;
369 req->create = creation;
370 req->attrs = attributes;
371 req->drive_type = drive_type;
372 wine_server_add_data( req, filename, strlen(filename) );
374 err = wine_server_call( req );
379 /* If write access failed, retry without GENERIC_WRITE */
381 if (!ret && !fail_read_only && (access & GENERIC_WRITE))
383 if ((err == STATUS_MEDIA_WRITE_PROTECTED) || (err == STATUS_ACCESS_DENIED))
385 TRACE("Write access failed for file '%s', trying without "
386 "write access\n", filename);
387 access &= ~GENERIC_WRITE;
392 if (err) SetLastError( RtlNtStatusToDosError(err) );
394 if (!ret) WARN("Unable to create file '%s' (GLE %ld)\n", filename, GetLastError());
400 /***********************************************************************
403 * Same as FILE_CreateFile but for a device
404 * Returns 0 on failure.
406 HANDLE FILE_CreateDevice( int client_id, DWORD access, LPSECURITY_ATTRIBUTES sa )
409 SERVER_START_REQ( create_device )
411 req->access = access;
412 req->inherit = (sa && (sa->nLength>=sizeof(*sa)) && sa->bInheritHandle);
415 wine_server_call_err( req );
422 static HANDLE FILE_OpenPipe(LPCSTR name, DWORD access)
424 WCHAR buffer[MAX_PATH];
428 if (name && !(len = MultiByteToWideChar( CP_ACP, 0, name, strlen(name), buffer, MAX_PATH )))
430 SetLastError( ERROR_FILENAME_EXCED_RANGE );
433 SERVER_START_REQ( open_named_pipe )
435 req->access = access;
437 wine_server_add_data( req, buffer, len * sizeof(WCHAR) );
438 wine_server_call_err( req );
442 TRACE("Returned %d\n",ret);
446 /*************************************************************************
447 * CreateFileA [KERNEL32.@] Creates or opens a file or other object
449 * Creates or opens an object, and returns a handle that can be used to
450 * access that object.
454 * filename [in] pointer to filename to be accessed
455 * access [in] access mode requested
456 * sharing [in] share mode
457 * sa [in] pointer to security attributes
458 * creation [in] how to create the file
459 * attributes [in] attributes for newly created file
460 * template [in] handle to file with extended attributes to copy
463 * Success: Open handle to specified file
464 * Failure: INVALID_HANDLE_VALUE
467 * Should call SetLastError() on failure.
471 * Doesn't support character devices, template files, or a
472 * lot of the 'attributes' flags yet.
474 HANDLE WINAPI CreateFileA( LPCSTR filename, DWORD access, DWORD sharing,
475 LPSECURITY_ATTRIBUTES sa, DWORD creation,
476 DWORD attributes, HANDLE template )
478 DOS_FULL_NAME full_name;
483 SetLastError( ERROR_INVALID_PARAMETER );
484 return INVALID_HANDLE_VALUE;
486 TRACE("%s %s%s%s%s%s%s%s\n",filename,
487 ((access & GENERIC_READ)==GENERIC_READ)?"GENERIC_READ ":"",
488 ((access & GENERIC_WRITE)==GENERIC_WRITE)?"GENERIC_WRITE ":"",
489 (!access)?"QUERY_ACCESS ":"",
490 ((sharing & FILE_SHARE_READ)==FILE_SHARE_READ)?"FILE_SHARE_READ ":"",
491 ((sharing & FILE_SHARE_WRITE)==FILE_SHARE_WRITE)?"FILE_SHARE_WRITE ":"",
492 ((sharing & FILE_SHARE_DELETE)==FILE_SHARE_DELETE)?"FILE_SHARE_DELETE ":"",
493 (creation ==CREATE_NEW)?"CREATE_NEW":
494 (creation ==CREATE_ALWAYS)?"CREATE_ALWAYS ":
495 (creation ==OPEN_EXISTING)?"OPEN_EXISTING ":
496 (creation ==OPEN_ALWAYS)?"OPEN_ALWAYS ":
497 (creation ==TRUNCATE_EXISTING)?"TRUNCATE_EXISTING ":"");
499 /* If the name starts with '\\?\', ignore the first 4 chars. */
500 if (!strncmp(filename, "\\\\?\\", 4))
503 if (!strncmp(filename, "UNC\\", 4))
505 FIXME("UNC name (%s) not supported.\n", filename );
506 SetLastError( ERROR_PATH_NOT_FOUND );
507 return INVALID_HANDLE_VALUE;
511 if (!strncmp(filename, "\\\\.\\", 4)) {
512 if(!strncasecmp(&filename[4],"pipe\\",5))
514 TRACE("Opening a pipe: %s\n",filename);
515 ret = FILE_OpenPipe(filename,access);
518 else if (isalpha(filename[4]) && filename[5] == ':' && filename[6] == '\0')
520 ret = FILE_CreateDevice( (toupper(filename[4]) - 'A') | 0x20000, access, sa );
523 else if (!DOSFS_GetDevice( filename ))
525 ret = DEVICE_Open( filename+4, access, sa );
529 filename+=4; /* fall into DOSFS_Device case below */
532 /* If the name still starts with '\\', it's a UNC name. */
533 if (!strncmp(filename, "\\\\", 2))
535 ret = SMB_CreateFileA(filename, access, sharing, sa, creation, attributes, template );
539 /* If the name contains a DOS wild card (* or ?), do no create a file */
540 if(strchr(filename,'*') || strchr(filename,'?'))
541 return INVALID_HANDLE_VALUE;
543 /* Open a console for CONIN$ or CONOUT$ */
544 if (!strcasecmp(filename, "CONIN$"))
546 ret = FILE_OpenConsole( FALSE, access, sharing, sa );
549 if (!strcasecmp(filename, "CONOUT$"))
551 ret = FILE_OpenConsole( TRUE, access, sharing, sa );
555 if (DOSFS_GetDevice( filename ))
557 TRACE("opening device '%s'\n", filename );
559 if (!(ret = DOSFS_OpenDevice( filename, access, attributes, sa )))
561 /* Do not silence this please. It is a critical error. -MM */
562 ERR("Couldn't open device '%s'!\n",filename);
563 SetLastError( ERROR_FILE_NOT_FOUND );
568 /* check for filename, don't check for last entry if creating */
569 if (!DOSFS_GetFullName( filename,
570 (creation == OPEN_EXISTING) ||
571 (creation == TRUNCATE_EXISTING),
573 WARN("Unable to get full filename from '%s' (GLE %ld)\n",
574 filename, GetLastError());
575 return INVALID_HANDLE_VALUE;
578 ret = FILE_CreateFile( full_name.long_name, access, sharing,
579 sa, creation, attributes, template,
580 DRIVE_GetFlags(full_name.drive) & DRIVE_FAIL_READ_ONLY,
581 GetDriveTypeA( full_name.short_name ) );
583 if (!ret) ret = INVALID_HANDLE_VALUE;
589 /*************************************************************************
590 * CreateFileW (KERNEL32.@)
592 HANDLE WINAPI CreateFileW( LPCWSTR filename, DWORD access, DWORD sharing,
593 LPSECURITY_ATTRIBUTES sa, DWORD creation,
594 DWORD attributes, HANDLE template)
596 LPSTR afn = HEAP_strdupWtoA( GetProcessHeap(), 0, filename );
597 HANDLE res = CreateFileA( afn, access, sharing, sa, creation, attributes, template );
598 HeapFree( GetProcessHeap(), 0, afn );
603 /***********************************************************************
606 * Fill a file information from a struct stat.
608 static void FILE_FillInfo( struct stat *st, BY_HANDLE_FILE_INFORMATION *info )
610 if (S_ISDIR(st->st_mode))
611 info->dwFileAttributes = FILE_ATTRIBUTE_DIRECTORY;
613 info->dwFileAttributes = FILE_ATTRIBUTE_ARCHIVE;
614 if (!(st->st_mode & S_IWUSR))
615 info->dwFileAttributes |= FILE_ATTRIBUTE_READONLY;
617 RtlSecondsSince1970ToTime( st->st_mtime, &info->ftCreationTime );
618 RtlSecondsSince1970ToTime( st->st_mtime, &info->ftLastWriteTime );
619 RtlSecondsSince1970ToTime( st->st_atime, &info->ftLastAccessTime );
621 info->dwVolumeSerialNumber = 0; /* FIXME */
622 info->nFileSizeHigh = 0;
623 info->nFileSizeLow = 0;
624 if (!S_ISDIR(st->st_mode)) {
625 info->nFileSizeHigh = st->st_size >> 32;
626 info->nFileSizeLow = st->st_size & 0xffffffff;
628 info->nNumberOfLinks = st->st_nlink;
629 info->nFileIndexHigh = 0;
630 info->nFileIndexLow = st->st_ino;
634 /***********************************************************************
637 * Stat a Unix path name. Return TRUE if OK.
639 BOOL FILE_Stat( LPCSTR unixName, BY_HANDLE_FILE_INFORMATION *info )
643 if (lstat( unixName, &st ) == -1)
648 if (!S_ISLNK(st.st_mode)) FILE_FillInfo( &st, info );
651 /* do a "real" stat to find out
652 about the type of the symlink destination */
653 if (stat( unixName, &st ) == -1)
658 FILE_FillInfo( &st, info );
659 info->dwFileAttributes |= FILE_ATTRIBUTE_SYMLINK;
665 /***********************************************************************
666 * GetFileInformationByHandle (KERNEL32.@)
668 DWORD WINAPI GetFileInformationByHandle( HANDLE hFile,
669 BY_HANDLE_FILE_INFORMATION *info )
674 SERVER_START_REQ( get_file_info )
677 if ((ret = !wine_server_call_err( req )))
679 /* FIXME: which file types are supported ?
680 * Serial ports (FILE_TYPE_CHAR) are not,
681 * and MSDN also says that pipes are not supported.
682 * FILE_TYPE_REMOTE seems to be supported according to
683 * MSDN q234741.txt */
684 if ((reply->type == FILE_TYPE_DISK) || (reply->type == FILE_TYPE_REMOTE))
686 RtlSecondsSince1970ToTime( reply->write_time, &info->ftCreationTime );
687 RtlSecondsSince1970ToTime( reply->write_time, &info->ftLastWriteTime );
688 RtlSecondsSince1970ToTime( reply->access_time, &info->ftLastAccessTime );
689 info->dwFileAttributes = reply->attr;
690 info->dwVolumeSerialNumber = reply->serial;
691 info->nFileSizeHigh = reply->size_high;
692 info->nFileSizeLow = reply->size_low;
693 info->nNumberOfLinks = reply->links;
694 info->nFileIndexHigh = reply->index_high;
695 info->nFileIndexLow = reply->index_low;
699 SetLastError(ERROR_NOT_SUPPORTED);
709 /**************************************************************************
710 * GetFileAttributes (KERNEL.420)
712 DWORD WINAPI GetFileAttributes16( LPCSTR name )
714 return GetFileAttributesA( name );
718 /**************************************************************************
719 * GetFileAttributesA (KERNEL32.@)
721 DWORD WINAPI GetFileAttributesA( LPCSTR name )
723 DOS_FULL_NAME full_name;
724 BY_HANDLE_FILE_INFORMATION info;
728 SetLastError( ERROR_INVALID_PARAMETER );
731 if (!DOSFS_GetFullName( name, TRUE, &full_name) )
733 if (!FILE_Stat( full_name.long_name, &info )) return -1;
734 return info.dwFileAttributes;
738 /**************************************************************************
739 * GetFileAttributesW (KERNEL32.@)
741 DWORD WINAPI GetFileAttributesW( LPCWSTR name )
743 LPSTR nameA = HEAP_strdupWtoA( GetProcessHeap(), 0, name );
744 DWORD res = GetFileAttributesA( nameA );
745 HeapFree( GetProcessHeap(), 0, nameA );
750 /**************************************************************************
751 * SetFileAttributes (KERNEL.421)
753 BOOL16 WINAPI SetFileAttributes16( LPCSTR lpFileName, DWORD attributes )
755 return SetFileAttributesA( lpFileName, attributes );
759 /**************************************************************************
760 * SetFileAttributesA (KERNEL32.@)
762 BOOL WINAPI SetFileAttributesA(LPCSTR lpFileName, DWORD attributes)
765 DOS_FULL_NAME full_name;
767 if (!DOSFS_GetFullName( lpFileName, TRUE, &full_name ))
770 TRACE("(%s,%lx)\n",lpFileName,attributes);
771 if (attributes & FILE_ATTRIBUTE_NORMAL) {
772 attributes &= ~FILE_ATTRIBUTE_NORMAL;
774 FIXME("(%s):%lx illegal combination with FILE_ATTRIBUTE_NORMAL.\n", lpFileName,attributes);
776 if(stat(full_name.long_name,&buf)==-1)
781 if (attributes & FILE_ATTRIBUTE_READONLY)
783 if(S_ISDIR(buf.st_mode))
785 WARN("FILE_ATTRIBUTE_READONLY ignored for directory.\n");
787 buf.st_mode &= ~0222; /* octal!, clear write permission bits */
788 attributes &= ~FILE_ATTRIBUTE_READONLY;
792 /* add write permission */
793 buf.st_mode |= (0600 | ((buf.st_mode & 044) >> 1)) & (~FILE_umask);
795 if (attributes & FILE_ATTRIBUTE_DIRECTORY)
797 if (!S_ISDIR(buf.st_mode))
798 FIXME("SetFileAttributes expected the file '%s' to be a directory",
800 attributes &= ~FILE_ATTRIBUTE_DIRECTORY;
802 attributes &= ~(FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_HIDDEN|FILE_ATTRIBUTE_SYSTEM);
804 FIXME("(%s):%lx attribute(s) not implemented.\n", lpFileName,attributes);
805 if (-1==chmod(full_name.long_name,buf.st_mode))
807 if(GetDriveTypeA(lpFileName) == DRIVE_CDROM) {
808 SetLastError( ERROR_ACCESS_DENIED );
813 * FIXME: We don't return FALSE here because of differences between
814 * Linux and Windows privileges. Under Linux only the owner of
815 * the file is allowed to change file attributes. Under Windows,
816 * applications expect that if you can write to a file, you can also
817 * change its attributes (see GENERIC_WRITE). We could try to be
818 * clever here but that would break multi-user installations where
819 * users share read-only DLLs. This is because some installers like
820 * to change attributes of already installed DLLs.
822 FIXME("Couldn't set file attributes for existing file \"%s\".\n"
823 "Check permissions or set VFAT \"quiet\" mount flag\n", full_name.long_name);
829 /**************************************************************************
830 * SetFileAttributesW (KERNEL32.@)
832 BOOL WINAPI SetFileAttributesW(LPCWSTR lpFileName, DWORD attributes)
835 DWORD len = WideCharToMultiByte( CP_ACP, 0, lpFileName, -1, NULL, 0, NULL, NULL );
836 LPSTR afn = HeapAlloc( GetProcessHeap(), 0, len );
838 WideCharToMultiByte( CP_ACP, 0, lpFileName, -1, afn, len, NULL, NULL );
839 res = SetFileAttributesA( afn, attributes );
840 HeapFree( GetProcessHeap(), 0, afn );
845 /***********************************************************************
846 * GetFileSize (KERNEL32.@)
848 DWORD WINAPI GetFileSize( HANDLE hFile, LPDWORD filesizehigh )
850 BY_HANDLE_FILE_INFORMATION info;
851 if (!GetFileInformationByHandle( hFile, &info )) return -1;
852 if (filesizehigh) *filesizehigh = info.nFileSizeHigh;
853 return info.nFileSizeLow;
857 /***********************************************************************
858 * GetFileTime (KERNEL32.@)
860 BOOL WINAPI GetFileTime( HANDLE hFile, FILETIME *lpCreationTime,
861 FILETIME *lpLastAccessTime,
862 FILETIME *lpLastWriteTime )
864 BY_HANDLE_FILE_INFORMATION info;
865 if (!GetFileInformationByHandle( hFile, &info )) return FALSE;
866 if (lpCreationTime) *lpCreationTime = info.ftCreationTime;
867 if (lpLastAccessTime) *lpLastAccessTime = info.ftLastAccessTime;
868 if (lpLastWriteTime) *lpLastWriteTime = info.ftLastWriteTime;
872 /***********************************************************************
873 * CompareFileTime (KERNEL32.@)
875 INT WINAPI CompareFileTime( LPFILETIME x, LPFILETIME y )
877 if (!x || !y) return -1;
879 if (x->dwHighDateTime > y->dwHighDateTime)
881 if (x->dwHighDateTime < y->dwHighDateTime)
883 if (x->dwLowDateTime > y->dwLowDateTime)
885 if (x->dwLowDateTime < y->dwLowDateTime)
890 /***********************************************************************
891 * FILE_GetTempFileName : utility for GetTempFileName
893 static UINT FILE_GetTempFileName( LPCSTR path, LPCSTR prefix, UINT unique,
894 LPSTR buffer, BOOL isWin16 )
896 static UINT unique_temp;
897 DOS_FULL_NAME full_name;
902 if ( !path || !prefix || !buffer ) return 0;
904 if (!unique_temp) unique_temp = time(NULL) & 0xffff;
905 num = unique ? (unique & 0xffff) : (unique_temp++ & 0xffff);
907 strcpy( buffer, path );
908 p = buffer + strlen(buffer);
910 /* add a \, if there isn't one and path is more than just the drive letter ... */
911 if ( !((strlen(buffer) == 2) && (buffer[1] == ':'))
912 && ((p == buffer) || (p[-1] != '\\'))) *p++ = '\\';
914 if (isWin16) *p++ = '~';
915 for (i = 3; (i > 0) && (*prefix); i--) *p++ = *prefix++;
916 sprintf( p, "%04x.tmp", num );
918 /* Now try to create it */
924 HFILE handle = CreateFileA( buffer, GENERIC_WRITE, 0, NULL,
925 CREATE_NEW, FILE_ATTRIBUTE_NORMAL, 0 );
926 if (handle != INVALID_HANDLE_VALUE)
927 { /* We created it */
928 TRACE("created %s\n",
930 CloseHandle( handle );
933 if (GetLastError() != ERROR_FILE_EXISTS)
934 break; /* No need to go on */
936 sprintf( p, "%04x.tmp", num );
937 } while (num != (unique & 0xffff));
940 /* Get the full path name */
942 if (DOSFS_GetFullName( buffer, FALSE, &full_name ))
944 /* Check if we have write access in the directory */
945 if ((p = strrchr( full_name.long_name, '/' ))) *p = '\0';
946 if (access( full_name.long_name, W_OK ) == -1)
947 WARN("returns '%s', which doesn't seem to be writeable.\n",
950 TRACE("returning %s\n", buffer );
951 return unique ? unique : num;
955 /***********************************************************************
956 * GetTempFileNameA (KERNEL32.@)
958 UINT WINAPI GetTempFileNameA( LPCSTR path, LPCSTR prefix, UINT unique,
961 return FILE_GetTempFileName(path, prefix, unique, buffer, FALSE);
964 /***********************************************************************
965 * GetTempFileNameW (KERNEL32.@)
967 UINT WINAPI GetTempFileNameW( LPCWSTR path, LPCWSTR prefix, UINT unique,
975 patha = HEAP_strdupWtoA( GetProcessHeap(), 0, path );
976 prefixa = HEAP_strdupWtoA( GetProcessHeap(), 0, prefix );
977 ret = FILE_GetTempFileName( patha, prefixa, unique, buffera, FALSE );
978 MultiByteToWideChar( CP_ACP, 0, buffera, -1, buffer, MAX_PATH );
979 HeapFree( GetProcessHeap(), 0, patha );
980 HeapFree( GetProcessHeap(), 0, prefixa );
985 /***********************************************************************
986 * GetTempFileName (KERNEL.97)
988 UINT16 WINAPI GetTempFileName16( BYTE drive, LPCSTR prefix, UINT16 unique,
993 if (!(drive & ~TF_FORCEDRIVE)) /* drive 0 means current default drive */
994 drive |= DRIVE_GetCurrentDrive() + 'A';
996 if ((drive & TF_FORCEDRIVE) &&
997 !DRIVE_IsValid( toupper(drive & ~TF_FORCEDRIVE) - 'A' ))
999 drive &= ~TF_FORCEDRIVE;
1000 WARN("invalid drive %d specified\n", drive );
1003 if (drive & TF_FORCEDRIVE)
1004 sprintf(temppath,"%c:", drive & ~TF_FORCEDRIVE );
1006 GetTempPathA( 132, temppath );
1007 return (UINT16)FILE_GetTempFileName( temppath, prefix, unique, buffer, TRUE );
1010 /***********************************************************************
1013 * Implementation of OpenFile16() and OpenFile32().
1015 static HFILE FILE_DoOpenFile( LPCSTR name, OFSTRUCT *ofs, UINT mode,
1020 WORD filedatetime[2];
1021 DOS_FULL_NAME full_name;
1022 DWORD access, sharing;
1025 if (!ofs) return HFILE_ERROR;
1027 TRACE("%s %s %s %s%s%s%s%s%s%s%s%s\n",name,
1028 ((mode & 0x3 )==OF_READ)?"OF_READ":
1029 ((mode & 0x3 )==OF_WRITE)?"OF_WRITE":
1030 ((mode & 0x3 )==OF_READWRITE)?"OF_READWRITE":"unknown",
1031 ((mode & 0x70 )==OF_SHARE_COMPAT)?"OF_SHARE_COMPAT":
1032 ((mode & 0x70 )==OF_SHARE_DENY_NONE)?"OF_SHARE_DENY_NONE":
1033 ((mode & 0x70 )==OF_SHARE_DENY_READ)?"OF_SHARE_DENY_READ":
1034 ((mode & 0x70 )==OF_SHARE_DENY_WRITE)?"OF_SHARE_DENY_WRITE":
1035 ((mode & 0x70 )==OF_SHARE_EXCLUSIVE)?"OF_SHARE_EXCLUSIVE":"unknown",
1036 ((mode & OF_PARSE )==OF_PARSE)?"OF_PARSE ":"",
1037 ((mode & OF_DELETE )==OF_DELETE)?"OF_DELETE ":"",
1038 ((mode & OF_VERIFY )==OF_VERIFY)?"OF_VERIFY ":"",
1039 ((mode & OF_SEARCH )==OF_SEARCH)?"OF_SEARCH ":"",
1040 ((mode & OF_CANCEL )==OF_CANCEL)?"OF_CANCEL ":"",
1041 ((mode & OF_CREATE )==OF_CREATE)?"OF_CREATE ":"",
1042 ((mode & OF_PROMPT )==OF_PROMPT)?"OF_PROMPT ":"",
1043 ((mode & OF_EXIST )==OF_EXIST)?"OF_EXIST ":"",
1044 ((mode & OF_REOPEN )==OF_REOPEN)?"OF_REOPEN ":""
1048 ofs->cBytes = sizeof(OFSTRUCT);
1050 if (mode & OF_REOPEN) name = ofs->szPathName;
1053 ERR("called with `name' set to NULL ! Please debug.\n");
1057 TRACE("%s %04x\n", name, mode );
1059 /* the watcom 10.6 IDE relies on a valid path returned in ofs->szPathName
1060 Are there any cases where getting the path here is wrong?
1061 Uwe Bonnes 1997 Apr 2 */
1062 if (!GetFullPathNameA( name, sizeof(ofs->szPathName),
1063 ofs->szPathName, NULL )) goto error;
1064 FILE_ConvertOFMode( mode, &access, &sharing );
1066 /* OF_PARSE simply fills the structure */
1068 if (mode & OF_PARSE)
1070 ofs->fFixedDisk = (GetDriveType16( ofs->szPathName[0]-'A' )
1071 != DRIVE_REMOVABLE);
1072 TRACE("(%s): OF_PARSE, res = '%s'\n",
1073 name, ofs->szPathName );
1077 /* OF_CREATE is completely different from all other options, so
1080 if (mode & OF_CREATE)
1082 if ((hFileRet = CreateFileA( name, GENERIC_READ | GENERIC_WRITE,
1083 sharing, NULL, CREATE_ALWAYS,
1084 FILE_ATTRIBUTE_NORMAL, 0 ))== INVALID_HANDLE_VALUE)
1089 /* If OF_SEARCH is set, ignore the given path */
1091 if ((mode & OF_SEARCH) && !(mode & OF_REOPEN))
1093 /* First try the file name as is */
1094 if (DOSFS_GetFullName( name, TRUE, &full_name )) goto found;
1095 /* Now remove the path */
1096 if (name[0] && (name[1] == ':')) name += 2;
1097 if ((p = strrchr( name, '\\' ))) name = p + 1;
1098 if ((p = strrchr( name, '/' ))) name = p + 1;
1099 if (!name[0]) goto not_found;
1102 /* Now look for the file */
1104 if (!DIR_SearchPath( NULL, name, NULL, &full_name, win32 )) goto not_found;
1107 TRACE("found %s = %s\n",
1108 full_name.long_name, full_name.short_name );
1109 lstrcpynA( ofs->szPathName, full_name.short_name,
1110 sizeof(ofs->szPathName) );
1112 if (mode & OF_SHARE_EXCLUSIVE)
1113 /* Some InstallShield version uses OF_SHARE_EXCLUSIVE
1114 on the file <tempdir>/_ins0432._mp to determine how
1115 far installation has proceeded.
1116 _ins0432._mp is an executable and while running the
1117 application expects the open with OF_SHARE_ to fail*/
1119 As our loader closes the files after loading the executable,
1120 we can't find the running executable with FILE_InUse.
1121 The loader should keep the file open, as Windows does that, too.
1124 char *last = strrchr(full_name.long_name,'/');
1126 last = full_name.long_name - 1;
1127 if (GetModuleHandle16(last+1))
1129 TRACE("Denying shared open for %s\n",full_name.long_name);
1134 if (mode & OF_DELETE)
1136 if (unlink( full_name.long_name ) == -1) goto not_found;
1137 TRACE("(%s): OF_DELETE return = OK\n", name);
1141 hFileRet = FILE_CreateFile( full_name.long_name, access, sharing,
1142 NULL, OPEN_EXISTING, 0, 0,
1143 DRIVE_GetFlags(full_name.drive) & DRIVE_FAIL_READ_ONLY,
1144 GetDriveTypeA( full_name.short_name ) );
1145 if (!hFileRet) goto not_found;
1147 GetFileTime( hFileRet, NULL, NULL, &filetime );
1148 FileTimeToDosDateTime( &filetime, &filedatetime[0], &filedatetime[1] );
1149 if ((mode & OF_VERIFY) && (mode & OF_REOPEN))
1151 if (memcmp( ofs->reserved, filedatetime, sizeof(ofs->reserved) ))
1153 CloseHandle( hFileRet );
1154 WARN("(%s): OF_VERIFY failed\n", name );
1155 /* FIXME: what error here? */
1156 SetLastError( ERROR_FILE_NOT_FOUND );
1160 memcpy( ofs->reserved, filedatetime, sizeof(ofs->reserved) );
1162 success: /* We get here if the open was successful */
1163 TRACE("(%s): OK, return = %d\n", name, hFileRet );
1166 if (mode & OF_EXIST) /* Return the handle, but close it first */
1167 CloseHandle( hFileRet );
1171 hFileRet = Win32HandleToDosFileHandle( hFileRet );
1172 if (hFileRet == HFILE_ERROR16) goto error;
1173 if (mode & OF_EXIST) /* Return the handle, but close it first */
1174 _lclose16( hFileRet );
1178 not_found: /* We get here if the file does not exist */
1179 WARN("'%s' not found or sharing violation\n", name );
1180 SetLastError( ERROR_FILE_NOT_FOUND );
1183 error: /* We get here if there was an error opening the file */
1184 ofs->nErrCode = GetLastError();
1185 WARN("(%s): return = HFILE_ERROR error= %d\n",
1186 name,ofs->nErrCode );
1191 /***********************************************************************
1192 * OpenFile (KERNEL.74)
1193 * OpenFileEx (KERNEL.360)
1195 HFILE16 WINAPI OpenFile16( LPCSTR name, OFSTRUCT *ofs, UINT16 mode )
1197 return FILE_DoOpenFile( name, ofs, mode, FALSE );
1201 /***********************************************************************
1202 * OpenFile (KERNEL32.@)
1204 HFILE WINAPI OpenFile( LPCSTR name, OFSTRUCT *ofs, UINT mode )
1206 return FILE_DoOpenFile( name, ofs, mode, TRUE );
1210 /***********************************************************************
1211 * FILE_InitProcessDosHandles
1213 * Allocates the default DOS handles for a process. Called either by
1214 * Win32HandleToDosFileHandle below or by the DOSVM stuff.
1216 static void FILE_InitProcessDosHandles( void )
1218 dos_handles[0] = GetStdHandle(STD_INPUT_HANDLE);
1219 dos_handles[1] = GetStdHandle(STD_OUTPUT_HANDLE);
1220 dos_handles[2] = GetStdHandle(STD_ERROR_HANDLE);
1221 dos_handles[3] = GetStdHandle(STD_ERROR_HANDLE);
1222 dos_handles[4] = GetStdHandle(STD_ERROR_HANDLE);
1225 /***********************************************************************
1226 * Win32HandleToDosFileHandle (KERNEL32.21)
1228 * Allocate a DOS handle for a Win32 handle. The Win32 handle is no
1229 * longer valid after this function (even on failure).
1231 * Note: this is not exactly right, since on Win95 the Win32 handles
1232 * are on top of DOS handles and we do it the other way
1233 * around. Should be good enough though.
1235 HFILE WINAPI Win32HandleToDosFileHandle( HANDLE handle )
1239 if (!handle || (handle == INVALID_HANDLE_VALUE))
1242 for (i = 5; i < DOS_TABLE_SIZE; i++)
1243 if (!dos_handles[i])
1245 dos_handles[i] = handle;
1246 TRACE("Got %d for h32 %d\n", i, handle );
1249 CloseHandle( handle );
1250 SetLastError( ERROR_TOO_MANY_OPEN_FILES );
1255 /***********************************************************************
1256 * DosFileHandleToWin32Handle (KERNEL32.20)
1258 * Return the Win32 handle for a DOS handle.
1260 * Note: this is not exactly right, since on Win95 the Win32 handles
1261 * are on top of DOS handles and we do it the other way
1262 * around. Should be good enough though.
1264 HANDLE WINAPI DosFileHandleToWin32Handle( HFILE handle )
1266 HFILE16 hfile = (HFILE16)handle;
1267 if (hfile < 5 && !dos_handles[hfile]) FILE_InitProcessDosHandles();
1268 if ((hfile >= DOS_TABLE_SIZE) || !dos_handles[hfile])
1270 SetLastError( ERROR_INVALID_HANDLE );
1271 return INVALID_HANDLE_VALUE;
1273 return dos_handles[hfile];
1277 /***********************************************************************
1278 * DisposeLZ32Handle (KERNEL32.22)
1280 * Note: this is not entirely correct, we should only close the
1281 * 32-bit handle and not the 16-bit one, but we cannot do
1282 * this because of the way our DOS handles are implemented.
1283 * It shouldn't break anything though.
1285 void WINAPI DisposeLZ32Handle( HANDLE handle )
1289 if (!handle || (handle == INVALID_HANDLE_VALUE)) return;
1291 for (i = 5; i < DOS_TABLE_SIZE; i++)
1292 if (dos_handles[i] == handle)
1295 CloseHandle( handle );
1301 /***********************************************************************
1304 * dup2() function for DOS handles.
1306 HFILE16 FILE_Dup2( HFILE16 hFile1, HFILE16 hFile2 )
1310 if (hFile1 < 5 && !dos_handles[hFile1]) FILE_InitProcessDosHandles();
1312 if ((hFile1 >= DOS_TABLE_SIZE) || (hFile2 >= DOS_TABLE_SIZE) || !dos_handles[hFile1])
1314 SetLastError( ERROR_INVALID_HANDLE );
1315 return HFILE_ERROR16;
1319 FIXME("stdio handle closed, need proper conversion\n" );
1320 SetLastError( ERROR_INVALID_HANDLE );
1321 return HFILE_ERROR16;
1323 if (!DuplicateHandle( GetCurrentProcess(), dos_handles[hFile1],
1324 GetCurrentProcess(), &new_handle,
1325 0, FALSE, DUPLICATE_SAME_ACCESS ))
1326 return HFILE_ERROR16;
1327 if (dos_handles[hFile2]) CloseHandle( dos_handles[hFile2] );
1328 dos_handles[hFile2] = new_handle;
1333 /***********************************************************************
1334 * _lclose (KERNEL.81)
1336 HFILE16 WINAPI _lclose16( HFILE16 hFile )
1340 FIXME("stdio handle closed, need proper conversion\n" );
1341 SetLastError( ERROR_INVALID_HANDLE );
1342 return HFILE_ERROR16;
1344 if ((hFile >= DOS_TABLE_SIZE) || !dos_handles[hFile])
1346 SetLastError( ERROR_INVALID_HANDLE );
1347 return HFILE_ERROR16;
1349 TRACE("%d (handle32=%d)\n", hFile, dos_handles[hFile] );
1350 CloseHandle( dos_handles[hFile] );
1351 dos_handles[hFile] = 0;
1356 /***********************************************************************
1357 * _lclose (KERNEL32.@)
1359 HFILE WINAPI _lclose( HFILE hFile )
1361 TRACE("handle %d\n", hFile );
1362 return CloseHandle( hFile ) ? 0 : HFILE_ERROR;
1365 /***********************************************************************
1366 * GetOverlappedResult (KERNEL32.@)
1368 * Check the result of an Asynchronous data transfer from a file.
1374 * If successful (and relevant) lpTransferred will hold the number of
1375 * bytes transferred during the async operation.
1379 * Currently only works for WaitCommEvent, ReadFile, WriteFile
1380 * with communications ports.
1383 BOOL WINAPI GetOverlappedResult(
1384 HANDLE hFile, /* [in] handle of file to check on */
1385 LPOVERLAPPED lpOverlapped, /* [in/out] pointer to overlapped */
1386 LPDWORD lpTransferred, /* [in/out] number of bytes transferred */
1387 BOOL bWait /* [in] wait for the transfer to complete ? */
1391 TRACE("(%d %p %p %x)\n", hFile, lpOverlapped, lpTransferred, bWait);
1393 if(lpOverlapped==NULL)
1395 ERR("lpOverlapped was null\n");
1398 if(!lpOverlapped->hEvent)
1400 ERR("lpOverlapped->hEvent was null\n");
1405 TRACE("waiting on %p\n",lpOverlapped);
1406 r = WaitForSingleObjectEx(lpOverlapped->hEvent, bWait?INFINITE:0, TRUE);
1407 TRACE("wait on %p returned %ld\n",lpOverlapped,r);
1408 } while (r==STATUS_USER_APC);
1411 *lpTransferred = lpOverlapped->InternalHigh;
1413 SetLastError ( lpOverlapped->Internal == STATUS_PENDING ?
1414 ERROR_IO_INCOMPLETE : lpOverlapped->Internal );
1416 return (r==WAIT_OBJECT_0);
1419 /***********************************************************************
1420 * CancelIo (KERNEL32.@)
1422 BOOL WINAPI CancelIo(HANDLE handle)
1424 async_private *ovp,*t;
1426 TRACE("handle = %x\n",handle);
1428 for (ovp = NtCurrentTeb()->pending_list; ovp; ovp = t)
1431 if ( ovp->handle == handle )
1432 cancel_async ( ovp );
1434 WaitForMultipleObjectsEx(0,NULL,FALSE,1,TRUE);
1438 /***********************************************************************
1439 * FILE_AsyncReadService (INTERNAL)
1441 * This function is called while the client is waiting on the
1442 * server, so we can't make any server calls here.
1444 static void FILE_AsyncReadService(async_private *ovp)
1446 async_fileio *fileio = (async_fileio*) ovp;
1447 LPOVERLAPPED lpOverlapped = fileio->lpOverlapped;
1449 int already = lpOverlapped->InternalHigh;
1451 TRACE("%p %p\n", lpOverlapped, fileio->buffer );
1453 /* check to see if the data is ready (non-blocking) */
1455 result = pread (ovp->fd, &fileio->buffer[already], fileio->count - already,
1456 OVERLAPPED_OFFSET (lpOverlapped) + already);
1457 if ((result < 0) && (errno == ESPIPE))
1458 result = read (ovp->fd, &fileio->buffer[already], fileio->count - already);
1460 if ( (result<0) && ((errno == EAGAIN) || (errno == EINTR)))
1462 TRACE("Deferred read %d\n",errno);
1467 /* check to see if the transfer is complete */
1470 TRACE("read returned errno %d\n",errno);
1471 r = STATUS_UNSUCCESSFUL;
1475 lpOverlapped->InternalHigh += result;
1476 TRACE("read %d more bytes %ld/%d so far\n",result,lpOverlapped->InternalHigh,fileio->count);
1478 if(lpOverlapped->InternalHigh < fileio->count)
1484 lpOverlapped->Internal = r;
1487 /***********************************************************************
1488 * FILE_ReadFileEx (INTERNAL)
1490 static BOOL FILE_ReadFileEx(HANDLE hFile, LPVOID buffer, DWORD bytesToRead,
1491 LPOVERLAPPED overlapped,
1492 LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine,
1500 TRACE("file %d to buf %p num %ld %p func %p\n",
1501 hFile, buffer, bytesToRead, overlapped, lpCompletionRoutine);
1503 /* check that there is an overlapped struct */
1504 if (overlapped==NULL)
1506 SetLastError(ERROR_INVALID_PARAMETER);
1510 fd = FILE_GetUnixHandleType ( hFile, GENERIC_READ, &type, &flags);
1513 WARN ( "Couldn't get FD\n" );
1514 SetLastError ( ERROR_INVALID_PARAMETER );
1518 ovp = (async_fileio*) HeapAlloc(GetProcessHeap(), 0, sizeof (async_fileio));
1521 TRACE("HeapAlloc Failed\n");
1522 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1526 ovp->async.ops = ( lpCompletionRoutine ? &fileio_async_ops : &fileio_nocomp_async_ops );
1527 ovp->async.handle = hFile;
1529 ovp->async.type = ASYNC_TYPE_READ;
1530 ovp->async.func = FILE_AsyncReadService;
1531 ovp->async.event = hEvent;
1532 ovp->lpOverlapped = overlapped;
1533 ovp->count = bytesToRead;
1534 ovp->completion_func = lpCompletionRoutine;
1535 ovp->buffer = buffer;
1537 return !register_new_async (&ovp->async);
1545 /***********************************************************************
1546 * ReadFileEx (KERNEL32.@)
1548 BOOL WINAPI ReadFileEx(HANDLE hFile, LPVOID buffer, DWORD bytesToRead,
1549 LPOVERLAPPED overlapped,
1550 LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine)
1552 overlapped->InternalHigh = 0;
1553 return FILE_ReadFileEx(hFile,buffer,bytesToRead,overlapped,lpCompletionRoutine, INVALID_HANDLE_VALUE);
1556 static BOOL FILE_TimeoutRead(HANDLE hFile, LPVOID buffer, DWORD bytesToRead, LPDWORD bytesRead)
1561 TRACE("%d %p %ld %p\n", hFile, buffer, bytesToRead, bytesRead );
1563 ZeroMemory(&ov, sizeof (OVERLAPPED));
1564 if(STATUS_SUCCESS==NtCreateEvent(&ov.hEvent, SYNCHRONIZE, NULL, 0, 0))
1566 if(FILE_ReadFileEx(hFile, buffer, bytesToRead, &ov, NULL, ov.hEvent))
1568 r = GetOverlappedResult(hFile, &ov, bytesRead, TRUE);
1571 CloseHandle(ov.hEvent);
1575 /***********************************************************************
1576 * ReadFile (KERNEL32.@)
1578 BOOL WINAPI ReadFile( HANDLE hFile, LPVOID buffer, DWORD bytesToRead,
1579 LPDWORD bytesRead, LPOVERLAPPED overlapped )
1581 int unix_handle, result, flags;
1584 TRACE("%d %p %ld %p %p\n", hFile, buffer, bytesToRead,
1585 bytesRead, overlapped );
1587 if (bytesRead) *bytesRead = 0; /* Do this before anything else */
1588 if (!bytesToRead) return TRUE;
1590 unix_handle = FILE_GetUnixHandleType( hFile, GENERIC_READ, &type, &flags );
1592 if (flags & FD_FLAG_OVERLAPPED)
1594 if (unix_handle == -1) return FALSE;
1595 if ( (overlapped==NULL) || NtResetEvent( overlapped->hEvent, NULL ) )
1597 TRACE("Overlapped not specified or invalid event flag\n");
1599 SetLastError(ERROR_INVALID_PARAMETER);
1604 overlapped->InternalHigh = 0;
1606 if(!FILE_ReadFileEx(hFile, buffer, bytesToRead, overlapped, NULL, overlapped->hEvent))
1609 if ( !GetOverlappedResult (hFile, overlapped, bytesRead, FALSE) )
1611 if ( GetLastError() == ERROR_IO_INCOMPLETE )
1612 SetLastError ( ERROR_IO_PENDING );
1618 if (flags & FD_FLAG_TIMEOUT)
1621 return FILE_TimeoutRead(hFile, buffer, bytesToRead, bytesRead);
1626 return SMB_ReadFile(hFile, buffer, bytesToRead, bytesRead, NULL);
1627 case FD_TYPE_CONSOLE:
1628 return ReadConsoleA(hFile, buffer, bytesToRead, bytesRead, NULL);
1631 /* normal unix files */
1632 if (unix_handle == -1)
1637 SetLastError(ERROR_INVALID_PARAMETER);
1643 /* code for synchronous reads */
1644 while ((result = read( unix_handle, buffer, bytesToRead )) == -1)
1646 if ((errno == EAGAIN) || (errno == EINTR)) continue;
1647 if ((errno == EFAULT) && !IsBadWritePtr( buffer, bytesToRead )) continue;
1651 close( unix_handle );
1652 if (result == -1) return FALSE;
1653 if (bytesRead) *bytesRead = result;
1658 /***********************************************************************
1659 * FILE_AsyncWriteService (INTERNAL)
1661 * This function is called while the client is waiting on the
1662 * server, so we can't make any server calls here.
1664 static void FILE_AsyncWriteService(struct async_private *ovp)
1666 async_fileio *fileio = (async_fileio *) ovp;
1667 LPOVERLAPPED lpOverlapped = fileio->lpOverlapped;
1669 int already = lpOverlapped->InternalHigh;
1671 TRACE("(%p %p)\n",lpOverlapped,fileio->buffer);
1673 /* write some data (non-blocking) */
1675 result = pwrite(ovp->fd, &fileio->buffer[already], fileio->count - already,
1676 OVERLAPPED_OFFSET (lpOverlapped) + already);
1677 if ((result < 0) && (errno == ESPIPE))
1678 result = write(ovp->fd, &fileio->buffer[already], fileio->count - already);
1680 if ( (result<0) && ((errno == EAGAIN) || (errno == EINTR)))
1686 /* check to see if the transfer is complete */
1689 r = STATUS_UNSUCCESSFUL;
1693 lpOverlapped->InternalHigh += result;
1695 TRACE("wrote %d more bytes %ld/%d so far\n",result,lpOverlapped->InternalHigh,fileio->count);
1697 if(lpOverlapped->InternalHigh < fileio->count)
1703 lpOverlapped->Internal = r;
1706 /***********************************************************************
1709 static BOOL FILE_WriteFileEx(HANDLE hFile, LPCVOID buffer, DWORD bytesToWrite,
1710 LPOVERLAPPED overlapped,
1711 LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine,
1719 TRACE("file %d to buf %p num %ld %p func %p stub\n",
1720 hFile, buffer, bytesToWrite, overlapped, lpCompletionRoutine);
1722 if (overlapped == NULL)
1724 SetLastError(ERROR_INVALID_PARAMETER);
1728 fd = FILE_GetUnixHandleType ( hFile, GENERIC_WRITE, &type, &flags );
1731 TRACE( "Couldn't get FD\n" );
1735 ovp = (async_fileio*) HeapAlloc(GetProcessHeap(), 0, sizeof (async_fileio));
1738 TRACE("HeapAlloc Failed\n");
1739 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1743 ovp->async.ops = &fileio_async_ops;
1744 ovp->async.handle = hFile;
1745 ovp->async.fd = FILE_GetUnixHandle( hFile, GENERIC_WRITE );
1746 ovp->async.type = ASYNC_TYPE_WRITE;
1747 ovp->async.func = FILE_AsyncWriteService;
1748 ovp->lpOverlapped = overlapped;
1749 ovp->async.event = hEvent;
1750 ovp->buffer = (LPVOID) buffer;
1751 ovp->count = bytesToWrite;
1752 ovp->completion_func = lpCompletionRoutine;
1754 return !register_new_async (&ovp->async);
1761 /***********************************************************************
1762 * WriteFileEx (KERNEL32.@)
1764 BOOL WINAPI WriteFileEx(HANDLE hFile, LPCVOID buffer, DWORD bytesToWrite,
1765 LPOVERLAPPED overlapped,
1766 LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine)
1768 overlapped->InternalHigh = 0;
1770 return FILE_WriteFileEx(hFile, buffer, bytesToWrite, overlapped, lpCompletionRoutine, INVALID_HANDLE_VALUE);
1773 /***********************************************************************
1774 * WriteFile (KERNEL32.@)
1776 BOOL WINAPI WriteFile( HANDLE hFile, LPCVOID buffer, DWORD bytesToWrite,
1777 LPDWORD bytesWritten, LPOVERLAPPED overlapped )
1779 int unix_handle, result, flags;
1782 TRACE("%d %p %ld %p %p\n", hFile, buffer, bytesToWrite,
1783 bytesWritten, overlapped );
1785 if (bytesWritten) *bytesWritten = 0; /* Do this before anything else */
1786 if (!bytesToWrite) return TRUE;
1788 unix_handle = FILE_GetUnixHandleType( hFile, GENERIC_WRITE, &type, &flags );
1790 if (flags & FD_FLAG_OVERLAPPED)
1792 if (unix_handle == -1) return FALSE;
1793 if ( (overlapped==NULL) || NtResetEvent( overlapped->hEvent, NULL ) )
1795 TRACE("Overlapped not specified or invalid event flag\n");
1797 SetLastError(ERROR_INVALID_PARAMETER);
1802 overlapped->InternalHigh = 0;
1804 if(!FILE_WriteFileEx(hFile, buffer, bytesToWrite, overlapped, NULL, overlapped->hEvent))
1807 if ( !GetOverlappedResult (hFile, overlapped, bytesWritten, FALSE) )
1809 if ( GetLastError() == ERROR_IO_INCOMPLETE )
1810 SetLastError ( ERROR_IO_PENDING );
1819 case FD_TYPE_CONSOLE:
1820 TRACE("%d %s %ld %p %p\n", hFile, debugstr_an(buffer, bytesToWrite), bytesToWrite,
1821 bytesWritten, overlapped );
1822 return WriteConsoleA(hFile, buffer, bytesToWrite, bytesWritten, NULL);
1824 if (unix_handle == -1)
1828 /* synchronous file write */
1829 while ((result = write( unix_handle, buffer, bytesToWrite )) == -1)
1831 if ((errno == EAGAIN) || (errno == EINTR)) continue;
1832 if ((errno == EFAULT) && !IsBadReadPtr( buffer, bytesToWrite )) continue;
1833 if (errno == ENOSPC)
1834 SetLastError( ERROR_DISK_FULL );
1839 close( unix_handle );
1840 if (result == -1) return FALSE;
1841 if (bytesWritten) *bytesWritten = result;
1846 /***********************************************************************
1847 * _hread (KERNEL.349)
1849 LONG WINAPI WIN16_hread( HFILE16 hFile, SEGPTR buffer, LONG count )
1853 TRACE("%d %08lx %ld\n",
1854 hFile, (DWORD)buffer, count );
1856 /* Some programs pass a count larger than the allocated buffer */
1857 maxlen = GetSelectorLimit16( SELECTOROF(buffer) ) - OFFSETOF(buffer) + 1;
1858 if (count > maxlen) count = maxlen;
1859 return _lread(DosFileHandleToWin32Handle(hFile), MapSL(buffer), count );
1863 /***********************************************************************
1864 * _lread (KERNEL.82)
1866 UINT16 WINAPI WIN16_lread( HFILE16 hFile, SEGPTR buffer, UINT16 count )
1868 return (UINT16)WIN16_hread( hFile, buffer, (LONG)count );
1872 /***********************************************************************
1873 * _lread (KERNEL32.@)
1875 UINT WINAPI _lread( HFILE handle, LPVOID buffer, UINT count )
1878 if (!ReadFile( handle, buffer, count, &result, NULL )) return -1;
1883 /***********************************************************************
1884 * _lread16 (KERNEL.82)
1886 UINT16 WINAPI _lread16( HFILE16 hFile, LPVOID buffer, UINT16 count )
1888 return (UINT16)_lread(DosFileHandleToWin32Handle(hFile), buffer, (LONG)count );
1892 /***********************************************************************
1893 * _lcreat (KERNEL.83)
1895 HFILE16 WINAPI _lcreat16( LPCSTR path, INT16 attr )
1897 return Win32HandleToDosFileHandle( _lcreat( path, attr ) );
1901 /***********************************************************************
1902 * _lcreat (KERNEL32.@)
1904 HFILE WINAPI _lcreat( LPCSTR path, INT attr )
1906 /* Mask off all flags not explicitly allowed by the doc */
1907 attr &= FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM;
1908 TRACE("%s %02x\n", path, attr );
1909 return CreateFileA( path, GENERIC_READ | GENERIC_WRITE,
1910 FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
1911 CREATE_ALWAYS, attr, 0 );
1915 /***********************************************************************
1916 * SetFilePointer (KERNEL32.@)
1918 DWORD WINAPI SetFilePointer( HANDLE hFile, LONG distance, LONG *highword,
1921 DWORD ret = 0xffffffff;
1923 TRACE("handle %d offset %ld high %ld origin %ld\n",
1924 hFile, distance, highword?*highword:0, method );
1926 SERVER_START_REQ( set_file_pointer )
1928 req->handle = hFile;
1929 req->low = distance;
1930 req->high = highword ? *highword : (distance >= 0) ? 0 : -1;
1931 /* FIXME: assumes 1:1 mapping between Windows and Unix seek constants */
1932 req->whence = method;
1934 if (!wine_server_call_err( req ))
1936 ret = reply->new_low;
1937 if (highword) *highword = reply->new_high;
1945 /***********************************************************************
1946 * _llseek (KERNEL.84)
1949 * Seeking before the start of the file should be allowed for _llseek16,
1950 * but cause subsequent I/O operations to fail (cf. interrupt list)
1953 LONG WINAPI _llseek16( HFILE16 hFile, LONG lOffset, INT16 nOrigin )
1955 return SetFilePointer( DosFileHandleToWin32Handle(hFile), lOffset, NULL, nOrigin );
1959 /***********************************************************************
1960 * _llseek (KERNEL32.@)
1962 LONG WINAPI _llseek( HFILE hFile, LONG lOffset, INT nOrigin )
1964 return SetFilePointer( hFile, lOffset, NULL, nOrigin );
1968 /***********************************************************************
1969 * _lopen (KERNEL.85)
1971 HFILE16 WINAPI _lopen16( LPCSTR path, INT16 mode )
1973 return Win32HandleToDosFileHandle( _lopen( path, mode ) );
1977 /***********************************************************************
1978 * _lopen (KERNEL32.@)
1980 HFILE WINAPI _lopen( LPCSTR path, INT mode )
1982 DWORD access, sharing;
1984 TRACE("('%s',%04x)\n", path, mode );
1985 FILE_ConvertOFMode( mode, &access, &sharing );
1986 return CreateFileA( path, access, sharing, NULL, OPEN_EXISTING, 0, 0 );
1990 /***********************************************************************
1991 * _lwrite (KERNEL.86)
1993 UINT16 WINAPI _lwrite16( HFILE16 hFile, LPCSTR buffer, UINT16 count )
1995 return (UINT16)_hwrite( DosFileHandleToWin32Handle(hFile), buffer, (LONG)count );
1998 /***********************************************************************
1999 * _lwrite (KERNEL32.@)
2001 UINT WINAPI _lwrite( HFILE hFile, LPCSTR buffer, UINT count )
2003 return (UINT)_hwrite( hFile, buffer, (LONG)count );
2007 /***********************************************************************
2008 * _hread16 (KERNEL.349)
2010 LONG WINAPI _hread16( HFILE16 hFile, LPVOID buffer, LONG count)
2012 return _lread( DosFileHandleToWin32Handle(hFile), buffer, count );
2016 /***********************************************************************
2017 * _hread (KERNEL32.@)
2019 LONG WINAPI _hread( HFILE hFile, LPVOID buffer, LONG count)
2021 return _lread( hFile, buffer, count );
2025 /***********************************************************************
2026 * _hwrite (KERNEL.350)
2028 LONG WINAPI _hwrite16( HFILE16 hFile, LPCSTR buffer, LONG count )
2030 return _hwrite( DosFileHandleToWin32Handle(hFile), buffer, count );
2034 /***********************************************************************
2035 * _hwrite (KERNEL32.@)
2037 * experimentation yields that _lwrite:
2038 * o truncates the file at the current position with
2040 * o returns 0 on a 0 length write
2041 * o works with console handles
2044 LONG WINAPI _hwrite( HFILE handle, LPCSTR buffer, LONG count )
2048 TRACE("%d %p %ld\n", handle, buffer, count );
2052 /* Expand or truncate at current position */
2053 if (!SetEndOfFile( handle )) return HFILE_ERROR;
2056 if (!WriteFile( handle, buffer, count, &result, NULL ))
2062 /***********************************************************************
2063 * SetHandleCount (KERNEL.199)
2065 UINT16 WINAPI SetHandleCount16( UINT16 count )
2067 return SetHandleCount( count );
2071 /*************************************************************************
2072 * SetHandleCount (KERNEL32.@)
2074 UINT WINAPI SetHandleCount( UINT count )
2076 return min( 256, count );
2080 /***********************************************************************
2081 * FlushFileBuffers (KERNEL32.@)
2083 BOOL WINAPI FlushFileBuffers( HANDLE hFile )
2086 SERVER_START_REQ( flush_file )
2088 req->handle = hFile;
2089 ret = !wine_server_call_err( req );
2096 /**************************************************************************
2097 * SetEndOfFile (KERNEL32.@)
2099 BOOL WINAPI SetEndOfFile( HANDLE hFile )
2102 SERVER_START_REQ( truncate_file )
2104 req->handle = hFile;
2105 ret = !wine_server_call_err( req );
2112 /***********************************************************************
2113 * DeleteFile (KERNEL.146)
2115 BOOL16 WINAPI DeleteFile16( LPCSTR path )
2117 return DeleteFileA( path );
2121 /***********************************************************************
2122 * DeleteFileA (KERNEL32.@)
2124 BOOL WINAPI DeleteFileA( LPCSTR path )
2126 DOS_FULL_NAME full_name;
2130 SetLastError(ERROR_INVALID_PARAMETER);
2133 TRACE("'%s'\n", path );
2137 ERR("Empty path passed\n");
2140 if (DOSFS_GetDevice( path ))
2142 WARN("cannot remove DOS device '%s'!\n", path);
2143 SetLastError( ERROR_FILE_NOT_FOUND );
2147 if (!DOSFS_GetFullName( path, TRUE, &full_name )) return FALSE;
2148 if (unlink( full_name.long_name ) == -1)
2157 /***********************************************************************
2158 * DeleteFileW (KERNEL32.@)
2160 BOOL WINAPI DeleteFileW( LPCWSTR path )
2162 LPSTR xpath = HEAP_strdupWtoA( GetProcessHeap(), 0, path );
2163 BOOL ret = DeleteFileA( xpath );
2164 HeapFree( GetProcessHeap(), 0, xpath );
2169 /***********************************************************************
2170 * GetFileType (KERNEL32.@)
2172 DWORD WINAPI GetFileType( HANDLE hFile )
2174 DWORD ret = FILE_TYPE_UNKNOWN;
2175 SERVER_START_REQ( get_file_info )
2177 req->handle = hFile;
2178 if (!wine_server_call_err( req )) ret = reply->type;
2185 /* check if a file name is for an executable file (.exe or .com) */
2186 inline static BOOL is_executable( const char *name )
2188 int len = strlen(name);
2190 if (len < 4) return FALSE;
2191 return (!strcasecmp( name + len - 4, ".exe" ) ||
2192 !strcasecmp( name + len - 4, ".com" ));
2196 /***********************************************************************
2197 * FILE_AddBootRenameEntry
2199 * Adds an entry to the registry that is loaded when windows boots and
2200 * checks if there are some files to be removed or renamed/moved.
2201 * <fn1> has to be valid and <fn2> may be NULL. If both pointers are
2202 * non-NULL then the file is moved, otherwise it is deleted. The
2203 * entry of the registrykey is always appended with two zero
2204 * terminated strings. If <fn2> is NULL then the second entry is
2205 * simply a single 0-byte. Otherwise the second filename goes
2206 * there. The entries are prepended with \??\ before the path and the
2207 * second filename gets also a '!' as the first character if
2208 * MOVEFILE_REPLACE_EXISTING is set. After the final string another
2209 * 0-byte follows to indicate the end of the strings.
2211 * \??\D:\test\file1[0]
2212 * !\??\D:\test\file1_renamed[0]
2213 * \??\D:\Test|delete[0]
2214 * [0] <- file is to be deleted, second string empty
2215 * \??\D:\test\file2[0]
2216 * !\??\D:\test\file2_renamed[0]
2217 * [0] <- indicates end of strings
2220 * \??\D:\test\file1[0]
2221 * !\??\D:\test\file1_renamed[0]
2222 * \??\D:\Test|delete[0]
2223 * [0] <- file is to be deleted, second string empty
2224 * [0] <- indicates end of strings
2227 static BOOL FILE_AddBootRenameEntry( const char *fn1, const char *fn2, DWORD flags )
2229 static const char PreString[] = "\\??\\";
2230 static const char ValueName[] = "PendingFileRenameOperations";
2234 DWORD Type, len1, len2, l;
2236 BYTE *Buffer = NULL;
2238 if(RegCreateKeyA(HKEY_LOCAL_MACHINE, "SYSTEM\\CurrentControlSet\\Control\\Session Manager",
2239 &Reboot) != ERROR_SUCCESS)
2241 WARN("Error creating key for reboot managment [%s]\n",
2242 "SYSTEM\\CurrentControlSet\\Control\\Session Manager");
2246 l = strlen(PreString);
2247 len1 = strlen(fn1) + l + 1;
2250 len2 = strlen(fn2) + l + 1;
2251 if (flags & MOVEFILE_REPLACE_EXISTING) len2++; /* Plus 1 because of the leading '!' */
2253 else len2 = 1; /* minimum is the 0 byte for the empty second string */
2255 /* First we check if the key exists and if so how many bytes it already contains. */
2256 if (RegQueryValueExA(Reboot, ValueName, NULL, &Type, NULL, &DataSize) == ERROR_SUCCESS)
2258 if (Type != REG_MULTI_SZ) goto Quit;
2259 if (!(Buffer = HeapAlloc( GetProcessHeap(), 0, DataSize + len1 + len2 + 1 ))) goto Quit;
2260 if (RegQueryValueExA(Reboot, ValueName, NULL, &Type, Buffer, &DataSize) != ERROR_SUCCESS)
2262 if (DataSize) DataSize--; /* remove terminating null (will be added back later) */
2266 if (!(Buffer = HeapAlloc( GetProcessHeap(), 0, len1 + len2 + 1 ))) goto Quit;
2269 sprintf( Buffer + DataSize, "%s%s", PreString, fn1 );
2273 sprintf( Buffer + DataSize, "%s%s%s",
2274 (flags & MOVEFILE_REPLACE_EXISTING) ? "!" : "", PreString, fn2 );
2277 else Buffer[DataSize++] = 0;
2279 Buffer[DataSize++] = 0; /* add final null */
2280 rc = !RegSetValueExA( Reboot, ValueName, 0, REG_MULTI_SZ, Buffer, DataSize );
2283 if (Reboot) RegCloseKey(Reboot);
2284 if (Buffer) HeapFree( GetProcessHeap(), 0, Buffer );
2289 /**************************************************************************
2290 * MoveFileExA (KERNEL32.@)
2292 BOOL WINAPI MoveFileExA( LPCSTR fn1, LPCSTR fn2, DWORD flag )
2294 DOS_FULL_NAME full_name1, full_name2;
2296 TRACE("(%s,%s,%04lx)\n", fn1, fn2, flag);
2298 /* FIXME: <Gerhard W. Gruber>sparhawk@gmx.at
2299 In case of W9x and lesser this function should return 120 (ERROR_CALL_NOT_IMPLEMENTED)
2300 to be really compatible. Most programs wont have any problems though. In case
2301 you encounter one, this is what you should return here. I don't know what's up
2302 with NT 3.5. Is this function available there or not?
2303 Does anybody really care about 3.5? :)
2306 /* Filename1 has to be always set to a valid path. Filename2 may be NULL
2307 if the source file has to be deleted.
2310 SetLastError(ERROR_INVALID_PARAMETER);
2314 /* This function has to be run through in order to process the name properly.
2315 If the BOOTDELAY flag is set, the file doesn't need to exist though. At least
2316 that is the behaviour on NT 4.0. The operation accepts the filenames as
2317 they are given but it can't reply with a reasonable returncode. Success
2318 means in that case success for entering the values into the registry.
2320 if(!DOSFS_GetFullName( fn1, TRUE, &full_name1 ))
2322 if(!(flag & MOVEFILE_DELAY_UNTIL_REBOOT))
2326 if (fn2) /* !fn2 means delete fn1 */
2328 if (DOSFS_GetFullName( fn2, TRUE, &full_name2 ))
2330 if(!(flag & MOVEFILE_DELAY_UNTIL_REBOOT))
2332 /* target exists, check if we may overwrite */
2333 if (!(flag & MOVEFILE_REPLACE_EXISTING))
2335 /* FIXME: Use right error code */
2336 SetLastError( ERROR_ACCESS_DENIED );
2343 if (!DOSFS_GetFullName( fn2, FALSE, &full_name2 ))
2345 if(!(flag & MOVEFILE_DELAY_UNTIL_REBOOT))
2350 /* Source name and target path are valid */
2352 if (flag & MOVEFILE_DELAY_UNTIL_REBOOT)
2354 /* FIXME: (bon@elektron.ikp.physik.th-darmstadt.de 970706)
2355 Perhaps we should queue these command and execute it
2356 when exiting... What about using on_exit(2)
2358 FIXME("Please move existing file '%s' to file '%s' when Wine has finished\n",
2360 return FILE_AddBootRenameEntry( fn1, fn2, flag );
2363 if (full_name1.drive != full_name2.drive)
2365 /* use copy, if allowed */
2366 if (!(flag & MOVEFILE_COPY_ALLOWED))
2368 /* FIXME: Use right error code */
2369 SetLastError( ERROR_FILE_EXISTS );
2372 return CopyFileA( fn1, fn2, !(flag & MOVEFILE_REPLACE_EXISTING) );
2374 if (rename( full_name1.long_name, full_name2.long_name ) == -1)
2379 if (is_executable( full_name1.long_name ) != is_executable( full_name2.long_name ))
2382 if (stat( full_name2.long_name, &fstat ) != -1)
2384 if (is_executable( full_name2.long_name ))
2385 /* set executable bit where read bit is set */
2386 fstat.st_mode |= (fstat.st_mode & 0444) >> 2;
2388 fstat.st_mode &= ~0111;
2389 chmod( full_name2.long_name, fstat.st_mode );
2394 else /* fn2 == NULL means delete source */
2396 if (flag & MOVEFILE_DELAY_UNTIL_REBOOT)
2398 if (flag & MOVEFILE_COPY_ALLOWED) {
2399 WARN("Illegal flag\n");
2400 SetLastError( ERROR_GEN_FAILURE );
2403 /* FIXME: (bon@elektron.ikp.physik.th-darmstadt.de 970706)
2404 Perhaps we should queue these command and execute it
2405 when exiting... What about using on_exit(2)
2407 FIXME("Please delete file '%s' when Wine has finished\n", fn1);
2408 return FILE_AddBootRenameEntry( fn1, NULL, flag );
2411 if (unlink( full_name1.long_name ) == -1)
2416 return TRUE; /* successfully deleted */
2420 /**************************************************************************
2421 * MoveFileExW (KERNEL32.@)
2423 BOOL WINAPI MoveFileExW( LPCWSTR fn1, LPCWSTR fn2, DWORD flag )
2425 LPSTR afn1 = HEAP_strdupWtoA( GetProcessHeap(), 0, fn1 );
2426 LPSTR afn2 = HEAP_strdupWtoA( GetProcessHeap(), 0, fn2 );
2427 BOOL res = MoveFileExA( afn1, afn2, flag );
2428 HeapFree( GetProcessHeap(), 0, afn1 );
2429 HeapFree( GetProcessHeap(), 0, afn2 );
2434 /**************************************************************************
2435 * MoveFileA (KERNEL32.@)
2437 * Move file or directory
2439 BOOL WINAPI MoveFileA( LPCSTR fn1, LPCSTR fn2 )
2441 DOS_FULL_NAME full_name1, full_name2;
2444 TRACE("(%s,%s)\n", fn1, fn2 );
2446 if (!DOSFS_GetFullName( fn1, TRUE, &full_name1 )) return FALSE;
2447 if (DOSFS_GetFullName( fn2, TRUE, &full_name2 )) {
2448 /* The new name must not already exist */
2449 SetLastError(ERROR_ALREADY_EXISTS);
2452 if (!DOSFS_GetFullName( fn2, FALSE, &full_name2 )) return FALSE;
2454 if (full_name1.drive == full_name2.drive) /* move */
2455 return MoveFileExA( fn1, fn2, MOVEFILE_COPY_ALLOWED );
2458 if (stat( full_name1.long_name, &fstat ))
2460 WARN("Invalid source file %s\n",
2461 full_name1.long_name);
2465 if (S_ISDIR(fstat.st_mode)) {
2466 /* No Move for directories across file systems */
2467 /* FIXME: Use right error code */
2468 SetLastError( ERROR_GEN_FAILURE );
2471 return CopyFileA(fn1, fn2, TRUE); /*fail, if exist */
2475 /**************************************************************************
2476 * MoveFileW (KERNEL32.@)
2478 BOOL WINAPI MoveFileW( LPCWSTR fn1, LPCWSTR fn2 )
2480 LPSTR afn1 = HEAP_strdupWtoA( GetProcessHeap(), 0, fn1 );
2481 LPSTR afn2 = HEAP_strdupWtoA( GetProcessHeap(), 0, fn2 );
2482 BOOL res = MoveFileA( afn1, afn2 );
2483 HeapFree( GetProcessHeap(), 0, afn1 );
2484 HeapFree( GetProcessHeap(), 0, afn2 );
2489 /**************************************************************************
2490 * CopyFileA (KERNEL32.@)
2492 BOOL WINAPI CopyFileA( LPCSTR source, LPCSTR dest, BOOL fail_if_exists )
2495 BY_HANDLE_FILE_INFORMATION info;
2501 if ((h1 = _lopen( source, OF_READ )) == HFILE_ERROR) return FALSE;
2502 if (!GetFileInformationByHandle( h1, &info ))
2507 mode = (info.dwFileAttributes & FILE_ATTRIBUTE_READONLY) ? 0444 : 0666;
2508 if ((h2 = CreateFileA( dest, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
2509 fail_if_exists ? CREATE_NEW : CREATE_ALWAYS,
2510 info.dwFileAttributes, h1 )) == INVALID_HANDLE_VALUE)
2515 while ((count = _lread( h1, buffer, sizeof(buffer) )) > 0)
2520 INT res = _lwrite( h2, p, count );
2521 if (res <= 0) goto done;
2534 /**************************************************************************
2535 * CopyFileW (KERNEL32.@)
2537 BOOL WINAPI CopyFileW( LPCWSTR source, LPCWSTR dest, BOOL fail_if_exists)
2539 LPSTR sourceA = HEAP_strdupWtoA( GetProcessHeap(), 0, source );
2540 LPSTR destA = HEAP_strdupWtoA( GetProcessHeap(), 0, dest );
2541 BOOL ret = CopyFileA( sourceA, destA, fail_if_exists );
2542 HeapFree( GetProcessHeap(), 0, sourceA );
2543 HeapFree( GetProcessHeap(), 0, destA );
2548 /**************************************************************************
2549 * CopyFileExA (KERNEL32.@)
2551 * This implementation ignores most of the extra parameters passed-in into
2552 * the "ex" version of the method and calls the CopyFile method.
2553 * It will have to be fixed eventually.
2555 BOOL WINAPI CopyFileExA(LPCSTR sourceFilename,
2556 LPCSTR destFilename,
2557 LPPROGRESS_ROUTINE progressRoutine,
2559 LPBOOL cancelFlagPointer,
2562 BOOL failIfExists = FALSE;
2565 * Interpret the only flag that CopyFile can interpret.
2567 if ( (copyFlags & COPY_FILE_FAIL_IF_EXISTS) != 0)
2569 failIfExists = TRUE;
2572 return CopyFileA(sourceFilename, destFilename, failIfExists);
2575 /**************************************************************************
2576 * CopyFileExW (KERNEL32.@)
2578 BOOL WINAPI CopyFileExW(LPCWSTR sourceFilename,
2579 LPCWSTR destFilename,
2580 LPPROGRESS_ROUTINE progressRoutine,
2582 LPBOOL cancelFlagPointer,
2585 LPSTR sourceA = HEAP_strdupWtoA( GetProcessHeap(), 0, sourceFilename );
2586 LPSTR destA = HEAP_strdupWtoA( GetProcessHeap(), 0, destFilename );
2588 BOOL ret = CopyFileExA(sourceA,
2595 HeapFree( GetProcessHeap(), 0, sourceA );
2596 HeapFree( GetProcessHeap(), 0, destA );
2602 /***********************************************************************
2603 * SetFileTime (KERNEL32.@)
2605 BOOL WINAPI SetFileTime( HANDLE hFile,
2606 const FILETIME *lpCreationTime,
2607 const FILETIME *lpLastAccessTime,
2608 const FILETIME *lpLastWriteTime )
2611 SERVER_START_REQ( set_file_time )
2613 req->handle = hFile;
2614 if (lpLastAccessTime)
2615 RtlTimeToSecondsSince1970( lpLastAccessTime, (DWORD *)&req->access_time );
2617 req->access_time = 0; /* FIXME */
2618 if (lpLastWriteTime)
2619 RtlTimeToSecondsSince1970( lpLastWriteTime, (DWORD *)&req->write_time );
2621 req->write_time = 0; /* FIXME */
2622 ret = !wine_server_call_err( req );
2629 /**************************************************************************
2630 * LockFile (KERNEL32.@)
2632 BOOL WINAPI LockFile( HANDLE hFile, DWORD dwFileOffsetLow, DWORD dwFileOffsetHigh,
2633 DWORD nNumberOfBytesToLockLow, DWORD nNumberOfBytesToLockHigh )
2636 SERVER_START_REQ( lock_file )
2638 req->handle = hFile;
2639 req->offset_low = dwFileOffsetLow;
2640 req->offset_high = dwFileOffsetHigh;
2641 req->count_low = nNumberOfBytesToLockLow;
2642 req->count_high = nNumberOfBytesToLockHigh;
2643 ret = !wine_server_call_err( req );
2649 /**************************************************************************
2650 * LockFileEx [KERNEL32.@]
2652 * Locks a byte range within an open file for shared or exclusive access.
2659 * Per Microsoft docs, the third parameter (reserved) must be set to 0.
2661 BOOL WINAPI LockFileEx( HANDLE hFile, DWORD flags, DWORD reserved,
2662 DWORD nNumberOfBytesToLockLow, DWORD nNumberOfBytesToLockHigh,
2663 LPOVERLAPPED pOverlapped )
2665 FIXME("hFile=%d,flags=%ld,reserved=%ld,lowbytes=%ld,highbytes=%ld,overlapped=%p: stub.\n",
2666 hFile, flags, reserved, nNumberOfBytesToLockLow, nNumberOfBytesToLockHigh,
2669 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
2672 ERR("reserved == %ld: Supposed to be 0??\n", reserved);
2673 SetLastError(ERROR_INVALID_PARAMETER);
2680 /**************************************************************************
2681 * UnlockFile (KERNEL32.@)
2683 BOOL WINAPI UnlockFile( HANDLE hFile, DWORD dwFileOffsetLow, DWORD dwFileOffsetHigh,
2684 DWORD nNumberOfBytesToUnlockLow, DWORD nNumberOfBytesToUnlockHigh )
2687 SERVER_START_REQ( unlock_file )
2689 req->handle = hFile;
2690 req->offset_low = dwFileOffsetLow;
2691 req->offset_high = dwFileOffsetHigh;
2692 req->count_low = nNumberOfBytesToUnlockLow;
2693 req->count_high = nNumberOfBytesToUnlockHigh;
2694 ret = !wine_server_call_err( req );
2701 /**************************************************************************
2702 * UnlockFileEx (KERNEL32.@)
2704 BOOL WINAPI UnlockFileEx(
2707 DWORD nNumberOfBytesToUnlockLow,
2708 DWORD nNumberOfBytesToUnlockHigh,
2709 LPOVERLAPPED lpOverlapped
2712 FIXME("hFile=%d,reserved=%ld,lowbytes=%ld,highbytes=%ld,overlapped=%p: stub.\n",
2713 hFile, dwReserved, nNumberOfBytesToUnlockLow, nNumberOfBytesToUnlockHigh,
2715 if (dwReserved == 0)
2716 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
2719 ERR("reserved == %ld: Supposed to be 0??\n", dwReserved);
2720 SetLastError(ERROR_INVALID_PARAMETER);
2729 struct DOS_FILE_LOCK {
2730 struct DOS_FILE_LOCK * next;
2734 FILE_OBJECT * dos_file;
2735 /* char * unix_name;*/
2738 typedef struct DOS_FILE_LOCK DOS_FILE_LOCK;
2740 static DOS_FILE_LOCK *locks = NULL;
2741 static void DOS_RemoveFileLocks(FILE_OBJECT *file);
2744 /* Locks need to be mirrored because unix file locking is based
2745 * on the pid. Inside of wine there can be multiple WINE processes
2746 * that share the same unix pid.
2747 * Read's and writes should check these locks also - not sure
2748 * how critical that is at this point (FIXME).
2751 static BOOL DOS_AddLock(FILE_OBJECT *file, struct flock *f)
2753 DOS_FILE_LOCK *curr;
2756 processId = GetCurrentProcessId();
2758 /* check if lock overlaps a current lock for the same file */
2760 for (curr = locks; curr; curr = curr->next) {
2761 if (strcmp(curr->unix_name, file->unix_name) == 0) {
2762 if ((f->l_start == curr->base) && (f->l_len == curr->len))
2763 return TRUE;/* region is identic */
2764 if ((f->l_start < (curr->base + curr->len)) &&
2765 ((f->l_start + f->l_len) > curr->base)) {
2766 /* region overlaps */
2773 curr = HeapAlloc( GetProcessHeap(), 0, sizeof(DOS_FILE_LOCK) );
2774 curr->processId = GetCurrentProcessId();
2775 curr->base = f->l_start;
2776 curr->len = f->l_len;
2777 /* curr->unix_name = HEAP_strdupA( GetProcessHeap(), 0, file->unix_name);*/
2779 curr->dos_file = file;
2784 static void DOS_RemoveFileLocks(FILE_OBJECT *file)
2787 DOS_FILE_LOCK **curr;
2790 processId = GetCurrentProcessId();
2793 if ((*curr)->dos_file == file) {
2795 *curr = (*curr)->next;
2796 /* HeapFree( GetProcessHeap(), 0, rem->unix_name );*/
2797 HeapFree( GetProcessHeap(), 0, rem );
2800 curr = &(*curr)->next;
2804 static BOOL DOS_RemoveLock(FILE_OBJECT *file, struct flock *f)
2807 DOS_FILE_LOCK **curr;
2810 processId = GetCurrentProcessId();
2811 for (curr = &locks; *curr; curr = &(*curr)->next) {
2812 if ((*curr)->processId == processId &&
2813 (*curr)->dos_file == file &&
2814 (*curr)->base == f->l_start &&
2815 (*curr)->len == f->l_len) {
2816 /* this is the same lock */
2818 *curr = (*curr)->next;
2819 /* HeapFree( GetProcessHeap(), 0, rem->unix_name );*/
2820 HeapFree( GetProcessHeap(), 0, rem );
2824 /* no matching lock found */
2829 /**************************************************************************
2830 * LockFile (KERNEL32.@)
2832 BOOL WINAPI LockFile(
2833 HFILE hFile,DWORD dwFileOffsetLow,DWORD dwFileOffsetHigh,
2834 DWORD nNumberOfBytesToLockLow,DWORD nNumberOfBytesToLockHigh )
2839 TRACE("handle %d offsetlow=%ld offsethigh=%ld nbyteslow=%ld nbyteshigh=%ld\n",
2840 hFile, dwFileOffsetLow, dwFileOffsetHigh,
2841 nNumberOfBytesToLockLow, nNumberOfBytesToLockHigh);
2843 if (dwFileOffsetHigh || nNumberOfBytesToLockHigh) {
2844 FIXME("Unimplemented bytes > 32bits\n");
2848 f.l_start = dwFileOffsetLow;
2849 f.l_len = nNumberOfBytesToLockLow;
2850 f.l_whence = SEEK_SET;
2854 if (!(file = FILE_GetFile(hFile,0,NULL))) return FALSE;
2856 /* shadow locks internally */
2857 if (!DOS_AddLock(file, &f)) {
2858 SetLastError( ERROR_LOCK_VIOLATION );
2862 /* FIXME: Unix locking commented out for now, doesn't work with Excel */
2863 #ifdef USE_UNIX_LOCKS
2864 if (fcntl(file->unix_handle, F_SETLK, &f) == -1) {
2865 if (errno == EACCES || errno == EAGAIN) {
2866 SetLastError( ERROR_LOCK_VIOLATION );
2871 /* remove our internal copy of the lock */
2872 DOS_RemoveLock(file, &f);
2880 /**************************************************************************
2881 * UnlockFile (KERNEL32.@)
2883 BOOL WINAPI UnlockFile(
2884 HFILE hFile,DWORD dwFileOffsetLow,DWORD dwFileOffsetHigh,
2885 DWORD nNumberOfBytesToUnlockLow,DWORD nNumberOfBytesToUnlockHigh )
2890 TRACE("handle %d offsetlow=%ld offsethigh=%ld nbyteslow=%ld nbyteshigh=%ld\n",
2891 hFile, dwFileOffsetLow, dwFileOffsetHigh,
2892 nNumberOfBytesToUnlockLow, nNumberOfBytesToUnlockHigh);
2894 if (dwFileOffsetHigh || nNumberOfBytesToUnlockHigh) {
2895 WARN("Unimplemented bytes > 32bits\n");
2899 f.l_start = dwFileOffsetLow;
2900 f.l_len = nNumberOfBytesToUnlockLow;
2901 f.l_whence = SEEK_SET;
2905 if (!(file = FILE_GetFile(hFile,0,NULL))) return FALSE;
2907 DOS_RemoveLock(file, &f); /* ok if fails - may be another wine */
2909 /* FIXME: Unix locking commented out for now, doesn't work with Excel */
2910 #ifdef USE_UNIX_LOCKS
2911 if (fcntl(file->unix_handle, F_SETLK, &f) == -1) {
2920 /**************************************************************************
2921 * GetFileAttributesExA [KERNEL32.@]
2923 BOOL WINAPI GetFileAttributesExA(
2924 LPCSTR lpFileName, GET_FILEEX_INFO_LEVELS fInfoLevelId,
2925 LPVOID lpFileInformation)
2927 DOS_FULL_NAME full_name;
2928 BY_HANDLE_FILE_INFORMATION info;
2930 if (lpFileName == NULL) return FALSE;
2931 if (lpFileInformation == NULL) return FALSE;
2933 if (fInfoLevelId == GetFileExInfoStandard) {
2934 LPWIN32_FILE_ATTRIBUTE_DATA lpFad =
2935 (LPWIN32_FILE_ATTRIBUTE_DATA) lpFileInformation;
2936 if (!DOSFS_GetFullName( lpFileName, TRUE, &full_name )) return FALSE;
2937 if (!FILE_Stat( full_name.long_name, &info )) return FALSE;
2939 lpFad->dwFileAttributes = info.dwFileAttributes;
2940 lpFad->ftCreationTime = info.ftCreationTime;
2941 lpFad->ftLastAccessTime = info.ftLastAccessTime;
2942 lpFad->ftLastWriteTime = info.ftLastWriteTime;
2943 lpFad->nFileSizeHigh = info.nFileSizeHigh;
2944 lpFad->nFileSizeLow = info.nFileSizeLow;
2947 FIXME("invalid info level %d!\n", fInfoLevelId);
2955 /**************************************************************************
2956 * GetFileAttributesExW [KERNEL32.@]
2958 BOOL WINAPI GetFileAttributesExW(
2959 LPCWSTR lpFileName, GET_FILEEX_INFO_LEVELS fInfoLevelId,
2960 LPVOID lpFileInformation)
2962 LPSTR nameA = HEAP_strdupWtoA( GetProcessHeap(), 0, lpFileName );
2964 GetFileAttributesExA( nameA, fInfoLevelId, lpFileInformation);
2965 HeapFree( GetProcessHeap(), 0, nameA );