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;
118 enum fd_type fd_type;
121 static DWORD fileio_get_async_status (const struct async_private *ovp)
123 return ((async_fileio*) ovp)->lpOverlapped->Internal;
126 static void fileio_set_async_status (async_private *ovp, const DWORD status)
128 ((async_fileio*) ovp)->lpOverlapped->Internal = status;
131 static DWORD fileio_get_async_count (const struct async_private *ovp)
133 async_fileio *fileio = (async_fileio*) ovp;
134 DWORD ret = fileio->count - fileio->lpOverlapped->InternalHigh;
135 return (ret < 0 ? 0 : ret);
138 static void CALLBACK fileio_call_completion_func (ULONG_PTR data)
140 async_fileio *ovp = (async_fileio*) data;
141 TRACE ("data: %p\n", ovp);
143 ovp->completion_func( ovp->lpOverlapped->Internal,
144 ovp->lpOverlapped->InternalHigh,
147 fileio_async_cleanup ( &ovp->async );
150 static void fileio_async_cleanup ( struct async_private *ovp )
152 HeapFree ( GetProcessHeap(), 0, ovp );
155 /***********************************************************************
158 * Convert OF_* mode into flags for CreateFile.
160 static void FILE_ConvertOFMode( INT mode, DWORD *access, DWORD *sharing )
164 case OF_READ: *access = GENERIC_READ; break;
165 case OF_WRITE: *access = GENERIC_WRITE; break;
166 case OF_READWRITE: *access = GENERIC_READ | GENERIC_WRITE; break;
167 default: *access = 0; break;
171 case OF_SHARE_EXCLUSIVE: *sharing = 0; break;
172 case OF_SHARE_DENY_WRITE: *sharing = FILE_SHARE_READ; break;
173 case OF_SHARE_DENY_READ: *sharing = FILE_SHARE_WRITE; break;
174 case OF_SHARE_DENY_NONE:
175 case OF_SHARE_COMPAT:
176 default: *sharing = FILE_SHARE_READ | FILE_SHARE_WRITE; break;
181 /***********************************************************************
184 * locale-independent case conversion for file I/O
186 int FILE_strcasecmp( const char *str1, const char *str2 )
190 int ret = FILE_toupper(*str1) - FILE_toupper(*str2);
191 if (ret || !*str1) return ret;
198 /***********************************************************************
201 * locale-independent case conversion for file I/O
203 int FILE_strncasecmp( const char *str1, const char *str2, int len )
206 for ( ; len > 0; len--, str1++, str2++)
207 if ((ret = FILE_toupper(*str1) - FILE_toupper(*str2)) || !*str1) break;
212 /***********************************************************************
213 * FILE_GetNtStatus(void)
215 * Retrieve the Nt Status code from errno.
216 * Try to be consistent with FILE_SetDosError().
218 DWORD FILE_GetNtStatus(void)
222 TRACE ( "errno = %d\n", errno );
225 case EAGAIN: nt = STATUS_SHARING_VIOLATION; break;
226 case EBADF: nt = STATUS_INVALID_HANDLE; break;
227 case ENOSPC: nt = STATUS_DISK_FULL; break;
230 case EACCES: nt = STATUS_ACCESS_DENIED; break;
231 case ENOENT: nt = STATUS_SHARING_VIOLATION; break;
232 case EISDIR: nt = STATUS_FILE_IS_A_DIRECTORY; break;
234 case ENFILE: nt = STATUS_NO_MORE_FILES; break;
236 case ENOTEMPTY: nt = STATUS_DIRECTORY_NOT_EMPTY; break;
237 case EPIPE: nt = STATUS_PIPE_BROKEN; break;
238 case ENOEXEC: /* ?? */
239 case ESPIPE: /* ?? */
240 case EEXIST: /* ?? */
242 FIXME ( "Converting errno %d to STATUS_UNSUCCESSFUL\n", err );
243 nt = STATUS_UNSUCCESSFUL;
248 /***********************************************************************
251 * Set the DOS error code from errno.
253 void FILE_SetDosError(void)
255 int save_errno = errno; /* errno gets overwritten by printf */
257 TRACE("errno = %d %s\n", errno, strerror(errno));
261 SetLastError( ERROR_SHARING_VIOLATION );
264 SetLastError( ERROR_INVALID_HANDLE );
267 SetLastError( ERROR_HANDLE_DISK_FULL );
272 SetLastError( ERROR_ACCESS_DENIED );
275 SetLastError( ERROR_LOCK_VIOLATION );
278 SetLastError( ERROR_FILE_NOT_FOUND );
281 SetLastError( ERROR_CANNOT_MAKE );
285 SetLastError( ERROR_NO_MORE_FILES );
288 SetLastError( ERROR_FILE_EXISTS );
292 SetLastError( ERROR_SEEK );
295 SetLastError( ERROR_DIR_NOT_EMPTY );
298 SetLastError( ERROR_BAD_FORMAT );
301 WARN("unknown file error: %s\n", strerror(save_errno) );
302 SetLastError( ERROR_GEN_FAILURE );
309 /***********************************************************************
312 * Duplicate a Unix handle into a task handle.
313 * Returns 0 on failure.
315 HANDLE FILE_DupUnixHandle( int fd, DWORD access, BOOL inherit )
319 wine_server_send_fd( fd );
321 SERVER_START_REQ( alloc_file_handle )
323 req->access = access;
324 req->inherit = inherit;
326 wine_server_call( req );
334 /***********************************************************************
335 * FILE_GetUnixHandleType
337 * Retrieve the Unix handle corresponding to a file handle.
338 * Returns -1 on failure.
340 static int FILE_GetUnixHandleType( HANDLE handle, DWORD access, enum fd_type *type, int *flags_ptr )
342 int ret, flags, fd = -1;
344 ret = wine_server_handle_to_fd( handle, access, &fd, type, &flags );
345 if (flags_ptr) *flags_ptr = flags;
346 if (ret) SetLastError( RtlNtStatusToDosError(ret) );
347 else if (((access & GENERIC_READ) && (flags & FD_FLAG_RECV_SHUTDOWN)) ||
348 ((access & GENERIC_WRITE) && (flags & FD_FLAG_SEND_SHUTDOWN)))
351 SetLastError ( ERROR_PIPE_NOT_CONNECTED );
357 /***********************************************************************
360 * Retrieve the Unix handle corresponding to a file handle.
361 * Returns -1 on failure.
363 int FILE_GetUnixHandle( HANDLE handle, DWORD access )
365 return FILE_GetUnixHandleType( handle, access, NULL, NULL );
368 /*************************************************************************
371 * Open a handle to the current process console.
372 * Returns 0 on failure.
374 static HANDLE FILE_OpenConsole( BOOL output, DWORD access, DWORD sharing, LPSECURITY_ATTRIBUTES sa )
378 SERVER_START_REQ( open_console )
381 req->access = access;
382 req->share = sharing;
383 req->inherit = (sa && (sa->nLength>=sizeof(*sa)) && sa->bInheritHandle);
385 wine_server_call_err( req );
393 /***********************************************************************
396 * Implementation of CreateFile. Takes a Unix path name.
397 * Returns 0 on failure.
399 HANDLE FILE_CreateFile( LPCSTR filename, DWORD access, DWORD sharing,
400 LPSECURITY_ATTRIBUTES sa, DWORD creation,
401 DWORD attributes, HANDLE template, BOOL fail_read_only,
409 SERVER_START_REQ( create_file )
411 req->access = access;
412 req->inherit = (sa && (sa->nLength>=sizeof(*sa)) && sa->bInheritHandle);
413 req->sharing = sharing;
414 req->create = creation;
415 req->attrs = attributes;
416 req->drive_type = drive_type;
417 wine_server_add_data( req, filename, strlen(filename) );
419 err = wine_server_call( req );
424 /* If write access failed, retry without GENERIC_WRITE */
426 if (!ret && !fail_read_only && (access & GENERIC_WRITE))
428 if ((err == STATUS_MEDIA_WRITE_PROTECTED) || (err == STATUS_ACCESS_DENIED))
430 TRACE("Write access failed for file '%s', trying without "
431 "write access\n", filename);
432 access &= ~GENERIC_WRITE;
437 if (err) SetLastError( RtlNtStatusToDosError(err) );
439 if (!ret) WARN("Unable to create file '%s' (GLE %ld)\n", filename, GetLastError());
445 /***********************************************************************
448 * Same as FILE_CreateFile but for a device
449 * Returns 0 on failure.
451 HANDLE FILE_CreateDevice( int client_id, DWORD access, LPSECURITY_ATTRIBUTES sa )
454 SERVER_START_REQ( create_device )
456 req->access = access;
457 req->inherit = (sa && (sa->nLength>=sizeof(*sa)) && sa->bInheritHandle);
460 wine_server_call_err( req );
467 static HANDLE FILE_OpenPipe(LPCSTR name, DWORD access)
469 WCHAR buffer[MAX_PATH];
473 if (name && !(len = MultiByteToWideChar( CP_ACP, 0, name, strlen(name), buffer, MAX_PATH )))
475 SetLastError( ERROR_FILENAME_EXCED_RANGE );
478 SERVER_START_REQ( open_named_pipe )
480 req->access = access;
482 wine_server_add_data( req, buffer, len * sizeof(WCHAR) );
483 wine_server_call_err( req );
487 TRACE("Returned %d\n",ret);
491 /*************************************************************************
492 * CreateFileA [KERNEL32.@] Creates or opens a file or other object
494 * Creates or opens an object, and returns a handle that can be used to
495 * access that object.
499 * filename [in] pointer to filename to be accessed
500 * access [in] access mode requested
501 * sharing [in] share mode
502 * sa [in] pointer to security attributes
503 * creation [in] how to create the file
504 * attributes [in] attributes for newly created file
505 * template [in] handle to file with extended attributes to copy
508 * Success: Open handle to specified file
509 * Failure: INVALID_HANDLE_VALUE
512 * Should call SetLastError() on failure.
516 * Doesn't support character devices, template files, or a
517 * lot of the 'attributes' flags yet.
519 HANDLE WINAPI CreateFileA( LPCSTR filename, DWORD access, DWORD sharing,
520 LPSECURITY_ATTRIBUTES sa, DWORD creation,
521 DWORD attributes, HANDLE template )
523 DOS_FULL_NAME full_name;
528 SetLastError( ERROR_INVALID_PARAMETER );
529 return INVALID_HANDLE_VALUE;
531 TRACE("%s %s%s%s%s%s%s%s\n",filename,
532 ((access & GENERIC_READ)==GENERIC_READ)?"GENERIC_READ ":"",
533 ((access & GENERIC_WRITE)==GENERIC_WRITE)?"GENERIC_WRITE ":"",
534 (!access)?"QUERY_ACCESS ":"",
535 ((sharing & FILE_SHARE_READ)==FILE_SHARE_READ)?"FILE_SHARE_READ ":"",
536 ((sharing & FILE_SHARE_WRITE)==FILE_SHARE_WRITE)?"FILE_SHARE_WRITE ":"",
537 ((sharing & FILE_SHARE_DELETE)==FILE_SHARE_DELETE)?"FILE_SHARE_DELETE ":"",
538 (creation ==CREATE_NEW)?"CREATE_NEW":
539 (creation ==CREATE_ALWAYS)?"CREATE_ALWAYS ":
540 (creation ==OPEN_EXISTING)?"OPEN_EXISTING ":
541 (creation ==OPEN_ALWAYS)?"OPEN_ALWAYS ":
542 (creation ==TRUNCATE_EXISTING)?"TRUNCATE_EXISTING ":"");
544 /* If the name starts with '\\?\', ignore the first 4 chars. */
545 if (!strncmp(filename, "\\\\?\\", 4))
548 if (!strncmp(filename, "UNC\\", 4))
550 FIXME("UNC name (%s) not supported.\n", filename );
551 SetLastError( ERROR_PATH_NOT_FOUND );
552 return INVALID_HANDLE_VALUE;
556 if (!strncmp(filename, "\\\\.\\", 4)) {
557 if(!strncasecmp(&filename[4],"pipe\\",5))
559 TRACE("Opening a pipe: %s\n",filename);
560 ret = FILE_OpenPipe(filename,access);
563 else if (isalpha(filename[4]) && filename[5] == ':' && filename[6] == '\0')
565 ret = FILE_CreateDevice( (toupper(filename[4]) - 'A') | 0x20000, access, sa );
568 else if (!DOSFS_GetDevice( filename ))
570 ret = DEVICE_Open( filename+4, access, sa );
574 filename+=4; /* fall into DOSFS_Device case below */
577 /* If the name still starts with '\\', it's a UNC name. */
578 if (!strncmp(filename, "\\\\", 2))
580 ret = SMB_CreateFileA(filename, access, sharing, sa, creation, attributes, template );
584 /* If the name contains a DOS wild card (* or ?), do no create a file */
585 if(strchr(filename,'*') || strchr(filename,'?'))
586 return INVALID_HANDLE_VALUE;
588 /* Open a console for CONIN$ or CONOUT$ */
589 if (!strcasecmp(filename, "CONIN$"))
591 ret = FILE_OpenConsole( FALSE, access, sharing, sa );
594 if (!strcasecmp(filename, "CONOUT$"))
596 ret = FILE_OpenConsole( TRUE, access, sharing, sa );
600 if (DOSFS_GetDevice( filename ))
602 TRACE("opening device '%s'\n", filename );
604 if (!(ret = DOSFS_OpenDevice( filename, access, attributes, sa )))
606 /* Do not silence this please. It is a critical error. -MM */
607 ERR("Couldn't open device '%s'!\n",filename);
608 SetLastError( ERROR_FILE_NOT_FOUND );
613 /* check for filename, don't check for last entry if creating */
614 if (!DOSFS_GetFullName( filename,
615 (creation == OPEN_EXISTING) ||
616 (creation == TRUNCATE_EXISTING),
618 WARN("Unable to get full filename from '%s' (GLE %ld)\n",
619 filename, GetLastError());
620 return INVALID_HANDLE_VALUE;
623 ret = FILE_CreateFile( full_name.long_name, access, sharing,
624 sa, creation, attributes, template,
625 DRIVE_GetFlags(full_name.drive) & DRIVE_FAIL_READ_ONLY,
626 GetDriveTypeA( full_name.short_name ) );
628 if (!ret) ret = INVALID_HANDLE_VALUE;
634 /*************************************************************************
635 * CreateFileW (KERNEL32.@)
637 HANDLE WINAPI CreateFileW( LPCWSTR filename, DWORD access, DWORD sharing,
638 LPSECURITY_ATTRIBUTES sa, DWORD creation,
639 DWORD attributes, HANDLE template)
641 LPSTR afn = HEAP_strdupWtoA( GetProcessHeap(), 0, filename );
642 HANDLE res = CreateFileA( afn, access, sharing, sa, creation, attributes, template );
643 HeapFree( GetProcessHeap(), 0, afn );
648 /***********************************************************************
651 * Fill a file information from a struct stat.
653 static void FILE_FillInfo( struct stat *st, BY_HANDLE_FILE_INFORMATION *info )
655 if (S_ISDIR(st->st_mode))
656 info->dwFileAttributes = FILE_ATTRIBUTE_DIRECTORY;
658 info->dwFileAttributes = FILE_ATTRIBUTE_ARCHIVE;
659 if (!(st->st_mode & S_IWUSR))
660 info->dwFileAttributes |= FILE_ATTRIBUTE_READONLY;
662 RtlSecondsSince1970ToTime( st->st_mtime, &info->ftCreationTime );
663 RtlSecondsSince1970ToTime( st->st_mtime, &info->ftLastWriteTime );
664 RtlSecondsSince1970ToTime( st->st_atime, &info->ftLastAccessTime );
666 info->dwVolumeSerialNumber = 0; /* FIXME */
667 info->nFileSizeHigh = 0;
668 info->nFileSizeLow = 0;
669 if (!S_ISDIR(st->st_mode)) {
670 info->nFileSizeHigh = st->st_size >> 32;
671 info->nFileSizeLow = st->st_size & 0xffffffff;
673 info->nNumberOfLinks = st->st_nlink;
674 info->nFileIndexHigh = 0;
675 info->nFileIndexLow = st->st_ino;
679 /***********************************************************************
682 * Stat a Unix path name. Return TRUE if OK.
684 BOOL FILE_Stat( LPCSTR unixName, BY_HANDLE_FILE_INFORMATION *info )
688 if (lstat( unixName, &st ) == -1)
693 if (!S_ISLNK(st.st_mode)) FILE_FillInfo( &st, info );
696 /* do a "real" stat to find out
697 about the type of the symlink destination */
698 if (stat( unixName, &st ) == -1)
703 FILE_FillInfo( &st, info );
704 info->dwFileAttributes |= FILE_ATTRIBUTE_SYMLINK;
710 /***********************************************************************
711 * GetFileInformationByHandle (KERNEL32.@)
713 DWORD WINAPI GetFileInformationByHandle( HANDLE hFile,
714 BY_HANDLE_FILE_INFORMATION *info )
719 SERVER_START_REQ( get_file_info )
722 if ((ret = !wine_server_call_err( req )))
724 /* FIXME: which file types are supported ?
725 * Serial ports (FILE_TYPE_CHAR) are not,
726 * and MSDN also says that pipes are not supported.
727 * FILE_TYPE_REMOTE seems to be supported according to
728 * MSDN q234741.txt */
729 if ((reply->type == FILE_TYPE_DISK) || (reply->type == FILE_TYPE_REMOTE))
731 RtlSecondsSince1970ToTime( reply->write_time, &info->ftCreationTime );
732 RtlSecondsSince1970ToTime( reply->write_time, &info->ftLastWriteTime );
733 RtlSecondsSince1970ToTime( reply->access_time, &info->ftLastAccessTime );
734 info->dwFileAttributes = reply->attr;
735 info->dwVolumeSerialNumber = reply->serial;
736 info->nFileSizeHigh = reply->size_high;
737 info->nFileSizeLow = reply->size_low;
738 info->nNumberOfLinks = reply->links;
739 info->nFileIndexHigh = reply->index_high;
740 info->nFileIndexLow = reply->index_low;
744 SetLastError(ERROR_NOT_SUPPORTED);
754 /**************************************************************************
755 * GetFileAttributes (KERNEL.420)
757 DWORD WINAPI GetFileAttributes16( LPCSTR name )
759 return GetFileAttributesA( name );
763 /**************************************************************************
764 * GetFileAttributesA (KERNEL32.@)
766 DWORD WINAPI GetFileAttributesA( LPCSTR name )
768 DOS_FULL_NAME full_name;
769 BY_HANDLE_FILE_INFORMATION info;
773 SetLastError( ERROR_INVALID_PARAMETER );
776 if (!DOSFS_GetFullName( name, TRUE, &full_name) )
778 if (!FILE_Stat( full_name.long_name, &info )) return -1;
779 return info.dwFileAttributes;
783 /**************************************************************************
784 * GetFileAttributesW (KERNEL32.@)
786 DWORD WINAPI GetFileAttributesW( LPCWSTR name )
788 LPSTR nameA = HEAP_strdupWtoA( GetProcessHeap(), 0, name );
789 DWORD res = GetFileAttributesA( nameA );
790 HeapFree( GetProcessHeap(), 0, nameA );
795 /**************************************************************************
796 * SetFileAttributes (KERNEL.421)
798 BOOL16 WINAPI SetFileAttributes16( LPCSTR lpFileName, DWORD attributes )
800 return SetFileAttributesA( lpFileName, attributes );
804 /**************************************************************************
805 * SetFileAttributesA (KERNEL32.@)
807 BOOL WINAPI SetFileAttributesA(LPCSTR lpFileName, DWORD attributes)
810 DOS_FULL_NAME full_name;
812 if (!DOSFS_GetFullName( lpFileName, TRUE, &full_name ))
815 TRACE("(%s,%lx)\n",lpFileName,attributes);
816 if (attributes & FILE_ATTRIBUTE_NORMAL) {
817 attributes &= ~FILE_ATTRIBUTE_NORMAL;
819 FIXME("(%s):%lx illegal combination with FILE_ATTRIBUTE_NORMAL.\n", lpFileName,attributes);
821 if(stat(full_name.long_name,&buf)==-1)
826 if (attributes & FILE_ATTRIBUTE_READONLY)
828 if(S_ISDIR(buf.st_mode))
830 WARN("FILE_ATTRIBUTE_READONLY ignored for directory.\n");
832 buf.st_mode &= ~0222; /* octal!, clear write permission bits */
833 attributes &= ~FILE_ATTRIBUTE_READONLY;
837 /* add write permission */
838 buf.st_mode |= (0600 | ((buf.st_mode & 044) >> 1)) & (~FILE_umask);
840 if (attributes & FILE_ATTRIBUTE_DIRECTORY)
842 if (!S_ISDIR(buf.st_mode))
843 FIXME("SetFileAttributes expected the file '%s' to be a directory",
845 attributes &= ~FILE_ATTRIBUTE_DIRECTORY;
847 attributes &= ~(FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_HIDDEN|FILE_ATTRIBUTE_SYSTEM);
849 FIXME("(%s):%lx attribute(s) not implemented.\n", lpFileName,attributes);
850 if (-1==chmod(full_name.long_name,buf.st_mode))
852 if(GetDriveTypeA(lpFileName) == DRIVE_CDROM) {
853 SetLastError( ERROR_ACCESS_DENIED );
858 * FIXME: We don't return FALSE here because of differences between
859 * Linux and Windows privileges. Under Linux only the owner of
860 * the file is allowed to change file attributes. Under Windows,
861 * applications expect that if you can write to a file, you can also
862 * change its attributes (see GENERIC_WRITE). We could try to be
863 * clever here but that would break multi-user installations where
864 * users share read-only DLLs. This is because some installers like
865 * to change attributes of already installed DLLs.
867 FIXME("Couldn't set file attributes for existing file \"%s\".\n"
868 "Check permissions or set VFAT \"quiet\" mount flag\n", full_name.long_name);
874 /**************************************************************************
875 * SetFileAttributesW (KERNEL32.@)
877 BOOL WINAPI SetFileAttributesW(LPCWSTR lpFileName, DWORD attributes)
880 DWORD len = WideCharToMultiByte( CP_ACP, 0, lpFileName, -1, NULL, 0, NULL, NULL );
881 LPSTR afn = HeapAlloc( GetProcessHeap(), 0, len );
883 WideCharToMultiByte( CP_ACP, 0, lpFileName, -1, afn, len, NULL, NULL );
884 res = SetFileAttributesA( afn, attributes );
885 HeapFree( GetProcessHeap(), 0, afn );
890 /***********************************************************************
891 * GetFileSize (KERNEL32.@)
893 DWORD WINAPI GetFileSize( HANDLE hFile, LPDWORD filesizehigh )
895 BY_HANDLE_FILE_INFORMATION info;
896 if (!GetFileInformationByHandle( hFile, &info )) return -1;
897 if (filesizehigh) *filesizehigh = info.nFileSizeHigh;
898 return info.nFileSizeLow;
902 /***********************************************************************
903 * GetFileTime (KERNEL32.@)
905 BOOL WINAPI GetFileTime( HANDLE hFile, FILETIME *lpCreationTime,
906 FILETIME *lpLastAccessTime,
907 FILETIME *lpLastWriteTime )
909 BY_HANDLE_FILE_INFORMATION info;
910 if (!GetFileInformationByHandle( hFile, &info )) return FALSE;
911 if (lpCreationTime) *lpCreationTime = info.ftCreationTime;
912 if (lpLastAccessTime) *lpLastAccessTime = info.ftLastAccessTime;
913 if (lpLastWriteTime) *lpLastWriteTime = info.ftLastWriteTime;
917 /***********************************************************************
918 * CompareFileTime (KERNEL32.@)
920 INT WINAPI CompareFileTime( LPFILETIME x, LPFILETIME y )
922 if (!x || !y) return -1;
924 if (x->dwHighDateTime > y->dwHighDateTime)
926 if (x->dwHighDateTime < y->dwHighDateTime)
928 if (x->dwLowDateTime > y->dwLowDateTime)
930 if (x->dwLowDateTime < y->dwLowDateTime)
935 /***********************************************************************
936 * FILE_GetTempFileName : utility for GetTempFileName
938 static UINT FILE_GetTempFileName( LPCSTR path, LPCSTR prefix, UINT unique,
939 LPSTR buffer, BOOL isWin16 )
941 static UINT unique_temp;
942 DOS_FULL_NAME full_name;
947 if ( !path || !prefix || !buffer ) return 0;
949 if (!unique_temp) unique_temp = time(NULL) & 0xffff;
950 num = unique ? (unique & 0xffff) : (unique_temp++ & 0xffff);
952 strcpy( buffer, path );
953 p = buffer + strlen(buffer);
955 /* add a \, if there isn't one and path is more than just the drive letter ... */
956 if ( !((strlen(buffer) == 2) && (buffer[1] == ':'))
957 && ((p == buffer) || (p[-1] != '\\'))) *p++ = '\\';
959 if (isWin16) *p++ = '~';
960 for (i = 3; (i > 0) && (*prefix); i--) *p++ = *prefix++;
961 sprintf( p, "%04x.tmp", num );
963 /* Now try to create it */
969 HFILE handle = CreateFileA( buffer, GENERIC_WRITE, 0, NULL,
970 CREATE_NEW, FILE_ATTRIBUTE_NORMAL, 0 );
971 if (handle != INVALID_HANDLE_VALUE)
972 { /* We created it */
973 TRACE("created %s\n",
975 CloseHandle( handle );
978 if (GetLastError() != ERROR_FILE_EXISTS)
979 break; /* No need to go on */
981 sprintf( p, "%04x.tmp", num );
982 } while (num != (unique & 0xffff));
985 /* Get the full path name */
987 if (DOSFS_GetFullName( buffer, FALSE, &full_name ))
989 /* Check if we have write access in the directory */
990 if ((p = strrchr( full_name.long_name, '/' ))) *p = '\0';
991 if (access( full_name.long_name, W_OK ) == -1)
992 WARN("returns '%s', which doesn't seem to be writeable.\n",
995 TRACE("returning %s\n", buffer );
996 return unique ? unique : num;
1000 /***********************************************************************
1001 * GetTempFileNameA (KERNEL32.@)
1003 UINT WINAPI GetTempFileNameA( LPCSTR path, LPCSTR prefix, UINT unique,
1006 return FILE_GetTempFileName(path, prefix, unique, buffer, FALSE);
1009 /***********************************************************************
1010 * GetTempFileNameW (KERNEL32.@)
1012 UINT WINAPI GetTempFileNameW( LPCWSTR path, LPCWSTR prefix, UINT unique,
1015 LPSTR patha,prefixa;
1019 if (!path) return 0;
1020 patha = HEAP_strdupWtoA( GetProcessHeap(), 0, path );
1021 prefixa = HEAP_strdupWtoA( GetProcessHeap(), 0, prefix );
1022 ret = FILE_GetTempFileName( patha, prefixa, unique, buffera, FALSE );
1023 MultiByteToWideChar( CP_ACP, 0, buffera, -1, buffer, MAX_PATH );
1024 HeapFree( GetProcessHeap(), 0, patha );
1025 HeapFree( GetProcessHeap(), 0, prefixa );
1030 /***********************************************************************
1031 * GetTempFileName (KERNEL.97)
1033 UINT16 WINAPI GetTempFileName16( BYTE drive, LPCSTR prefix, UINT16 unique,
1038 if (!(drive & ~TF_FORCEDRIVE)) /* drive 0 means current default drive */
1039 drive |= DRIVE_GetCurrentDrive() + 'A';
1041 if ((drive & TF_FORCEDRIVE) &&
1042 !DRIVE_IsValid( toupper(drive & ~TF_FORCEDRIVE) - 'A' ))
1044 drive &= ~TF_FORCEDRIVE;
1045 WARN("invalid drive %d specified\n", drive );
1048 if (drive & TF_FORCEDRIVE)
1049 sprintf(temppath,"%c:", drive & ~TF_FORCEDRIVE );
1051 GetTempPathA( 132, temppath );
1052 return (UINT16)FILE_GetTempFileName( temppath, prefix, unique, buffer, TRUE );
1055 /***********************************************************************
1058 * Implementation of OpenFile16() and OpenFile32().
1060 static HFILE FILE_DoOpenFile( LPCSTR name, OFSTRUCT *ofs, UINT mode,
1065 WORD filedatetime[2];
1066 DOS_FULL_NAME full_name;
1067 DWORD access, sharing;
1070 if (!ofs) return HFILE_ERROR;
1072 TRACE("%s %s %s %s%s%s%s%s%s%s%s%s\n",name,
1073 ((mode & 0x3 )==OF_READ)?"OF_READ":
1074 ((mode & 0x3 )==OF_WRITE)?"OF_WRITE":
1075 ((mode & 0x3 )==OF_READWRITE)?"OF_READWRITE":"unknown",
1076 ((mode & 0x70 )==OF_SHARE_COMPAT)?"OF_SHARE_COMPAT":
1077 ((mode & 0x70 )==OF_SHARE_DENY_NONE)?"OF_SHARE_DENY_NONE":
1078 ((mode & 0x70 )==OF_SHARE_DENY_READ)?"OF_SHARE_DENY_READ":
1079 ((mode & 0x70 )==OF_SHARE_DENY_WRITE)?"OF_SHARE_DENY_WRITE":
1080 ((mode & 0x70 )==OF_SHARE_EXCLUSIVE)?"OF_SHARE_EXCLUSIVE":"unknown",
1081 ((mode & OF_PARSE )==OF_PARSE)?"OF_PARSE ":"",
1082 ((mode & OF_DELETE )==OF_DELETE)?"OF_DELETE ":"",
1083 ((mode & OF_VERIFY )==OF_VERIFY)?"OF_VERIFY ":"",
1084 ((mode & OF_SEARCH )==OF_SEARCH)?"OF_SEARCH ":"",
1085 ((mode & OF_CANCEL )==OF_CANCEL)?"OF_CANCEL ":"",
1086 ((mode & OF_CREATE )==OF_CREATE)?"OF_CREATE ":"",
1087 ((mode & OF_PROMPT )==OF_PROMPT)?"OF_PROMPT ":"",
1088 ((mode & OF_EXIST )==OF_EXIST)?"OF_EXIST ":"",
1089 ((mode & OF_REOPEN )==OF_REOPEN)?"OF_REOPEN ":""
1093 ofs->cBytes = sizeof(OFSTRUCT);
1095 if (mode & OF_REOPEN) name = ofs->szPathName;
1098 ERR("called with `name' set to NULL ! Please debug.\n");
1102 TRACE("%s %04x\n", name, mode );
1104 /* the watcom 10.6 IDE relies on a valid path returned in ofs->szPathName
1105 Are there any cases where getting the path here is wrong?
1106 Uwe Bonnes 1997 Apr 2 */
1107 if (!GetFullPathNameA( name, sizeof(ofs->szPathName),
1108 ofs->szPathName, NULL )) goto error;
1109 FILE_ConvertOFMode( mode, &access, &sharing );
1111 /* OF_PARSE simply fills the structure */
1113 if (mode & OF_PARSE)
1115 ofs->fFixedDisk = (GetDriveType16( ofs->szPathName[0]-'A' )
1116 != DRIVE_REMOVABLE);
1117 TRACE("(%s): OF_PARSE, res = '%s'\n",
1118 name, ofs->szPathName );
1122 /* OF_CREATE is completely different from all other options, so
1125 if (mode & OF_CREATE)
1127 if ((hFileRet = CreateFileA( name, GENERIC_READ | GENERIC_WRITE,
1128 sharing, NULL, CREATE_ALWAYS,
1129 FILE_ATTRIBUTE_NORMAL, 0 ))== INVALID_HANDLE_VALUE)
1134 /* If OF_SEARCH is set, ignore the given path */
1136 if ((mode & OF_SEARCH) && !(mode & OF_REOPEN))
1138 /* First try the file name as is */
1139 if (DOSFS_GetFullName( name, TRUE, &full_name )) goto found;
1140 /* Now remove the path */
1141 if (name[0] && (name[1] == ':')) name += 2;
1142 if ((p = strrchr( name, '\\' ))) name = p + 1;
1143 if ((p = strrchr( name, '/' ))) name = p + 1;
1144 if (!name[0]) goto not_found;
1147 /* Now look for the file */
1149 if (!DIR_SearchPath( NULL, name, NULL, &full_name, win32 )) goto not_found;
1152 TRACE("found %s = %s\n",
1153 full_name.long_name, full_name.short_name );
1154 lstrcpynA( ofs->szPathName, full_name.short_name,
1155 sizeof(ofs->szPathName) );
1157 if (mode & OF_SHARE_EXCLUSIVE)
1158 /* Some InstallShield version uses OF_SHARE_EXCLUSIVE
1159 on the file <tempdir>/_ins0432._mp to determine how
1160 far installation has proceeded.
1161 _ins0432._mp is an executable and while running the
1162 application expects the open with OF_SHARE_ to fail*/
1164 As our loader closes the files after loading the executable,
1165 we can't find the running executable with FILE_InUse.
1166 The loader should keep the file open, as Windows does that, too.
1169 char *last = strrchr(full_name.long_name,'/');
1171 last = full_name.long_name - 1;
1172 if (GetModuleHandle16(last+1))
1174 TRACE("Denying shared open for %s\n",full_name.long_name);
1179 if (mode & OF_DELETE)
1181 if (unlink( full_name.long_name ) == -1) goto not_found;
1182 TRACE("(%s): OF_DELETE return = OK\n", name);
1186 hFileRet = FILE_CreateFile( full_name.long_name, access, sharing,
1187 NULL, OPEN_EXISTING, 0, 0,
1188 DRIVE_GetFlags(full_name.drive) & DRIVE_FAIL_READ_ONLY,
1189 GetDriveTypeA( full_name.short_name ) );
1190 if (!hFileRet) goto not_found;
1192 GetFileTime( hFileRet, NULL, NULL, &filetime );
1193 FileTimeToDosDateTime( &filetime, &filedatetime[0], &filedatetime[1] );
1194 if ((mode & OF_VERIFY) && (mode & OF_REOPEN))
1196 if (memcmp( ofs->reserved, filedatetime, sizeof(ofs->reserved) ))
1198 CloseHandle( hFileRet );
1199 WARN("(%s): OF_VERIFY failed\n", name );
1200 /* FIXME: what error here? */
1201 SetLastError( ERROR_FILE_NOT_FOUND );
1205 memcpy( ofs->reserved, filedatetime, sizeof(ofs->reserved) );
1207 success: /* We get here if the open was successful */
1208 TRACE("(%s): OK, return = %d\n", name, hFileRet );
1211 if (mode & OF_EXIST) /* Return the handle, but close it first */
1212 CloseHandle( hFileRet );
1216 hFileRet = Win32HandleToDosFileHandle( hFileRet );
1217 if (hFileRet == HFILE_ERROR16) goto error;
1218 if (mode & OF_EXIST) /* Return the handle, but close it first */
1219 _lclose16( hFileRet );
1223 not_found: /* We get here if the file does not exist */
1224 WARN("'%s' not found or sharing violation\n", name );
1225 SetLastError( ERROR_FILE_NOT_FOUND );
1228 error: /* We get here if there was an error opening the file */
1229 ofs->nErrCode = GetLastError();
1230 WARN("(%s): return = HFILE_ERROR error= %d\n",
1231 name,ofs->nErrCode );
1236 /***********************************************************************
1237 * OpenFile (KERNEL.74)
1238 * OpenFileEx (KERNEL.360)
1240 HFILE16 WINAPI OpenFile16( LPCSTR name, OFSTRUCT *ofs, UINT16 mode )
1242 return FILE_DoOpenFile( name, ofs, mode, FALSE );
1246 /***********************************************************************
1247 * OpenFile (KERNEL32.@)
1249 HFILE WINAPI OpenFile( LPCSTR name, OFSTRUCT *ofs, UINT mode )
1251 return FILE_DoOpenFile( name, ofs, mode, TRUE );
1255 /***********************************************************************
1256 * FILE_InitProcessDosHandles
1258 * Allocates the default DOS handles for a process. Called either by
1259 * Win32HandleToDosFileHandle below or by the DOSVM stuff.
1261 static void FILE_InitProcessDosHandles( void )
1263 dos_handles[0] = GetStdHandle(STD_INPUT_HANDLE);
1264 dos_handles[1] = GetStdHandle(STD_OUTPUT_HANDLE);
1265 dos_handles[2] = GetStdHandle(STD_ERROR_HANDLE);
1266 dos_handles[3] = GetStdHandle(STD_ERROR_HANDLE);
1267 dos_handles[4] = GetStdHandle(STD_ERROR_HANDLE);
1270 /***********************************************************************
1271 * Win32HandleToDosFileHandle (KERNEL32.21)
1273 * Allocate a DOS handle for a Win32 handle. The Win32 handle is no
1274 * longer valid after this function (even on failure).
1276 * Note: this is not exactly right, since on Win95 the Win32 handles
1277 * are on top of DOS handles and we do it the other way
1278 * around. Should be good enough though.
1280 HFILE WINAPI Win32HandleToDosFileHandle( HANDLE handle )
1284 if (!handle || (handle == INVALID_HANDLE_VALUE))
1287 for (i = 5; i < DOS_TABLE_SIZE; i++)
1288 if (!dos_handles[i])
1290 dos_handles[i] = handle;
1291 TRACE("Got %d for h32 %d\n", i, handle );
1294 CloseHandle( handle );
1295 SetLastError( ERROR_TOO_MANY_OPEN_FILES );
1300 /***********************************************************************
1301 * DosFileHandleToWin32Handle (KERNEL32.20)
1303 * Return the Win32 handle for a DOS handle.
1305 * Note: this is not exactly right, since on Win95 the Win32 handles
1306 * are on top of DOS handles and we do it the other way
1307 * around. Should be good enough though.
1309 HANDLE WINAPI DosFileHandleToWin32Handle( HFILE handle )
1311 HFILE16 hfile = (HFILE16)handle;
1312 if (hfile < 5 && !dos_handles[hfile]) FILE_InitProcessDosHandles();
1313 if ((hfile >= DOS_TABLE_SIZE) || !dos_handles[hfile])
1315 SetLastError( ERROR_INVALID_HANDLE );
1316 return INVALID_HANDLE_VALUE;
1318 return dos_handles[hfile];
1322 /***********************************************************************
1323 * DisposeLZ32Handle (KERNEL32.22)
1325 * Note: this is not entirely correct, we should only close the
1326 * 32-bit handle and not the 16-bit one, but we cannot do
1327 * this because of the way our DOS handles are implemented.
1328 * It shouldn't break anything though.
1330 void WINAPI DisposeLZ32Handle( HANDLE handle )
1334 if (!handle || (handle == INVALID_HANDLE_VALUE)) return;
1336 for (i = 5; i < DOS_TABLE_SIZE; i++)
1337 if (dos_handles[i] == handle)
1340 CloseHandle( handle );
1346 /***********************************************************************
1349 * dup2() function for DOS handles.
1351 HFILE16 FILE_Dup2( HFILE16 hFile1, HFILE16 hFile2 )
1355 if (hFile1 < 5 && !dos_handles[hFile1]) FILE_InitProcessDosHandles();
1357 if ((hFile1 >= DOS_TABLE_SIZE) || (hFile2 >= DOS_TABLE_SIZE) || !dos_handles[hFile1])
1359 SetLastError( ERROR_INVALID_HANDLE );
1360 return HFILE_ERROR16;
1364 FIXME("stdio handle closed, need proper conversion\n" );
1365 SetLastError( ERROR_INVALID_HANDLE );
1366 return HFILE_ERROR16;
1368 if (!DuplicateHandle( GetCurrentProcess(), dos_handles[hFile1],
1369 GetCurrentProcess(), &new_handle,
1370 0, FALSE, DUPLICATE_SAME_ACCESS ))
1371 return HFILE_ERROR16;
1372 if (dos_handles[hFile2]) CloseHandle( dos_handles[hFile2] );
1373 dos_handles[hFile2] = new_handle;
1378 /***********************************************************************
1379 * _lclose (KERNEL.81)
1381 HFILE16 WINAPI _lclose16( HFILE16 hFile )
1385 FIXME("stdio handle closed, need proper conversion\n" );
1386 SetLastError( ERROR_INVALID_HANDLE );
1387 return HFILE_ERROR16;
1389 if ((hFile >= DOS_TABLE_SIZE) || !dos_handles[hFile])
1391 SetLastError( ERROR_INVALID_HANDLE );
1392 return HFILE_ERROR16;
1394 TRACE("%d (handle32=%d)\n", hFile, dos_handles[hFile] );
1395 CloseHandle( dos_handles[hFile] );
1396 dos_handles[hFile] = 0;
1401 /***********************************************************************
1402 * _lclose (KERNEL32.@)
1404 HFILE WINAPI _lclose( HFILE hFile )
1406 TRACE("handle %d\n", hFile );
1407 return CloseHandle( hFile ) ? 0 : HFILE_ERROR;
1410 /***********************************************************************
1411 * GetOverlappedResult (KERNEL32.@)
1413 * Check the result of an Asynchronous data transfer from a file.
1419 * If successful (and relevant) lpTransferred will hold the number of
1420 * bytes transferred during the async operation.
1424 * Currently only works for WaitCommEvent, ReadFile, WriteFile
1425 * with communications ports.
1428 BOOL WINAPI GetOverlappedResult(
1429 HANDLE hFile, /* [in] handle of file to check on */
1430 LPOVERLAPPED lpOverlapped, /* [in/out] pointer to overlapped */
1431 LPDWORD lpTransferred, /* [in/out] number of bytes transferred */
1432 BOOL bWait /* [in] wait for the transfer to complete ? */
1436 TRACE("(%d %p %p %x)\n", hFile, lpOverlapped, lpTransferred, bWait);
1438 if(lpOverlapped==NULL)
1440 ERR("lpOverlapped was null\n");
1443 if(!lpOverlapped->hEvent)
1445 ERR("lpOverlapped->hEvent was null\n");
1450 TRACE("waiting on %p\n",lpOverlapped);
1451 r = WaitForSingleObjectEx(lpOverlapped->hEvent, bWait?INFINITE:0, TRUE);
1452 TRACE("wait on %p returned %ld\n",lpOverlapped,r);
1453 } while (r==STATUS_USER_APC);
1456 *lpTransferred = lpOverlapped->InternalHigh;
1458 SetLastError ( lpOverlapped->Internal == STATUS_PENDING ?
1459 ERROR_IO_INCOMPLETE : RtlNtStatusToDosError ( lpOverlapped->Internal ) );
1461 return (r==WAIT_OBJECT_0);
1464 /***********************************************************************
1465 * CancelIo (KERNEL32.@)
1467 BOOL WINAPI CancelIo(HANDLE handle)
1469 async_private *ovp,*t;
1471 TRACE("handle = %x\n",handle);
1473 for (ovp = NtCurrentTeb()->pending_list; ovp; ovp = t)
1476 if ( ovp->handle == handle )
1477 cancel_async ( ovp );
1479 WaitForMultipleObjectsEx(0,NULL,FALSE,1,TRUE);
1483 /***********************************************************************
1484 * FILE_AsyncReadService (INTERNAL)
1486 * This function is called while the client is waiting on the
1487 * server, so we can't make any server calls here.
1489 static void FILE_AsyncReadService(async_private *ovp)
1491 async_fileio *fileio = (async_fileio*) ovp;
1492 LPOVERLAPPED lpOverlapped = fileio->lpOverlapped;
1494 int already = lpOverlapped->InternalHigh;
1496 TRACE("%p %p\n", lpOverlapped, fileio->buffer );
1498 /* check to see if the data is ready (non-blocking) */
1500 if ( fileio->fd_type == FD_TYPE_SOCKET )
1501 result = read (ovp->fd, &fileio->buffer[already], fileio->count - already);
1504 result = pread (ovp->fd, &fileio->buffer[already], fileio->count - already,
1505 OVERLAPPED_OFFSET (lpOverlapped) + already);
1506 if ((result < 0) && (errno == ESPIPE))
1507 result = read (ovp->fd, &fileio->buffer[already], fileio->count - already);
1510 if ( (result<0) && ((errno == EAGAIN) || (errno == EINTR)))
1512 TRACE("Deferred read %d\n",errno);
1517 /* check to see if the transfer is complete */
1520 r = FILE_GetNtStatus ();
1524 lpOverlapped->InternalHigh += result;
1525 TRACE("read %d more bytes %ld/%d so far\n",result,lpOverlapped->InternalHigh,fileio->count);
1527 if(lpOverlapped->InternalHigh >= fileio->count || fileio->fd_type == FD_TYPE_SOCKET )
1533 lpOverlapped->Internal = r;
1536 /***********************************************************************
1537 * FILE_ReadFileEx (INTERNAL)
1539 static BOOL FILE_ReadFileEx(HANDLE hFile, LPVOID buffer, DWORD bytesToRead,
1540 LPOVERLAPPED overlapped,
1541 LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine,
1549 TRACE("file %d to buf %p num %ld %p func %p\n",
1550 hFile, buffer, bytesToRead, overlapped, lpCompletionRoutine);
1552 /* check that there is an overlapped struct */
1553 if (overlapped==NULL)
1555 SetLastError(ERROR_INVALID_PARAMETER);
1559 fd = FILE_GetUnixHandleType ( hFile, GENERIC_READ, &type, &flags);
1562 WARN ( "Couldn't get FD\n" );
1565 if ( ! (flags & FD_FLAG_OVERLAPPED) ) {
1566 WARN ( "fd is not overlapped\n" );
1567 SetLastError ( ERROR_INVALID_PARAMETER );
1571 ovp = (async_fileio*) HeapAlloc(GetProcessHeap(), 0, sizeof (async_fileio));
1574 TRACE("HeapAlloc Failed\n");
1575 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1579 ovp->async.ops = ( lpCompletionRoutine ? &fileio_async_ops : &fileio_nocomp_async_ops );
1580 ovp->async.handle = hFile;
1582 ovp->async.type = ASYNC_TYPE_READ;
1583 ovp->async.func = FILE_AsyncReadService;
1584 ovp->async.event = hEvent;
1585 ovp->lpOverlapped = overlapped;
1586 ovp->count = bytesToRead;
1587 ovp->completion_func = lpCompletionRoutine;
1588 ovp->buffer = buffer;
1589 ovp->fd_type = type;
1591 return !register_new_async (&ovp->async);
1599 /***********************************************************************
1600 * ReadFileEx (KERNEL32.@)
1602 BOOL WINAPI ReadFileEx(HANDLE hFile, LPVOID buffer, DWORD bytesToRead,
1603 LPOVERLAPPED overlapped,
1604 LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine)
1606 overlapped->InternalHigh = 0;
1607 return FILE_ReadFileEx(hFile,buffer,bytesToRead,overlapped,lpCompletionRoutine, INVALID_HANDLE_VALUE);
1610 static BOOL FILE_TimeoutRead(HANDLE hFile, LPVOID buffer, DWORD bytesToRead, LPDWORD bytesRead)
1615 TRACE("%d %p %ld %p\n", hFile, buffer, bytesToRead, bytesRead );
1617 ZeroMemory(&ov, sizeof (OVERLAPPED));
1618 if(STATUS_SUCCESS==NtCreateEvent(&ov.hEvent, SYNCHRONIZE, NULL, 0, 0))
1620 if(FILE_ReadFileEx(hFile, buffer, bytesToRead, &ov, NULL, ov.hEvent))
1622 r = GetOverlappedResult(hFile, &ov, bytesRead, TRUE);
1625 CloseHandle(ov.hEvent);
1629 /***********************************************************************
1630 * ReadFile (KERNEL32.@)
1632 BOOL WINAPI ReadFile( HANDLE hFile, LPVOID buffer, DWORD bytesToRead,
1633 LPDWORD bytesRead, LPOVERLAPPED overlapped )
1635 int unix_handle, result, flags;
1638 TRACE("%d %p %ld %p %p\n", hFile, buffer, bytesToRead,
1639 bytesRead, overlapped );
1641 if (bytesRead) *bytesRead = 0; /* Do this before anything else */
1642 if (!bytesToRead) return TRUE;
1644 unix_handle = FILE_GetUnixHandleType( hFile, GENERIC_READ, &type, &flags );
1646 if (flags & FD_FLAG_OVERLAPPED)
1648 if (unix_handle == -1) return FALSE;
1649 if ( (overlapped==NULL) || NtResetEvent( overlapped->hEvent, NULL ) )
1651 TRACE("Overlapped not specified or invalid event flag\n");
1653 SetLastError(ERROR_INVALID_PARAMETER);
1658 overlapped->InternalHigh = 0;
1660 if(!FILE_ReadFileEx(hFile, buffer, bytesToRead, overlapped, NULL, overlapped->hEvent))
1663 if ( !GetOverlappedResult (hFile, overlapped, bytesRead, FALSE) )
1665 if ( GetLastError() == ERROR_IO_INCOMPLETE )
1666 SetLastError ( ERROR_IO_PENDING );
1672 if (flags & FD_FLAG_TIMEOUT)
1675 return FILE_TimeoutRead(hFile, buffer, bytesToRead, bytesRead);
1680 return SMB_ReadFile(hFile, buffer, bytesToRead, bytesRead, NULL);
1681 case FD_TYPE_CONSOLE:
1682 return ReadConsoleA(hFile, buffer, bytesToRead, bytesRead, NULL);
1685 /* normal unix files */
1686 if (unix_handle == -1)
1691 SetLastError(ERROR_INVALID_PARAMETER);
1697 /* code for synchronous reads */
1698 while ((result = read( unix_handle, buffer, bytesToRead )) == -1)
1700 if ((errno == EAGAIN) || (errno == EINTR)) continue;
1701 if ((errno == EFAULT) && !IsBadWritePtr( buffer, bytesToRead )) continue;
1705 close( unix_handle );
1706 if (result == -1) return FALSE;
1707 if (bytesRead) *bytesRead = result;
1712 /***********************************************************************
1713 * FILE_AsyncWriteService (INTERNAL)
1715 * This function is called while the client is waiting on the
1716 * server, so we can't make any server calls here.
1718 static void FILE_AsyncWriteService(struct async_private *ovp)
1720 async_fileio *fileio = (async_fileio *) ovp;
1721 LPOVERLAPPED lpOverlapped = fileio->lpOverlapped;
1723 int already = lpOverlapped->InternalHigh;
1725 TRACE("(%p %p)\n",lpOverlapped,fileio->buffer);
1727 /* write some data (non-blocking) */
1729 if ( fileio->fd_type == FD_TYPE_SOCKET )
1730 result = write(ovp->fd, &fileio->buffer[already], fileio->count - already);
1733 result = pwrite(ovp->fd, &fileio->buffer[already], fileio->count - already,
1734 OVERLAPPED_OFFSET (lpOverlapped) + already);
1735 if ((result < 0) && (errno == ESPIPE))
1736 result = write(ovp->fd, &fileio->buffer[already], fileio->count - already);
1739 if ( (result<0) && ((errno == EAGAIN) || (errno == EINTR)))
1745 /* check to see if the transfer is complete */
1748 r = FILE_GetNtStatus ();
1752 lpOverlapped->InternalHigh += result;
1754 TRACE("wrote %d more bytes %ld/%d so far\n",result,lpOverlapped->InternalHigh,fileio->count);
1756 if(lpOverlapped->InternalHigh < fileio->count)
1762 lpOverlapped->Internal = r;
1765 /***********************************************************************
1768 static BOOL FILE_WriteFileEx(HANDLE hFile, LPCVOID buffer, DWORD bytesToWrite,
1769 LPOVERLAPPED overlapped,
1770 LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine,
1778 TRACE("file %d to buf %p num %ld %p func %p handle %d\n",
1779 hFile, buffer, bytesToWrite, overlapped, lpCompletionRoutine, hEvent);
1781 if (overlapped == NULL)
1783 SetLastError(ERROR_INVALID_PARAMETER);
1787 fd = FILE_GetUnixHandleType ( hFile, GENERIC_WRITE, &type, &flags );
1790 TRACE( "Couldn't get FD\n" );
1793 if ( ! (flags & FD_FLAG_OVERLAPPED) ) {
1794 WARN ( "fd is not overlapped\n" );
1795 SetLastError ( ERROR_INVALID_PARAMETER );
1799 ovp = (async_fileio*) HeapAlloc(GetProcessHeap(), 0, sizeof (async_fileio));
1802 TRACE("HeapAlloc Failed\n");
1803 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1807 ovp->async.ops = ( lpCompletionRoutine ? &fileio_async_ops : &fileio_nocomp_async_ops );
1808 ovp->async.handle = hFile;
1810 ovp->async.type = ASYNC_TYPE_WRITE;
1811 ovp->async.func = FILE_AsyncWriteService;
1812 ovp->lpOverlapped = overlapped;
1813 ovp->async.event = hEvent;
1814 ovp->buffer = (LPVOID) buffer;
1815 ovp->count = bytesToWrite;
1816 ovp->completion_func = lpCompletionRoutine;
1817 ovp->fd_type = type;
1819 return !register_new_async (&ovp->async);
1826 /***********************************************************************
1827 * WriteFileEx (KERNEL32.@)
1829 BOOL WINAPI WriteFileEx(HANDLE hFile, LPCVOID buffer, DWORD bytesToWrite,
1830 LPOVERLAPPED overlapped,
1831 LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine)
1833 overlapped->InternalHigh = 0;
1835 return FILE_WriteFileEx(hFile, buffer, bytesToWrite, overlapped, lpCompletionRoutine, INVALID_HANDLE_VALUE);
1838 /***********************************************************************
1839 * WriteFile (KERNEL32.@)
1841 BOOL WINAPI WriteFile( HANDLE hFile, LPCVOID buffer, DWORD bytesToWrite,
1842 LPDWORD bytesWritten, LPOVERLAPPED overlapped )
1844 int unix_handle, result, flags;
1847 TRACE("%d %p %ld %p %p\n", hFile, buffer, bytesToWrite,
1848 bytesWritten, overlapped );
1850 if (bytesWritten) *bytesWritten = 0; /* Do this before anything else */
1851 if (!bytesToWrite) return TRUE;
1853 unix_handle = FILE_GetUnixHandleType( hFile, GENERIC_WRITE, &type, &flags );
1855 if (flags & FD_FLAG_OVERLAPPED)
1857 if (unix_handle == -1) return FALSE;
1858 if ( (overlapped==NULL) || NtResetEvent( overlapped->hEvent, NULL ) )
1860 TRACE("Overlapped not specified or invalid event flag\n");
1862 SetLastError(ERROR_INVALID_PARAMETER);
1867 overlapped->InternalHigh = 0;
1869 if(!FILE_WriteFileEx(hFile, buffer, bytesToWrite, overlapped, NULL, overlapped->hEvent))
1872 if ( !GetOverlappedResult (hFile, overlapped, bytesWritten, FALSE) )
1874 if ( GetLastError() == ERROR_IO_INCOMPLETE )
1875 SetLastError ( ERROR_IO_PENDING );
1884 case FD_TYPE_CONSOLE:
1885 TRACE("%d %s %ld %p %p\n", hFile, debugstr_an(buffer, bytesToWrite), bytesToWrite,
1886 bytesWritten, overlapped );
1887 return WriteConsoleA(hFile, buffer, bytesToWrite, bytesWritten, NULL);
1889 if (unix_handle == -1)
1893 /* synchronous file write */
1894 while ((result = write( unix_handle, buffer, bytesToWrite )) == -1)
1896 if ((errno == EAGAIN) || (errno == EINTR)) continue;
1897 if ((errno == EFAULT) && !IsBadReadPtr( buffer, bytesToWrite )) continue;
1898 if (errno == ENOSPC)
1899 SetLastError( ERROR_DISK_FULL );
1904 close( unix_handle );
1905 if (result == -1) return FALSE;
1906 if (bytesWritten) *bytesWritten = result;
1911 /***********************************************************************
1912 * _hread (KERNEL.349)
1914 LONG WINAPI WIN16_hread( HFILE16 hFile, SEGPTR buffer, LONG count )
1918 TRACE("%d %08lx %ld\n",
1919 hFile, (DWORD)buffer, count );
1921 /* Some programs pass a count larger than the allocated buffer */
1922 maxlen = GetSelectorLimit16( SELECTOROF(buffer) ) - OFFSETOF(buffer) + 1;
1923 if (count > maxlen) count = maxlen;
1924 return _lread(DosFileHandleToWin32Handle(hFile), MapSL(buffer), count );
1928 /***********************************************************************
1929 * _lread (KERNEL.82)
1931 UINT16 WINAPI WIN16_lread( HFILE16 hFile, SEGPTR buffer, UINT16 count )
1933 return (UINT16)WIN16_hread( hFile, buffer, (LONG)count );
1937 /***********************************************************************
1938 * _lread (KERNEL32.@)
1940 UINT WINAPI _lread( HFILE handle, LPVOID buffer, UINT count )
1943 if (!ReadFile( handle, buffer, count, &result, NULL )) return -1;
1948 /***********************************************************************
1949 * _lread16 (KERNEL.82)
1951 UINT16 WINAPI _lread16( HFILE16 hFile, LPVOID buffer, UINT16 count )
1953 return (UINT16)_lread(DosFileHandleToWin32Handle(hFile), buffer, (LONG)count );
1957 /***********************************************************************
1958 * _lcreat (KERNEL.83)
1960 HFILE16 WINAPI _lcreat16( LPCSTR path, INT16 attr )
1962 return Win32HandleToDosFileHandle( _lcreat( path, attr ) );
1966 /***********************************************************************
1967 * _lcreat (KERNEL32.@)
1969 HFILE WINAPI _lcreat( LPCSTR path, INT attr )
1971 /* Mask off all flags not explicitly allowed by the doc */
1972 attr &= FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM;
1973 TRACE("%s %02x\n", path, attr );
1974 return CreateFileA( path, GENERIC_READ | GENERIC_WRITE,
1975 FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
1976 CREATE_ALWAYS, attr, 0 );
1980 /***********************************************************************
1981 * SetFilePointer (KERNEL32.@)
1983 DWORD WINAPI SetFilePointer( HANDLE hFile, LONG distance, LONG *highword,
1986 DWORD ret = 0xffffffff;
1988 TRACE("handle %d offset %ld high %ld origin %ld\n",
1989 hFile, distance, highword?*highword:0, method );
1991 SERVER_START_REQ( set_file_pointer )
1993 req->handle = hFile;
1994 req->low = distance;
1995 req->high = highword ? *highword : (distance >= 0) ? 0 : -1;
1996 /* FIXME: assumes 1:1 mapping between Windows and Unix seek constants */
1997 req->whence = method;
1999 if (!wine_server_call_err( req ))
2001 ret = reply->new_low;
2002 if (highword) *highword = reply->new_high;
2010 /***********************************************************************
2011 * _llseek (KERNEL.84)
2014 * Seeking before the start of the file should be allowed for _llseek16,
2015 * but cause subsequent I/O operations to fail (cf. interrupt list)
2018 LONG WINAPI _llseek16( HFILE16 hFile, LONG lOffset, INT16 nOrigin )
2020 return SetFilePointer( DosFileHandleToWin32Handle(hFile), lOffset, NULL, nOrigin );
2024 /***********************************************************************
2025 * _llseek (KERNEL32.@)
2027 LONG WINAPI _llseek( HFILE hFile, LONG lOffset, INT nOrigin )
2029 return SetFilePointer( hFile, lOffset, NULL, nOrigin );
2033 /***********************************************************************
2034 * _lopen (KERNEL.85)
2036 HFILE16 WINAPI _lopen16( LPCSTR path, INT16 mode )
2038 return Win32HandleToDosFileHandle( _lopen( path, mode ) );
2042 /***********************************************************************
2043 * _lopen (KERNEL32.@)
2045 HFILE WINAPI _lopen( LPCSTR path, INT mode )
2047 DWORD access, sharing;
2049 TRACE("('%s',%04x)\n", path, mode );
2050 FILE_ConvertOFMode( mode, &access, &sharing );
2051 return CreateFileA( path, access, sharing, NULL, OPEN_EXISTING, 0, 0 );
2055 /***********************************************************************
2056 * _lwrite (KERNEL.86)
2058 UINT16 WINAPI _lwrite16( HFILE16 hFile, LPCSTR buffer, UINT16 count )
2060 return (UINT16)_hwrite( DosFileHandleToWin32Handle(hFile), buffer, (LONG)count );
2063 /***********************************************************************
2064 * _lwrite (KERNEL32.@)
2066 UINT WINAPI _lwrite( HFILE hFile, LPCSTR buffer, UINT count )
2068 return (UINT)_hwrite( hFile, buffer, (LONG)count );
2072 /***********************************************************************
2073 * _hread16 (KERNEL.349)
2075 LONG WINAPI _hread16( HFILE16 hFile, LPVOID buffer, LONG count)
2077 return _lread( DosFileHandleToWin32Handle(hFile), buffer, count );
2081 /***********************************************************************
2082 * _hread (KERNEL32.@)
2084 LONG WINAPI _hread( HFILE hFile, LPVOID buffer, LONG count)
2086 return _lread( hFile, buffer, count );
2090 /***********************************************************************
2091 * _hwrite (KERNEL.350)
2093 LONG WINAPI _hwrite16( HFILE16 hFile, LPCSTR buffer, LONG count )
2095 return _hwrite( DosFileHandleToWin32Handle(hFile), buffer, count );
2099 /***********************************************************************
2100 * _hwrite (KERNEL32.@)
2102 * experimentation yields that _lwrite:
2103 * o truncates the file at the current position with
2105 * o returns 0 on a 0 length write
2106 * o works with console handles
2109 LONG WINAPI _hwrite( HFILE handle, LPCSTR buffer, LONG count )
2113 TRACE("%d %p %ld\n", handle, buffer, count );
2117 /* Expand or truncate at current position */
2118 if (!SetEndOfFile( handle )) return HFILE_ERROR;
2121 if (!WriteFile( handle, buffer, count, &result, NULL ))
2127 /***********************************************************************
2128 * SetHandleCount (KERNEL.199)
2130 UINT16 WINAPI SetHandleCount16( UINT16 count )
2132 return SetHandleCount( count );
2136 /*************************************************************************
2137 * SetHandleCount (KERNEL32.@)
2139 UINT WINAPI SetHandleCount( UINT count )
2141 return min( 256, count );
2145 /***********************************************************************
2146 * FlushFileBuffers (KERNEL32.@)
2148 BOOL WINAPI FlushFileBuffers( HANDLE hFile )
2151 SERVER_START_REQ( flush_file )
2153 req->handle = hFile;
2154 ret = !wine_server_call_err( req );
2161 /**************************************************************************
2162 * SetEndOfFile (KERNEL32.@)
2164 BOOL WINAPI SetEndOfFile( HANDLE hFile )
2167 SERVER_START_REQ( truncate_file )
2169 req->handle = hFile;
2170 ret = !wine_server_call_err( req );
2177 /***********************************************************************
2178 * DeleteFile (KERNEL.146)
2180 BOOL16 WINAPI DeleteFile16( LPCSTR path )
2182 return DeleteFileA( path );
2186 /***********************************************************************
2187 * DeleteFileA (KERNEL32.@)
2189 BOOL WINAPI DeleteFileA( LPCSTR path )
2191 DOS_FULL_NAME full_name;
2195 SetLastError(ERROR_INVALID_PARAMETER);
2198 TRACE("'%s'\n", path );
2202 ERR("Empty path passed\n");
2205 if (DOSFS_GetDevice( path ))
2207 WARN("cannot remove DOS device '%s'!\n", path);
2208 SetLastError( ERROR_FILE_NOT_FOUND );
2212 if (!DOSFS_GetFullName( path, TRUE, &full_name )) return FALSE;
2213 if (unlink( full_name.long_name ) == -1)
2222 /***********************************************************************
2223 * DeleteFileW (KERNEL32.@)
2225 BOOL WINAPI DeleteFileW( LPCWSTR path )
2227 LPSTR xpath = HEAP_strdupWtoA( GetProcessHeap(), 0, path );
2228 BOOL ret = DeleteFileA( xpath );
2229 HeapFree( GetProcessHeap(), 0, xpath );
2234 /***********************************************************************
2235 * GetFileType (KERNEL32.@)
2237 DWORD WINAPI GetFileType( HANDLE hFile )
2239 DWORD ret = FILE_TYPE_UNKNOWN;
2240 SERVER_START_REQ( get_file_info )
2242 req->handle = hFile;
2243 if (!wine_server_call_err( req )) ret = reply->type;
2250 /* check if a file name is for an executable file (.exe or .com) */
2251 inline static BOOL is_executable( const char *name )
2253 int len = strlen(name);
2255 if (len < 4) return FALSE;
2256 return (!strcasecmp( name + len - 4, ".exe" ) ||
2257 !strcasecmp( name + len - 4, ".com" ));
2261 /***********************************************************************
2262 * FILE_AddBootRenameEntry
2264 * Adds an entry to the registry that is loaded when windows boots and
2265 * checks if there are some files to be removed or renamed/moved.
2266 * <fn1> has to be valid and <fn2> may be NULL. If both pointers are
2267 * non-NULL then the file is moved, otherwise it is deleted. The
2268 * entry of the registrykey is always appended with two zero
2269 * terminated strings. If <fn2> is NULL then the second entry is
2270 * simply a single 0-byte. Otherwise the second filename goes
2271 * there. The entries are prepended with \??\ before the path and the
2272 * second filename gets also a '!' as the first character if
2273 * MOVEFILE_REPLACE_EXISTING is set. After the final string another
2274 * 0-byte follows to indicate the end of the strings.
2276 * \??\D:\test\file1[0]
2277 * !\??\D:\test\file1_renamed[0]
2278 * \??\D:\Test|delete[0]
2279 * [0] <- file is to be deleted, second string empty
2280 * \??\D:\test\file2[0]
2281 * !\??\D:\test\file2_renamed[0]
2282 * [0] <- indicates end of strings
2285 * \??\D:\test\file1[0]
2286 * !\??\D:\test\file1_renamed[0]
2287 * \??\D:\Test|delete[0]
2288 * [0] <- file is to be deleted, second string empty
2289 * [0] <- indicates end of strings
2292 static BOOL FILE_AddBootRenameEntry( const char *fn1, const char *fn2, DWORD flags )
2294 static const char PreString[] = "\\??\\";
2295 static const char ValueName[] = "PendingFileRenameOperations";
2299 DWORD Type, len1, len2, l;
2301 BYTE *Buffer = NULL;
2303 if(RegCreateKeyA(HKEY_LOCAL_MACHINE, "SYSTEM\\CurrentControlSet\\Control\\Session Manager",
2304 &Reboot) != ERROR_SUCCESS)
2306 WARN("Error creating key for reboot managment [%s]\n",
2307 "SYSTEM\\CurrentControlSet\\Control\\Session Manager");
2311 l = strlen(PreString);
2312 len1 = strlen(fn1) + l + 1;
2315 len2 = strlen(fn2) + l + 1;
2316 if (flags & MOVEFILE_REPLACE_EXISTING) len2++; /* Plus 1 because of the leading '!' */
2318 else len2 = 1; /* minimum is the 0 byte for the empty second string */
2320 /* First we check if the key exists and if so how many bytes it already contains. */
2321 if (RegQueryValueExA(Reboot, ValueName, NULL, &Type, NULL, &DataSize) == ERROR_SUCCESS)
2323 if (Type != REG_MULTI_SZ) goto Quit;
2324 if (!(Buffer = HeapAlloc( GetProcessHeap(), 0, DataSize + len1 + len2 + 1 ))) goto Quit;
2325 if (RegQueryValueExA(Reboot, ValueName, NULL, &Type, Buffer, &DataSize) != ERROR_SUCCESS)
2327 if (DataSize) DataSize--; /* remove terminating null (will be added back later) */
2331 if (!(Buffer = HeapAlloc( GetProcessHeap(), 0, len1 + len2 + 1 ))) goto Quit;
2334 sprintf( Buffer + DataSize, "%s%s", PreString, fn1 );
2338 sprintf( Buffer + DataSize, "%s%s%s",
2339 (flags & MOVEFILE_REPLACE_EXISTING) ? "!" : "", PreString, fn2 );
2342 else Buffer[DataSize++] = 0;
2344 Buffer[DataSize++] = 0; /* add final null */
2345 rc = !RegSetValueExA( Reboot, ValueName, 0, REG_MULTI_SZ, Buffer, DataSize );
2348 if (Reboot) RegCloseKey(Reboot);
2349 if (Buffer) HeapFree( GetProcessHeap(), 0, Buffer );
2354 /**************************************************************************
2355 * MoveFileExA (KERNEL32.@)
2357 BOOL WINAPI MoveFileExA( LPCSTR fn1, LPCSTR fn2, DWORD flag )
2359 DOS_FULL_NAME full_name1, full_name2;
2361 TRACE("(%s,%s,%04lx)\n", fn1, fn2, flag);
2363 /* FIXME: <Gerhard W. Gruber>sparhawk@gmx.at
2364 In case of W9x and lesser this function should return 120 (ERROR_CALL_NOT_IMPLEMENTED)
2365 to be really compatible. Most programs wont have any problems though. In case
2366 you encounter one, this is what you should return here. I don't know what's up
2367 with NT 3.5. Is this function available there or not?
2368 Does anybody really care about 3.5? :)
2371 /* Filename1 has to be always set to a valid path. Filename2 may be NULL
2372 if the source file has to be deleted.
2375 SetLastError(ERROR_INVALID_PARAMETER);
2379 /* This function has to be run through in order to process the name properly.
2380 If the BOOTDELAY flag is set, the file doesn't need to exist though. At least
2381 that is the behaviour on NT 4.0. The operation accepts the filenames as
2382 they are given but it can't reply with a reasonable returncode. Success
2383 means in that case success for entering the values into the registry.
2385 if(!DOSFS_GetFullName( fn1, TRUE, &full_name1 ))
2387 if(!(flag & MOVEFILE_DELAY_UNTIL_REBOOT))
2391 if (fn2) /* !fn2 means delete fn1 */
2393 if (DOSFS_GetFullName( fn2, TRUE, &full_name2 ))
2395 if(!(flag & MOVEFILE_DELAY_UNTIL_REBOOT))
2397 /* target exists, check if we may overwrite */
2398 if (!(flag & MOVEFILE_REPLACE_EXISTING))
2400 /* FIXME: Use right error code */
2401 SetLastError( ERROR_ACCESS_DENIED );
2408 if (!DOSFS_GetFullName( fn2, FALSE, &full_name2 ))
2410 if(!(flag & MOVEFILE_DELAY_UNTIL_REBOOT))
2415 /* Source name and target path are valid */
2417 if (flag & MOVEFILE_DELAY_UNTIL_REBOOT)
2419 /* FIXME: (bon@elektron.ikp.physik.th-darmstadt.de 970706)
2420 Perhaps we should queue these command and execute it
2421 when exiting... What about using on_exit(2)
2423 FIXME("Please move existing file '%s' to file '%s' when Wine has finished\n",
2425 return FILE_AddBootRenameEntry( fn1, fn2, flag );
2428 if (full_name1.drive != full_name2.drive)
2430 /* use copy, if allowed */
2431 if (!(flag & MOVEFILE_COPY_ALLOWED))
2433 /* FIXME: Use right error code */
2434 SetLastError( ERROR_FILE_EXISTS );
2437 return CopyFileA( fn1, fn2, !(flag & MOVEFILE_REPLACE_EXISTING) );
2439 if (rename( full_name1.long_name, full_name2.long_name ) == -1)
2444 if (is_executable( full_name1.long_name ) != is_executable( full_name2.long_name ))
2447 if (stat( full_name2.long_name, &fstat ) != -1)
2449 if (is_executable( full_name2.long_name ))
2450 /* set executable bit where read bit is set */
2451 fstat.st_mode |= (fstat.st_mode & 0444) >> 2;
2453 fstat.st_mode &= ~0111;
2454 chmod( full_name2.long_name, fstat.st_mode );
2459 else /* fn2 == NULL means delete source */
2461 if (flag & MOVEFILE_DELAY_UNTIL_REBOOT)
2463 if (flag & MOVEFILE_COPY_ALLOWED) {
2464 WARN("Illegal flag\n");
2465 SetLastError( ERROR_GEN_FAILURE );
2468 /* FIXME: (bon@elektron.ikp.physik.th-darmstadt.de 970706)
2469 Perhaps we should queue these command and execute it
2470 when exiting... What about using on_exit(2)
2472 FIXME("Please delete file '%s' when Wine has finished\n", fn1);
2473 return FILE_AddBootRenameEntry( fn1, NULL, flag );
2476 if (unlink( full_name1.long_name ) == -1)
2481 return TRUE; /* successfully deleted */
2485 /**************************************************************************
2486 * MoveFileExW (KERNEL32.@)
2488 BOOL WINAPI MoveFileExW( LPCWSTR fn1, LPCWSTR fn2, DWORD flag )
2490 LPSTR afn1 = HEAP_strdupWtoA( GetProcessHeap(), 0, fn1 );
2491 LPSTR afn2 = HEAP_strdupWtoA( GetProcessHeap(), 0, fn2 );
2492 BOOL res = MoveFileExA( afn1, afn2, flag );
2493 HeapFree( GetProcessHeap(), 0, afn1 );
2494 HeapFree( GetProcessHeap(), 0, afn2 );
2499 /**************************************************************************
2500 * MoveFileA (KERNEL32.@)
2502 * Move file or directory
2504 BOOL WINAPI MoveFileA( LPCSTR fn1, LPCSTR fn2 )
2506 DOS_FULL_NAME full_name1, full_name2;
2509 TRACE("(%s,%s)\n", fn1, fn2 );
2511 if (!DOSFS_GetFullName( fn1, TRUE, &full_name1 )) return FALSE;
2512 if (DOSFS_GetFullName( fn2, TRUE, &full_name2 )) {
2513 /* The new name must not already exist */
2514 SetLastError(ERROR_ALREADY_EXISTS);
2517 if (!DOSFS_GetFullName( fn2, FALSE, &full_name2 )) return FALSE;
2519 if (full_name1.drive == full_name2.drive) /* move */
2520 return MoveFileExA( fn1, fn2, MOVEFILE_COPY_ALLOWED );
2523 if (stat( full_name1.long_name, &fstat ))
2525 WARN("Invalid source file %s\n",
2526 full_name1.long_name);
2530 if (S_ISDIR(fstat.st_mode)) {
2531 /* No Move for directories across file systems */
2532 /* FIXME: Use right error code */
2533 SetLastError( ERROR_GEN_FAILURE );
2536 return CopyFileA(fn1, fn2, TRUE); /*fail, if exist */
2540 /**************************************************************************
2541 * MoveFileW (KERNEL32.@)
2543 BOOL WINAPI MoveFileW( LPCWSTR fn1, LPCWSTR fn2 )
2545 LPSTR afn1 = HEAP_strdupWtoA( GetProcessHeap(), 0, fn1 );
2546 LPSTR afn2 = HEAP_strdupWtoA( GetProcessHeap(), 0, fn2 );
2547 BOOL res = MoveFileA( afn1, afn2 );
2548 HeapFree( GetProcessHeap(), 0, afn1 );
2549 HeapFree( GetProcessHeap(), 0, afn2 );
2554 /**************************************************************************
2555 * CopyFileA (KERNEL32.@)
2557 BOOL WINAPI CopyFileA( LPCSTR source, LPCSTR dest, BOOL fail_if_exists )
2560 BY_HANDLE_FILE_INFORMATION info;
2566 if ((h1 = _lopen( source, OF_READ )) == HFILE_ERROR) return FALSE;
2567 if (!GetFileInformationByHandle( h1, &info ))
2572 mode = (info.dwFileAttributes & FILE_ATTRIBUTE_READONLY) ? 0444 : 0666;
2573 if ((h2 = CreateFileA( dest, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
2574 fail_if_exists ? CREATE_NEW : CREATE_ALWAYS,
2575 info.dwFileAttributes, h1 )) == INVALID_HANDLE_VALUE)
2580 while ((count = _lread( h1, buffer, sizeof(buffer) )) > 0)
2585 INT res = _lwrite( h2, p, count );
2586 if (res <= 0) goto done;
2599 /**************************************************************************
2600 * CopyFileW (KERNEL32.@)
2602 BOOL WINAPI CopyFileW( LPCWSTR source, LPCWSTR dest, BOOL fail_if_exists)
2604 LPSTR sourceA = HEAP_strdupWtoA( GetProcessHeap(), 0, source );
2605 LPSTR destA = HEAP_strdupWtoA( GetProcessHeap(), 0, dest );
2606 BOOL ret = CopyFileA( sourceA, destA, fail_if_exists );
2607 HeapFree( GetProcessHeap(), 0, sourceA );
2608 HeapFree( GetProcessHeap(), 0, destA );
2613 /**************************************************************************
2614 * CopyFileExA (KERNEL32.@)
2616 * This implementation ignores most of the extra parameters passed-in into
2617 * the "ex" version of the method and calls the CopyFile method.
2618 * It will have to be fixed eventually.
2620 BOOL WINAPI CopyFileExA(LPCSTR sourceFilename,
2621 LPCSTR destFilename,
2622 LPPROGRESS_ROUTINE progressRoutine,
2624 LPBOOL cancelFlagPointer,
2627 BOOL failIfExists = FALSE;
2630 * Interpret the only flag that CopyFile can interpret.
2632 if ( (copyFlags & COPY_FILE_FAIL_IF_EXISTS) != 0)
2634 failIfExists = TRUE;
2637 return CopyFileA(sourceFilename, destFilename, failIfExists);
2640 /**************************************************************************
2641 * CopyFileExW (KERNEL32.@)
2643 BOOL WINAPI CopyFileExW(LPCWSTR sourceFilename,
2644 LPCWSTR destFilename,
2645 LPPROGRESS_ROUTINE progressRoutine,
2647 LPBOOL cancelFlagPointer,
2650 LPSTR sourceA = HEAP_strdupWtoA( GetProcessHeap(), 0, sourceFilename );
2651 LPSTR destA = HEAP_strdupWtoA( GetProcessHeap(), 0, destFilename );
2653 BOOL ret = CopyFileExA(sourceA,
2660 HeapFree( GetProcessHeap(), 0, sourceA );
2661 HeapFree( GetProcessHeap(), 0, destA );
2667 /***********************************************************************
2668 * SetFileTime (KERNEL32.@)
2670 BOOL WINAPI SetFileTime( HANDLE hFile,
2671 const FILETIME *lpCreationTime,
2672 const FILETIME *lpLastAccessTime,
2673 const FILETIME *lpLastWriteTime )
2676 SERVER_START_REQ( set_file_time )
2678 req->handle = hFile;
2679 if (lpLastAccessTime)
2680 RtlTimeToSecondsSince1970( lpLastAccessTime, (DWORD *)&req->access_time );
2682 req->access_time = 0; /* FIXME */
2683 if (lpLastWriteTime)
2684 RtlTimeToSecondsSince1970( lpLastWriteTime, (DWORD *)&req->write_time );
2686 req->write_time = 0; /* FIXME */
2687 ret = !wine_server_call_err( req );
2694 /**************************************************************************
2695 * LockFile (KERNEL32.@)
2697 BOOL WINAPI LockFile( HANDLE hFile, DWORD dwFileOffsetLow, DWORD dwFileOffsetHigh,
2698 DWORD nNumberOfBytesToLockLow, DWORD nNumberOfBytesToLockHigh )
2701 SERVER_START_REQ( lock_file )
2703 req->handle = hFile;
2704 req->offset_low = dwFileOffsetLow;
2705 req->offset_high = dwFileOffsetHigh;
2706 req->count_low = nNumberOfBytesToLockLow;
2707 req->count_high = nNumberOfBytesToLockHigh;
2708 ret = !wine_server_call_err( req );
2714 /**************************************************************************
2715 * LockFileEx [KERNEL32.@]
2717 * Locks a byte range within an open file for shared or exclusive access.
2724 * Per Microsoft docs, the third parameter (reserved) must be set to 0.
2726 BOOL WINAPI LockFileEx( HANDLE hFile, DWORD flags, DWORD reserved,
2727 DWORD nNumberOfBytesToLockLow, DWORD nNumberOfBytesToLockHigh,
2728 LPOVERLAPPED pOverlapped )
2730 FIXME("hFile=%d,flags=%ld,reserved=%ld,lowbytes=%ld,highbytes=%ld,overlapped=%p: stub.\n",
2731 hFile, flags, reserved, nNumberOfBytesToLockLow, nNumberOfBytesToLockHigh,
2734 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
2737 ERR("reserved == %ld: Supposed to be 0??\n", reserved);
2738 SetLastError(ERROR_INVALID_PARAMETER);
2745 /**************************************************************************
2746 * UnlockFile (KERNEL32.@)
2748 BOOL WINAPI UnlockFile( HANDLE hFile, DWORD dwFileOffsetLow, DWORD dwFileOffsetHigh,
2749 DWORD nNumberOfBytesToUnlockLow, DWORD nNumberOfBytesToUnlockHigh )
2752 SERVER_START_REQ( unlock_file )
2754 req->handle = hFile;
2755 req->offset_low = dwFileOffsetLow;
2756 req->offset_high = dwFileOffsetHigh;
2757 req->count_low = nNumberOfBytesToUnlockLow;
2758 req->count_high = nNumberOfBytesToUnlockHigh;
2759 ret = !wine_server_call_err( req );
2766 /**************************************************************************
2767 * UnlockFileEx (KERNEL32.@)
2769 BOOL WINAPI UnlockFileEx(
2772 DWORD nNumberOfBytesToUnlockLow,
2773 DWORD nNumberOfBytesToUnlockHigh,
2774 LPOVERLAPPED lpOverlapped
2777 FIXME("hFile=%d,reserved=%ld,lowbytes=%ld,highbytes=%ld,overlapped=%p: stub.\n",
2778 hFile, dwReserved, nNumberOfBytesToUnlockLow, nNumberOfBytesToUnlockHigh,
2780 if (dwReserved == 0)
2781 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
2784 ERR("reserved == %ld: Supposed to be 0??\n", dwReserved);
2785 SetLastError(ERROR_INVALID_PARAMETER);
2794 struct DOS_FILE_LOCK {
2795 struct DOS_FILE_LOCK * next;
2799 FILE_OBJECT * dos_file;
2800 /* char * unix_name;*/
2803 typedef struct DOS_FILE_LOCK DOS_FILE_LOCK;
2805 static DOS_FILE_LOCK *locks = NULL;
2806 static void DOS_RemoveFileLocks(FILE_OBJECT *file);
2809 /* Locks need to be mirrored because unix file locking is based
2810 * on the pid. Inside of wine there can be multiple WINE processes
2811 * that share the same unix pid.
2812 * Read's and writes should check these locks also - not sure
2813 * how critical that is at this point (FIXME).
2816 static BOOL DOS_AddLock(FILE_OBJECT *file, struct flock *f)
2818 DOS_FILE_LOCK *curr;
2821 processId = GetCurrentProcessId();
2823 /* check if lock overlaps a current lock for the same file */
2825 for (curr = locks; curr; curr = curr->next) {
2826 if (strcmp(curr->unix_name, file->unix_name) == 0) {
2827 if ((f->l_start == curr->base) && (f->l_len == curr->len))
2828 return TRUE;/* region is identic */
2829 if ((f->l_start < (curr->base + curr->len)) &&
2830 ((f->l_start + f->l_len) > curr->base)) {
2831 /* region overlaps */
2838 curr = HeapAlloc( GetProcessHeap(), 0, sizeof(DOS_FILE_LOCK) );
2839 curr->processId = GetCurrentProcessId();
2840 curr->base = f->l_start;
2841 curr->len = f->l_len;
2842 /* curr->unix_name = HEAP_strdupA( GetProcessHeap(), 0, file->unix_name);*/
2844 curr->dos_file = file;
2849 static void DOS_RemoveFileLocks(FILE_OBJECT *file)
2852 DOS_FILE_LOCK **curr;
2855 processId = GetCurrentProcessId();
2858 if ((*curr)->dos_file == file) {
2860 *curr = (*curr)->next;
2861 /* HeapFree( GetProcessHeap(), 0, rem->unix_name );*/
2862 HeapFree( GetProcessHeap(), 0, rem );
2865 curr = &(*curr)->next;
2869 static BOOL DOS_RemoveLock(FILE_OBJECT *file, struct flock *f)
2872 DOS_FILE_LOCK **curr;
2875 processId = GetCurrentProcessId();
2876 for (curr = &locks; *curr; curr = &(*curr)->next) {
2877 if ((*curr)->processId == processId &&
2878 (*curr)->dos_file == file &&
2879 (*curr)->base == f->l_start &&
2880 (*curr)->len == f->l_len) {
2881 /* this is the same lock */
2883 *curr = (*curr)->next;
2884 /* HeapFree( GetProcessHeap(), 0, rem->unix_name );*/
2885 HeapFree( GetProcessHeap(), 0, rem );
2889 /* no matching lock found */
2894 /**************************************************************************
2895 * LockFile (KERNEL32.@)
2897 BOOL WINAPI LockFile(
2898 HFILE hFile,DWORD dwFileOffsetLow,DWORD dwFileOffsetHigh,
2899 DWORD nNumberOfBytesToLockLow,DWORD nNumberOfBytesToLockHigh )
2904 TRACE("handle %d offsetlow=%ld offsethigh=%ld nbyteslow=%ld nbyteshigh=%ld\n",
2905 hFile, dwFileOffsetLow, dwFileOffsetHigh,
2906 nNumberOfBytesToLockLow, nNumberOfBytesToLockHigh);
2908 if (dwFileOffsetHigh || nNumberOfBytesToLockHigh) {
2909 FIXME("Unimplemented bytes > 32bits\n");
2913 f.l_start = dwFileOffsetLow;
2914 f.l_len = nNumberOfBytesToLockLow;
2915 f.l_whence = SEEK_SET;
2919 if (!(file = FILE_GetFile(hFile,0,NULL))) return FALSE;
2921 /* shadow locks internally */
2922 if (!DOS_AddLock(file, &f)) {
2923 SetLastError( ERROR_LOCK_VIOLATION );
2927 /* FIXME: Unix locking commented out for now, doesn't work with Excel */
2928 #ifdef USE_UNIX_LOCKS
2929 if (fcntl(file->unix_handle, F_SETLK, &f) == -1) {
2930 if (errno == EACCES || errno == EAGAIN) {
2931 SetLastError( ERROR_LOCK_VIOLATION );
2936 /* remove our internal copy of the lock */
2937 DOS_RemoveLock(file, &f);
2945 /**************************************************************************
2946 * UnlockFile (KERNEL32.@)
2948 BOOL WINAPI UnlockFile(
2949 HFILE hFile,DWORD dwFileOffsetLow,DWORD dwFileOffsetHigh,
2950 DWORD nNumberOfBytesToUnlockLow,DWORD nNumberOfBytesToUnlockHigh )
2955 TRACE("handle %d offsetlow=%ld offsethigh=%ld nbyteslow=%ld nbyteshigh=%ld\n",
2956 hFile, dwFileOffsetLow, dwFileOffsetHigh,
2957 nNumberOfBytesToUnlockLow, nNumberOfBytesToUnlockHigh);
2959 if (dwFileOffsetHigh || nNumberOfBytesToUnlockHigh) {
2960 WARN("Unimplemented bytes > 32bits\n");
2964 f.l_start = dwFileOffsetLow;
2965 f.l_len = nNumberOfBytesToUnlockLow;
2966 f.l_whence = SEEK_SET;
2970 if (!(file = FILE_GetFile(hFile,0,NULL))) return FALSE;
2972 DOS_RemoveLock(file, &f); /* ok if fails - may be another wine */
2974 /* FIXME: Unix locking commented out for now, doesn't work with Excel */
2975 #ifdef USE_UNIX_LOCKS
2976 if (fcntl(file->unix_handle, F_SETLK, &f) == -1) {
2985 /**************************************************************************
2986 * GetFileAttributesExA [KERNEL32.@]
2988 BOOL WINAPI GetFileAttributesExA(
2989 LPCSTR lpFileName, GET_FILEEX_INFO_LEVELS fInfoLevelId,
2990 LPVOID lpFileInformation)
2992 DOS_FULL_NAME full_name;
2993 BY_HANDLE_FILE_INFORMATION info;
2995 if (lpFileName == NULL) return FALSE;
2996 if (lpFileInformation == NULL) return FALSE;
2998 if (fInfoLevelId == GetFileExInfoStandard) {
2999 LPWIN32_FILE_ATTRIBUTE_DATA lpFad =
3000 (LPWIN32_FILE_ATTRIBUTE_DATA) lpFileInformation;
3001 if (!DOSFS_GetFullName( lpFileName, TRUE, &full_name )) return FALSE;
3002 if (!FILE_Stat( full_name.long_name, &info )) return FALSE;
3004 lpFad->dwFileAttributes = info.dwFileAttributes;
3005 lpFad->ftCreationTime = info.ftCreationTime;
3006 lpFad->ftLastAccessTime = info.ftLastAccessTime;
3007 lpFad->ftLastWriteTime = info.ftLastWriteTime;
3008 lpFad->nFileSizeHigh = info.nFileSizeHigh;
3009 lpFad->nFileSizeLow = info.nFileSizeLow;
3012 FIXME("invalid info level %d!\n", fInfoLevelId);
3020 /**************************************************************************
3021 * GetFileAttributesExW [KERNEL32.@]
3023 BOOL WINAPI GetFileAttributesExW(
3024 LPCWSTR lpFileName, GET_FILEEX_INFO_LEVELS fInfoLevelId,
3025 LPVOID lpFileInformation)
3027 LPSTR nameA = HEAP_strdupWtoA( GetProcessHeap(), 0, lpFileName );
3029 GetFileAttributesExA( nameA, fInfoLevelId, lpFileInformation);
3030 HeapFree( GetProcessHeap(), 0, nameA );