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 /***********************************************************************
310 * FILE_GetUnixHandleType
312 * Retrieve the Unix handle corresponding to a file handle.
313 * Returns -1 on failure.
315 static int FILE_GetUnixHandleType( HANDLE handle, DWORD access, enum fd_type *type, int *flags_ptr )
317 int ret, flags, fd = -1;
319 ret = wine_server_handle_to_fd( handle, access, &fd, type, &flags );
320 if (flags_ptr) *flags_ptr = flags;
321 if (ret) SetLastError( RtlNtStatusToDosError(ret) );
322 else if (((access & GENERIC_READ) && (flags & FD_FLAG_RECV_SHUTDOWN)) ||
323 ((access & GENERIC_WRITE) && (flags & FD_FLAG_SEND_SHUTDOWN)))
326 SetLastError ( ERROR_PIPE_NOT_CONNECTED );
332 /***********************************************************************
335 * Retrieve the Unix handle corresponding to a file handle.
336 * Returns -1 on failure.
338 int FILE_GetUnixHandle( HANDLE handle, DWORD access )
340 return FILE_GetUnixHandleType( handle, access, NULL, NULL );
343 /*************************************************************************
346 * Open a handle to the current process console.
347 * Returns 0 on failure.
349 static HANDLE FILE_OpenConsole( BOOL output, DWORD access, DWORD sharing, LPSECURITY_ATTRIBUTES sa )
353 SERVER_START_REQ( open_console )
356 req->access = access;
357 req->share = sharing;
358 req->inherit = (sa && (sa->nLength>=sizeof(*sa)) && sa->bInheritHandle);
360 wine_server_call_err( req );
367 /* FIXME: those routines defined as pointers are needed, because this file is
368 * currently compiled into NTDLL whereas it belongs to kernel32.
369 * this shall go away once all the DLL separation process is done
371 typedef BOOL (WINAPI* pRW)(HANDLE, const void*, DWORD, DWORD*, void*);
373 static BOOL FILE_ReadConsole(HANDLE hCon, void* buf, DWORD nb, DWORD* nr, void* p)
375 static HANDLE hKernel /* = 0 */;
376 static pRW pReadConsole /* = 0 */;
378 if ((!hKernel && !(hKernel = LoadLibraryA("kernel32"))) ||
380 !(pReadConsole = GetProcAddress(hKernel, "ReadConsoleA"))))
385 return (pReadConsole)(hCon, buf, nb, nr, p);
388 static BOOL FILE_WriteConsole(HANDLE hCon, const void* buf, DWORD nb, DWORD* nr, void* p)
390 static HANDLE hKernel /* = 0 */;
391 static pRW pWriteConsole /* = 0 */;
393 if ((!hKernel && !(hKernel = LoadLibraryA("kernel32"))) ||
395 !(pWriteConsole = GetProcAddress(hKernel, "WriteConsoleA"))))
400 return (pWriteConsole)(hCon, buf, nb, nr, p);
404 /***********************************************************************
407 * Implementation of CreateFile. Takes a Unix path name.
408 * Returns 0 on failure.
410 HANDLE FILE_CreateFile( LPCSTR filename, DWORD access, DWORD sharing,
411 LPSECURITY_ATTRIBUTES sa, DWORD creation,
412 DWORD attributes, HANDLE template, BOOL fail_read_only,
420 SERVER_START_REQ( create_file )
422 req->access = access;
423 req->inherit = (sa && (sa->nLength>=sizeof(*sa)) && sa->bInheritHandle);
424 req->sharing = sharing;
425 req->create = creation;
426 req->attrs = attributes;
427 req->drive_type = drive_type;
428 wine_server_add_data( req, filename, strlen(filename) );
430 err = wine_server_call( req );
435 /* If write access failed, retry without GENERIC_WRITE */
437 if (!ret && !fail_read_only && (access & GENERIC_WRITE))
439 if ((err == STATUS_MEDIA_WRITE_PROTECTED) || (err == STATUS_ACCESS_DENIED))
441 TRACE("Write access failed for file '%s', trying without "
442 "write access\n", filename);
443 access &= ~GENERIC_WRITE;
448 if (err) SetLastError( RtlNtStatusToDosError(err) );
450 if (!ret) WARN("Unable to create file '%s' (GLE %ld)\n", filename, GetLastError());
456 /***********************************************************************
459 * Same as FILE_CreateFile but for a device
460 * Returns 0 on failure.
462 HANDLE FILE_CreateDevice( int client_id, DWORD access, LPSECURITY_ATTRIBUTES sa )
465 SERVER_START_REQ( create_device )
467 req->access = access;
468 req->inherit = (sa && (sa->nLength>=sizeof(*sa)) && sa->bInheritHandle);
471 wine_server_call_err( req );
478 static HANDLE FILE_OpenPipe(LPCSTR name, DWORD access)
480 WCHAR buffer[MAX_PATH];
484 if (name && !(len = MultiByteToWideChar( CP_ACP, 0, name, strlen(name), buffer, MAX_PATH )))
486 SetLastError( ERROR_FILENAME_EXCED_RANGE );
489 SERVER_START_REQ( open_named_pipe )
491 req->access = access;
493 wine_server_add_data( req, buffer, len * sizeof(WCHAR) );
494 wine_server_call_err( req );
498 TRACE("Returned %d\n",ret);
502 /*************************************************************************
503 * CreateFileA [KERNEL32.@] Creates or opens a file or other object
505 * Creates or opens an object, and returns a handle that can be used to
506 * access that object.
510 * filename [in] pointer to filename to be accessed
511 * access [in] access mode requested
512 * sharing [in] share mode
513 * sa [in] pointer to security attributes
514 * creation [in] how to create the file
515 * attributes [in] attributes for newly created file
516 * template [in] handle to file with extended attributes to copy
519 * Success: Open handle to specified file
520 * Failure: INVALID_HANDLE_VALUE
523 * Should call SetLastError() on failure.
527 * Doesn't support character devices, template files, or a
528 * lot of the 'attributes' flags yet.
530 HANDLE WINAPI CreateFileA( LPCSTR filename, DWORD access, DWORD sharing,
531 LPSECURITY_ATTRIBUTES sa, DWORD creation,
532 DWORD attributes, HANDLE template )
534 DOS_FULL_NAME full_name;
539 SetLastError( ERROR_INVALID_PARAMETER );
540 return INVALID_HANDLE_VALUE;
542 TRACE("%s %s%s%s%s%s%s%s\n",filename,
543 ((access & GENERIC_READ)==GENERIC_READ)?"GENERIC_READ ":"",
544 ((access & GENERIC_WRITE)==GENERIC_WRITE)?"GENERIC_WRITE ":"",
545 (!access)?"QUERY_ACCESS ":"",
546 ((sharing & FILE_SHARE_READ)==FILE_SHARE_READ)?"FILE_SHARE_READ ":"",
547 ((sharing & FILE_SHARE_WRITE)==FILE_SHARE_WRITE)?"FILE_SHARE_WRITE ":"",
548 ((sharing & FILE_SHARE_DELETE)==FILE_SHARE_DELETE)?"FILE_SHARE_DELETE ":"",
549 (creation ==CREATE_NEW)?"CREATE_NEW":
550 (creation ==CREATE_ALWAYS)?"CREATE_ALWAYS ":
551 (creation ==OPEN_EXISTING)?"OPEN_EXISTING ":
552 (creation ==OPEN_ALWAYS)?"OPEN_ALWAYS ":
553 (creation ==TRUNCATE_EXISTING)?"TRUNCATE_EXISTING ":"");
555 /* If the name starts with '\\?\', ignore the first 4 chars. */
556 if (!strncmp(filename, "\\\\?\\", 4))
559 if (!strncmp(filename, "UNC\\", 4))
561 FIXME("UNC name (%s) not supported.\n", filename );
562 SetLastError( ERROR_PATH_NOT_FOUND );
563 return INVALID_HANDLE_VALUE;
567 if (!strncmp(filename, "\\\\.\\", 4)) {
568 if(!strncasecmp(&filename[4],"pipe\\",5))
570 TRACE("Opening a pipe: %s\n",filename);
571 ret = FILE_OpenPipe(filename,access);
574 else if (isalpha(filename[4]) && filename[5] == ':' && filename[6] == '\0')
576 ret = FILE_CreateDevice( (toupper(filename[4]) - 'A') | 0x20000, access, sa );
579 else if (!DOSFS_GetDevice( filename ))
581 ret = DEVICE_Open( filename+4, access, sa );
585 filename+=4; /* fall into DOSFS_Device case below */
588 /* If the name still starts with '\\', it's a UNC name. */
589 if (!strncmp(filename, "\\\\", 2))
591 ret = SMB_CreateFileA(filename, access, sharing, sa, creation, attributes, template );
595 /* If the name contains a DOS wild card (* or ?), do no create a file */
596 if(strchr(filename,'*') || strchr(filename,'?'))
597 return INVALID_HANDLE_VALUE;
599 /* Open a console for CONIN$ or CONOUT$ */
600 if (!strcasecmp(filename, "CONIN$"))
602 ret = FILE_OpenConsole( FALSE, access, sharing, sa );
605 if (!strcasecmp(filename, "CONOUT$"))
607 ret = FILE_OpenConsole( TRUE, access, sharing, sa );
611 if (DOSFS_GetDevice( filename ))
613 TRACE("opening device '%s'\n", filename );
615 if (!(ret = DOSFS_OpenDevice( filename, access, attributes, sa )))
617 /* Do not silence this please. It is a critical error. -MM */
618 ERR("Couldn't open device '%s'!\n",filename);
619 SetLastError( ERROR_FILE_NOT_FOUND );
624 /* check for filename, don't check for last entry if creating */
625 if (!DOSFS_GetFullName( filename,
626 (creation == OPEN_EXISTING) ||
627 (creation == TRUNCATE_EXISTING),
629 WARN("Unable to get full filename from '%s' (GLE %ld)\n",
630 filename, GetLastError());
631 return INVALID_HANDLE_VALUE;
634 ret = FILE_CreateFile( full_name.long_name, access, sharing,
635 sa, creation, attributes, template,
636 DRIVE_GetFlags(full_name.drive) & DRIVE_FAIL_READ_ONLY,
637 GetDriveTypeA( full_name.short_name ) );
639 if (!ret) ret = INVALID_HANDLE_VALUE;
645 /*************************************************************************
646 * CreateFileW (KERNEL32.@)
648 HANDLE WINAPI CreateFileW( LPCWSTR filename, DWORD access, DWORD sharing,
649 LPSECURITY_ATTRIBUTES sa, DWORD creation,
650 DWORD attributes, HANDLE template)
652 LPSTR afn = HEAP_strdupWtoA( GetProcessHeap(), 0, filename );
653 HANDLE res = CreateFileA( afn, access, sharing, sa, creation, attributes, template );
654 HeapFree( GetProcessHeap(), 0, afn );
659 /***********************************************************************
662 * Fill a file information from a struct stat.
664 static void FILE_FillInfo( struct stat *st, BY_HANDLE_FILE_INFORMATION *info )
666 if (S_ISDIR(st->st_mode))
667 info->dwFileAttributes = FILE_ATTRIBUTE_DIRECTORY;
669 info->dwFileAttributes = FILE_ATTRIBUTE_ARCHIVE;
670 if (!(st->st_mode & S_IWUSR))
671 info->dwFileAttributes |= FILE_ATTRIBUTE_READONLY;
673 RtlSecondsSince1970ToTime( st->st_mtime, &info->ftCreationTime );
674 RtlSecondsSince1970ToTime( st->st_mtime, &info->ftLastWriteTime );
675 RtlSecondsSince1970ToTime( st->st_atime, &info->ftLastAccessTime );
677 info->dwVolumeSerialNumber = 0; /* FIXME */
678 info->nFileSizeHigh = 0;
679 info->nFileSizeLow = 0;
680 if (!S_ISDIR(st->st_mode)) {
681 info->nFileSizeHigh = st->st_size >> 32;
682 info->nFileSizeLow = st->st_size & 0xffffffff;
684 info->nNumberOfLinks = st->st_nlink;
685 info->nFileIndexHigh = 0;
686 info->nFileIndexLow = st->st_ino;
690 /***********************************************************************
693 * Stat a Unix path name. Return TRUE if OK.
695 BOOL FILE_Stat( LPCSTR unixName, BY_HANDLE_FILE_INFORMATION *info )
699 if (lstat( unixName, &st ) == -1)
704 if (!S_ISLNK(st.st_mode)) FILE_FillInfo( &st, info );
707 /* do a "real" stat to find out
708 about the type of the symlink destination */
709 if (stat( unixName, &st ) == -1)
714 FILE_FillInfo( &st, info );
715 info->dwFileAttributes |= FILE_ATTRIBUTE_SYMLINK;
721 /***********************************************************************
722 * GetFileInformationByHandle (KERNEL32.@)
724 DWORD WINAPI GetFileInformationByHandle( HANDLE hFile,
725 BY_HANDLE_FILE_INFORMATION *info )
730 SERVER_START_REQ( get_file_info )
733 if ((ret = !wine_server_call_err( req )))
735 /* FIXME: which file types are supported ?
736 * Serial ports (FILE_TYPE_CHAR) are not,
737 * and MSDN also says that pipes are not supported.
738 * FILE_TYPE_REMOTE seems to be supported according to
739 * MSDN q234741.txt */
740 if ((reply->type == FILE_TYPE_DISK) || (reply->type == FILE_TYPE_REMOTE))
742 RtlSecondsSince1970ToTime( reply->write_time, &info->ftCreationTime );
743 RtlSecondsSince1970ToTime( reply->write_time, &info->ftLastWriteTime );
744 RtlSecondsSince1970ToTime( reply->access_time, &info->ftLastAccessTime );
745 info->dwFileAttributes = reply->attr;
746 info->dwVolumeSerialNumber = reply->serial;
747 info->nFileSizeHigh = reply->size_high;
748 info->nFileSizeLow = reply->size_low;
749 info->nNumberOfLinks = reply->links;
750 info->nFileIndexHigh = reply->index_high;
751 info->nFileIndexLow = reply->index_low;
755 SetLastError(ERROR_NOT_SUPPORTED);
765 /**************************************************************************
766 * GetFileAttributes (KERNEL.420)
768 DWORD WINAPI GetFileAttributes16( LPCSTR name )
770 return GetFileAttributesA( name );
774 /**************************************************************************
775 * GetFileAttributesA (KERNEL32.@)
777 DWORD WINAPI GetFileAttributesA( LPCSTR name )
779 DOS_FULL_NAME full_name;
780 BY_HANDLE_FILE_INFORMATION info;
784 SetLastError( ERROR_INVALID_PARAMETER );
787 if (!DOSFS_GetFullName( name, TRUE, &full_name) )
789 if (!FILE_Stat( full_name.long_name, &info )) return -1;
790 return info.dwFileAttributes;
794 /**************************************************************************
795 * GetFileAttributesW (KERNEL32.@)
797 DWORD WINAPI GetFileAttributesW( LPCWSTR name )
799 LPSTR nameA = HEAP_strdupWtoA( GetProcessHeap(), 0, name );
800 DWORD res = GetFileAttributesA( nameA );
801 HeapFree( GetProcessHeap(), 0, nameA );
806 /**************************************************************************
807 * SetFileAttributes (KERNEL.421)
809 BOOL16 WINAPI SetFileAttributes16( LPCSTR lpFileName, DWORD attributes )
811 return SetFileAttributesA( lpFileName, attributes );
815 /**************************************************************************
816 * SetFileAttributesA (KERNEL32.@)
818 BOOL WINAPI SetFileAttributesA(LPCSTR lpFileName, DWORD attributes)
821 DOS_FULL_NAME full_name;
823 if (!DOSFS_GetFullName( lpFileName, TRUE, &full_name ))
826 TRACE("(%s,%lx)\n",lpFileName,attributes);
827 if(stat(full_name.long_name,&buf)==-1)
832 if (attributes & FILE_ATTRIBUTE_READONLY)
834 if(S_ISDIR(buf.st_mode))
836 WARN("FILE_ATTRIBUTE_READONLY ignored for directory.\n");
838 buf.st_mode &= ~0222; /* octal!, clear write permission bits */
839 attributes &= ~FILE_ATTRIBUTE_READONLY;
843 /* add write permission */
844 buf.st_mode |= (0600 | ((buf.st_mode & 044) >> 1)) & (~FILE_umask);
846 if (attributes & FILE_ATTRIBUTE_DIRECTORY)
848 if (!S_ISDIR(buf.st_mode))
849 FIXME("SetFileAttributes expected the file '%s' to be a directory\n",
851 attributes &= ~FILE_ATTRIBUTE_DIRECTORY;
853 attributes &= ~(FILE_ATTRIBUTE_NORMAL|FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_HIDDEN|FILE_ATTRIBUTE_SYSTEM);
855 FIXME("(%s):%lx attribute(s) not implemented.\n", lpFileName,attributes);
856 if (-1==chmod(full_name.long_name,buf.st_mode))
858 if(GetDriveTypeA(lpFileName) == DRIVE_CDROM) {
859 SetLastError( ERROR_ACCESS_DENIED );
864 * FIXME: We don't return FALSE here because of differences between
865 * Linux and Windows privileges. Under Linux only the owner of
866 * the file is allowed to change file attributes. Under Windows,
867 * applications expect that if you can write to a file, you can also
868 * change its attributes (see GENERIC_WRITE). We could try to be
869 * clever here but that would break multi-user installations where
870 * users share read-only DLLs. This is because some installers like
871 * to change attributes of already installed DLLs.
873 FIXME("Couldn't set file attributes for existing file \"%s\".\n"
874 "Check permissions or set VFAT \"quiet\" mount flag\n", full_name.long_name);
880 /**************************************************************************
881 * SetFileAttributesW (KERNEL32.@)
883 BOOL WINAPI SetFileAttributesW(LPCWSTR lpFileName, DWORD attributes)
886 DWORD len = WideCharToMultiByte( CP_ACP, 0, lpFileName, -1, NULL, 0, NULL, NULL );
887 LPSTR afn = HeapAlloc( GetProcessHeap(), 0, len );
889 WideCharToMultiByte( CP_ACP, 0, lpFileName, -1, afn, len, NULL, NULL );
890 res = SetFileAttributesA( afn, attributes );
891 HeapFree( GetProcessHeap(), 0, afn );
896 /***********************************************************************
897 * GetFileSize (KERNEL32.@)
899 DWORD WINAPI GetFileSize( HANDLE hFile, LPDWORD filesizehigh )
901 BY_HANDLE_FILE_INFORMATION info;
902 if (!GetFileInformationByHandle( hFile, &info )) return -1;
903 if (filesizehigh) *filesizehigh = info.nFileSizeHigh;
904 return info.nFileSizeLow;
908 /***********************************************************************
909 * GetFileTime (KERNEL32.@)
911 BOOL WINAPI GetFileTime( HANDLE hFile, FILETIME *lpCreationTime,
912 FILETIME *lpLastAccessTime,
913 FILETIME *lpLastWriteTime )
915 BY_HANDLE_FILE_INFORMATION info;
916 if (!GetFileInformationByHandle( hFile, &info )) return FALSE;
917 if (lpCreationTime) *lpCreationTime = info.ftCreationTime;
918 if (lpLastAccessTime) *lpLastAccessTime = info.ftLastAccessTime;
919 if (lpLastWriteTime) *lpLastWriteTime = info.ftLastWriteTime;
923 /***********************************************************************
924 * CompareFileTime (KERNEL32.@)
926 INT WINAPI CompareFileTime( LPFILETIME x, LPFILETIME y )
928 if (!x || !y) return -1;
930 if (x->dwHighDateTime > y->dwHighDateTime)
932 if (x->dwHighDateTime < y->dwHighDateTime)
934 if (x->dwLowDateTime > y->dwLowDateTime)
936 if (x->dwLowDateTime < y->dwLowDateTime)
941 /***********************************************************************
942 * FILE_GetTempFileName : utility for GetTempFileName
944 static UINT FILE_GetTempFileName( LPCSTR path, LPCSTR prefix, UINT unique,
945 LPSTR buffer, BOOL isWin16 )
947 static UINT unique_temp;
948 DOS_FULL_NAME full_name;
953 if ( !path || !prefix || !buffer ) return 0;
955 if (!unique_temp) unique_temp = time(NULL) & 0xffff;
956 num = unique ? (unique & 0xffff) : (unique_temp++ & 0xffff);
958 strcpy( buffer, path );
959 p = buffer + strlen(buffer);
961 /* add a \, if there isn't one and path is more than just the drive letter ... */
962 if ( !((strlen(buffer) == 2) && (buffer[1] == ':'))
963 && ((p == buffer) || (p[-1] != '\\'))) *p++ = '\\';
965 if (isWin16) *p++ = '~';
966 for (i = 3; (i > 0) && (*prefix); i--) *p++ = *prefix++;
967 sprintf( p, "%04x.tmp", num );
969 /* Now try to create it */
975 HANDLE handle = CreateFileA( buffer, GENERIC_WRITE, 0, NULL,
976 CREATE_NEW, FILE_ATTRIBUTE_NORMAL, 0 );
977 if (handle != INVALID_HANDLE_VALUE)
978 { /* We created it */
979 TRACE("created %s\n",
981 CloseHandle( handle );
984 if (GetLastError() != ERROR_FILE_EXISTS)
985 break; /* No need to go on */
987 sprintf( p, "%04x.tmp", num );
988 } while (num != (unique & 0xffff));
991 /* Get the full path name */
993 if (DOSFS_GetFullName( buffer, FALSE, &full_name ))
995 /* Check if we have write access in the directory */
996 if ((p = strrchr( full_name.long_name, '/' ))) *p = '\0';
997 if (access( full_name.long_name, W_OK ) == -1)
998 WARN("returns '%s', which doesn't seem to be writeable.\n",
1001 TRACE("returning %s\n", buffer );
1002 return unique ? unique : num;
1006 /***********************************************************************
1007 * GetTempFileNameA (KERNEL32.@)
1009 UINT WINAPI GetTempFileNameA( LPCSTR path, LPCSTR prefix, UINT unique,
1012 return FILE_GetTempFileName(path, prefix, unique, buffer, FALSE);
1015 /***********************************************************************
1016 * GetTempFileNameW (KERNEL32.@)
1018 UINT WINAPI GetTempFileNameW( LPCWSTR path, LPCWSTR prefix, UINT unique,
1021 LPSTR patha,prefixa;
1025 if (!path) return 0;
1026 patha = HEAP_strdupWtoA( GetProcessHeap(), 0, path );
1027 prefixa = HEAP_strdupWtoA( GetProcessHeap(), 0, prefix );
1028 ret = FILE_GetTempFileName( patha, prefixa, unique, buffera, FALSE );
1029 MultiByteToWideChar( CP_ACP, 0, buffera, -1, buffer, MAX_PATH );
1030 HeapFree( GetProcessHeap(), 0, patha );
1031 HeapFree( GetProcessHeap(), 0, prefixa );
1036 /***********************************************************************
1037 * GetTempFileName (KERNEL.97)
1039 UINT16 WINAPI GetTempFileName16( BYTE drive, LPCSTR prefix, UINT16 unique,
1044 if (!(drive & ~TF_FORCEDRIVE)) /* drive 0 means current default drive */
1045 drive |= DRIVE_GetCurrentDrive() + 'A';
1047 if ((drive & TF_FORCEDRIVE) &&
1048 !DRIVE_IsValid( toupper(drive & ~TF_FORCEDRIVE) - 'A' ))
1050 drive &= ~TF_FORCEDRIVE;
1051 WARN("invalid drive %d specified\n", drive );
1054 if (drive & TF_FORCEDRIVE)
1055 sprintf(temppath,"%c:", drive & ~TF_FORCEDRIVE );
1057 GetTempPathA( 132, temppath );
1058 return (UINT16)FILE_GetTempFileName( temppath, prefix, unique, buffer, TRUE );
1061 /***********************************************************************
1064 * Implementation of OpenFile16() and OpenFile32().
1066 static HFILE FILE_DoOpenFile( LPCSTR name, OFSTRUCT *ofs, UINT mode,
1072 WORD filedatetime[2];
1073 DOS_FULL_NAME full_name;
1074 DWORD access, sharing;
1077 if (!ofs) return HFILE_ERROR;
1079 TRACE("%s %s %s %s%s%s%s%s%s%s%s%s\n",name,
1080 ((mode & 0x3 )==OF_READ)?"OF_READ":
1081 ((mode & 0x3 )==OF_WRITE)?"OF_WRITE":
1082 ((mode & 0x3 )==OF_READWRITE)?"OF_READWRITE":"unknown",
1083 ((mode & 0x70 )==OF_SHARE_COMPAT)?"OF_SHARE_COMPAT":
1084 ((mode & 0x70 )==OF_SHARE_DENY_NONE)?"OF_SHARE_DENY_NONE":
1085 ((mode & 0x70 )==OF_SHARE_DENY_READ)?"OF_SHARE_DENY_READ":
1086 ((mode & 0x70 )==OF_SHARE_DENY_WRITE)?"OF_SHARE_DENY_WRITE":
1087 ((mode & 0x70 )==OF_SHARE_EXCLUSIVE)?"OF_SHARE_EXCLUSIVE":"unknown",
1088 ((mode & OF_PARSE )==OF_PARSE)?"OF_PARSE ":"",
1089 ((mode & OF_DELETE )==OF_DELETE)?"OF_DELETE ":"",
1090 ((mode & OF_VERIFY )==OF_VERIFY)?"OF_VERIFY ":"",
1091 ((mode & OF_SEARCH )==OF_SEARCH)?"OF_SEARCH ":"",
1092 ((mode & OF_CANCEL )==OF_CANCEL)?"OF_CANCEL ":"",
1093 ((mode & OF_CREATE )==OF_CREATE)?"OF_CREATE ":"",
1094 ((mode & OF_PROMPT )==OF_PROMPT)?"OF_PROMPT ":"",
1095 ((mode & OF_EXIST )==OF_EXIST)?"OF_EXIST ":"",
1096 ((mode & OF_REOPEN )==OF_REOPEN)?"OF_REOPEN ":""
1100 ofs->cBytes = sizeof(OFSTRUCT);
1102 if (mode & OF_REOPEN) name = ofs->szPathName;
1105 ERR("called with `name' set to NULL ! Please debug.\n");
1109 TRACE("%s %04x\n", name, mode );
1111 /* the watcom 10.6 IDE relies on a valid path returned in ofs->szPathName
1112 Are there any cases where getting the path here is wrong?
1113 Uwe Bonnes 1997 Apr 2 */
1114 if (!GetFullPathNameA( name, sizeof(ofs->szPathName),
1115 ofs->szPathName, NULL )) goto error;
1116 FILE_ConvertOFMode( mode, &access, &sharing );
1118 /* OF_PARSE simply fills the structure */
1120 if (mode & OF_PARSE)
1122 ofs->fFixedDisk = (GetDriveType16( ofs->szPathName[0]-'A' )
1123 != DRIVE_REMOVABLE);
1124 TRACE("(%s): OF_PARSE, res = '%s'\n",
1125 name, ofs->szPathName );
1129 /* OF_CREATE is completely different from all other options, so
1132 if (mode & OF_CREATE)
1134 if ((handle = CreateFileA( name, GENERIC_READ | GENERIC_WRITE,
1135 sharing, NULL, CREATE_ALWAYS,
1136 FILE_ATTRIBUTE_NORMAL, 0 ))== INVALID_HANDLE_VALUE)
1141 /* If OF_SEARCH is set, ignore the given path */
1143 if ((mode & OF_SEARCH) && !(mode & OF_REOPEN))
1145 /* First try the file name as is */
1146 if (DOSFS_GetFullName( name, TRUE, &full_name )) goto found;
1147 /* Now remove the path */
1148 if (name[0] && (name[1] == ':')) name += 2;
1149 if ((p = strrchr( name, '\\' ))) name = p + 1;
1150 if ((p = strrchr( name, '/' ))) name = p + 1;
1151 if (!name[0]) goto not_found;
1154 /* Now look for the file */
1156 if (!DIR_SearchPath( NULL, name, NULL, &full_name, win32 )) goto not_found;
1159 TRACE("found %s = %s\n",
1160 full_name.long_name, full_name.short_name );
1161 lstrcpynA( ofs->szPathName, full_name.short_name,
1162 sizeof(ofs->szPathName) );
1164 if (mode & OF_SHARE_EXCLUSIVE)
1165 /* Some InstallShield version uses OF_SHARE_EXCLUSIVE
1166 on the file <tempdir>/_ins0432._mp to determine how
1167 far installation has proceeded.
1168 _ins0432._mp is an executable and while running the
1169 application expects the open with OF_SHARE_ to fail*/
1171 As our loader closes the files after loading the executable,
1172 we can't find the running executable with FILE_InUse.
1173 The loader should keep the file open, as Windows does that, too.
1176 char *last = strrchr(full_name.long_name,'/');
1178 last = full_name.long_name - 1;
1179 if (GetModuleHandle16(last+1))
1181 TRACE("Denying shared open for %s\n",full_name.long_name);
1186 if (mode & OF_DELETE)
1188 if (unlink( full_name.long_name ) == -1) goto not_found;
1189 TRACE("(%s): OF_DELETE return = OK\n", name);
1193 handle = FILE_CreateFile( full_name.long_name, access, sharing,
1194 NULL, OPEN_EXISTING, 0, 0,
1195 DRIVE_GetFlags(full_name.drive) & DRIVE_FAIL_READ_ONLY,
1196 GetDriveTypeA( full_name.short_name ) );
1197 if (!handle) goto not_found;
1199 GetFileTime( handle, NULL, NULL, &filetime );
1200 FileTimeToDosDateTime( &filetime, &filedatetime[0], &filedatetime[1] );
1201 if ((mode & OF_VERIFY) && (mode & OF_REOPEN))
1203 if (memcmp( ofs->reserved, filedatetime, sizeof(ofs->reserved) ))
1205 CloseHandle( handle );
1206 WARN("(%s): OF_VERIFY failed\n", name );
1207 /* FIXME: what error here? */
1208 SetLastError( ERROR_FILE_NOT_FOUND );
1212 memcpy( ofs->reserved, filedatetime, sizeof(ofs->reserved) );
1214 success: /* We get here if the open was successful */
1215 TRACE("(%s): OK, return = %x\n", name, handle );
1218 hFileRet = (HFILE)handle;
1219 if (mode & OF_EXIST) /* Return the handle, but close it first */
1220 CloseHandle( handle );
1224 hFileRet = Win32HandleToDosFileHandle( handle );
1225 if (hFileRet == HFILE_ERROR16) goto error;
1226 if (mode & OF_EXIST) /* Return the handle, but close it first */
1227 _lclose16( hFileRet );
1231 not_found: /* We get here if the file does not exist */
1232 WARN("'%s' not found or sharing violation\n", name );
1233 SetLastError( ERROR_FILE_NOT_FOUND );
1236 error: /* We get here if there was an error opening the file */
1237 ofs->nErrCode = GetLastError();
1238 WARN("(%s): return = HFILE_ERROR error= %d\n",
1239 name,ofs->nErrCode );
1244 /***********************************************************************
1245 * OpenFile (KERNEL.74)
1246 * OpenFileEx (KERNEL.360)
1248 HFILE16 WINAPI OpenFile16( LPCSTR name, OFSTRUCT *ofs, UINT16 mode )
1250 return FILE_DoOpenFile( name, ofs, mode, FALSE );
1254 /***********************************************************************
1255 * OpenFile (KERNEL32.@)
1257 HFILE WINAPI OpenFile( LPCSTR name, OFSTRUCT *ofs, UINT mode )
1259 return FILE_DoOpenFile( name, ofs, mode, TRUE );
1263 /***********************************************************************
1264 * FILE_InitProcessDosHandles
1266 * Allocates the default DOS handles for a process. Called either by
1267 * Win32HandleToDosFileHandle below or by the DOSVM stuff.
1269 static void FILE_InitProcessDosHandles( void )
1271 HANDLE cp = GetCurrentProcess();
1272 DuplicateHandle(cp, GetStdHandle(STD_INPUT_HANDLE), cp, &dos_handles[0],
1273 0, TRUE, DUPLICATE_SAME_ACCESS);
1274 DuplicateHandle(cp, GetStdHandle(STD_OUTPUT_HANDLE), cp, &dos_handles[1],
1275 0, TRUE, DUPLICATE_SAME_ACCESS);
1276 DuplicateHandle(cp, GetStdHandle(STD_ERROR_HANDLE), cp, &dos_handles[2],
1277 0, TRUE, DUPLICATE_SAME_ACCESS);
1278 DuplicateHandle(cp, GetStdHandle(STD_ERROR_HANDLE), cp, &dos_handles[3],
1279 0, TRUE, DUPLICATE_SAME_ACCESS);
1280 DuplicateHandle(cp, GetStdHandle(STD_ERROR_HANDLE), cp, &dos_handles[4],
1281 0, TRUE, DUPLICATE_SAME_ACCESS);
1284 /***********************************************************************
1285 * Win32HandleToDosFileHandle (KERNEL32.21)
1287 * Allocate a DOS handle for a Win32 handle. The Win32 handle is no
1288 * longer valid after this function (even on failure).
1290 * Note: this is not exactly right, since on Win95 the Win32 handles
1291 * are on top of DOS handles and we do it the other way
1292 * around. Should be good enough though.
1294 HFILE WINAPI Win32HandleToDosFileHandle( HANDLE handle )
1298 if (!handle || (handle == INVALID_HANDLE_VALUE))
1301 for (i = 5; i < DOS_TABLE_SIZE; i++)
1302 if (!dos_handles[i])
1304 dos_handles[i] = handle;
1305 TRACE("Got %d for h32 %d\n", i, handle );
1308 CloseHandle( handle );
1309 SetLastError( ERROR_TOO_MANY_OPEN_FILES );
1314 /***********************************************************************
1315 * DosFileHandleToWin32Handle (KERNEL32.20)
1317 * Return the Win32 handle for a DOS handle.
1319 * Note: this is not exactly right, since on Win95 the Win32 handles
1320 * are on top of DOS handles and we do it the other way
1321 * around. Should be good enough though.
1323 HANDLE WINAPI DosFileHandleToWin32Handle( HFILE handle )
1325 HFILE16 hfile = (HFILE16)handle;
1326 if (hfile < 5 && !dos_handles[hfile]) FILE_InitProcessDosHandles();
1327 if ((hfile >= DOS_TABLE_SIZE) || !dos_handles[hfile])
1329 SetLastError( ERROR_INVALID_HANDLE );
1330 return INVALID_HANDLE_VALUE;
1332 return dos_handles[hfile];
1336 /***********************************************************************
1337 * DisposeLZ32Handle (KERNEL32.22)
1339 * Note: this is not entirely correct, we should only close the
1340 * 32-bit handle and not the 16-bit one, but we cannot do
1341 * this because of the way our DOS handles are implemented.
1342 * It shouldn't break anything though.
1344 void WINAPI DisposeLZ32Handle( HANDLE handle )
1348 if (!handle || (handle == INVALID_HANDLE_VALUE)) return;
1350 for (i = 5; i < DOS_TABLE_SIZE; i++)
1351 if (dos_handles[i] == handle)
1354 CloseHandle( handle );
1360 /***********************************************************************
1363 * dup2() function for DOS handles.
1365 HFILE16 FILE_Dup2( HFILE16 hFile1, HFILE16 hFile2 )
1369 if (hFile1 < 5 && !dos_handles[hFile1]) FILE_InitProcessDosHandles();
1371 if ((hFile1 >= DOS_TABLE_SIZE) || (hFile2 >= DOS_TABLE_SIZE) || !dos_handles[hFile1])
1373 SetLastError( ERROR_INVALID_HANDLE );
1374 return HFILE_ERROR16;
1376 if (!DuplicateHandle( GetCurrentProcess(), dos_handles[hFile1],
1377 GetCurrentProcess(), &new_handle,
1378 0, FALSE, DUPLICATE_SAME_ACCESS ))
1379 return HFILE_ERROR16;
1380 if (dos_handles[hFile2]) CloseHandle( dos_handles[hFile2] );
1381 dos_handles[hFile2] = new_handle;
1386 /***********************************************************************
1387 * _lclose (KERNEL.81)
1389 HFILE16 WINAPI _lclose16( HFILE16 hFile )
1391 if ((hFile >= DOS_TABLE_SIZE) || !dos_handles[hFile])
1393 SetLastError( ERROR_INVALID_HANDLE );
1394 return HFILE_ERROR16;
1396 TRACE("%d (handle32=%d)\n", hFile, dos_handles[hFile] );
1397 CloseHandle( dos_handles[hFile] );
1398 dos_handles[hFile] = 0;
1403 /***********************************************************************
1404 * _lclose (KERNEL32.@)
1406 HFILE WINAPI _lclose( HFILE hFile )
1408 TRACE("handle %d\n", hFile );
1409 return CloseHandle( (HANDLE)hFile ) ? 0 : HFILE_ERROR;
1412 /***********************************************************************
1413 * GetOverlappedResult (KERNEL32.@)
1415 * Check the result of an Asynchronous data transfer from a file.
1421 * If successful (and relevant) lpTransferred will hold the number of
1422 * bytes transferred during the async operation.
1426 * Currently only works for WaitCommEvent, ReadFile, WriteFile
1427 * with communications ports.
1430 BOOL WINAPI GetOverlappedResult(
1431 HANDLE hFile, /* [in] handle of file to check on */
1432 LPOVERLAPPED lpOverlapped, /* [in/out] pointer to overlapped */
1433 LPDWORD lpTransferred, /* [in/out] number of bytes transferred */
1434 BOOL bWait /* [in] wait for the transfer to complete ? */
1438 TRACE("(%d %p %p %x)\n", hFile, lpOverlapped, lpTransferred, bWait);
1440 if(lpOverlapped==NULL)
1442 ERR("lpOverlapped was null\n");
1445 if(!lpOverlapped->hEvent)
1447 ERR("lpOverlapped->hEvent was null\n");
1452 TRACE("waiting on %p\n",lpOverlapped);
1453 r = WaitForSingleObjectEx(lpOverlapped->hEvent, bWait?INFINITE:0, TRUE);
1454 TRACE("wait on %p returned %ld\n",lpOverlapped,r);
1455 } while (r==STATUS_USER_APC);
1458 *lpTransferred = lpOverlapped->InternalHigh;
1460 SetLastError ( lpOverlapped->Internal == STATUS_PENDING ?
1461 ERROR_IO_INCOMPLETE : RtlNtStatusToDosError ( lpOverlapped->Internal ) );
1463 return (r==WAIT_OBJECT_0);
1466 /***********************************************************************
1467 * CancelIo (KERNEL32.@)
1469 BOOL WINAPI CancelIo(HANDLE handle)
1471 async_private *ovp,*t;
1473 TRACE("handle = %x\n",handle);
1475 for (ovp = NtCurrentTeb()->pending_list; ovp; ovp = t)
1478 if ( ovp->handle == handle )
1479 cancel_async ( ovp );
1481 WaitForMultipleObjectsEx(0,NULL,FALSE,1,TRUE);
1485 /***********************************************************************
1486 * FILE_AsyncReadService (INTERNAL)
1488 * This function is called while the client is waiting on the
1489 * server, so we can't make any server calls here.
1491 static void FILE_AsyncReadService(async_private *ovp)
1493 async_fileio *fileio = (async_fileio*) ovp;
1494 LPOVERLAPPED lpOverlapped = fileio->lpOverlapped;
1496 int already = lpOverlapped->InternalHigh;
1498 TRACE("%p %p\n", lpOverlapped, fileio->buffer );
1500 /* check to see if the data is ready (non-blocking) */
1502 if ( fileio->fd_type == FD_TYPE_SOCKET )
1503 result = read (ovp->fd, &fileio->buffer[already], fileio->count - already);
1506 result = pread (ovp->fd, &fileio->buffer[already], fileio->count - already,
1507 OVERLAPPED_OFFSET (lpOverlapped) + already);
1508 if ((result < 0) && (errno == ESPIPE))
1509 result = read (ovp->fd, &fileio->buffer[already], fileio->count - already);
1512 if ( (result<0) && ((errno == EAGAIN) || (errno == EINTR)))
1514 TRACE("Deferred read %d\n",errno);
1519 /* check to see if the transfer is complete */
1522 r = FILE_GetNtStatus ();
1526 lpOverlapped->InternalHigh += result;
1527 TRACE("read %d more bytes %ld/%d so far\n",result,lpOverlapped->InternalHigh,fileio->count);
1529 if(lpOverlapped->InternalHigh >= fileio->count || fileio->fd_type == FD_TYPE_SOCKET )
1535 lpOverlapped->Internal = r;
1538 /***********************************************************************
1539 * FILE_ReadFileEx (INTERNAL)
1541 static BOOL FILE_ReadFileEx(HANDLE hFile, LPVOID buffer, DWORD bytesToRead,
1542 LPOVERLAPPED overlapped,
1543 LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine,
1551 TRACE("file %d to buf %p num %ld %p func %p\n",
1552 hFile, buffer, bytesToRead, overlapped, lpCompletionRoutine);
1554 /* check that there is an overlapped struct */
1555 if (overlapped==NULL)
1557 SetLastError(ERROR_INVALID_PARAMETER);
1561 fd = FILE_GetUnixHandleType ( hFile, GENERIC_READ, &type, &flags);
1564 WARN ( "Couldn't get FD\n" );
1568 ovp = (async_fileio*) HeapAlloc(GetProcessHeap(), 0, sizeof (async_fileio));
1571 TRACE("HeapAlloc Failed\n");
1572 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1576 ovp->async.ops = ( lpCompletionRoutine ? &fileio_async_ops : &fileio_nocomp_async_ops );
1577 ovp->async.handle = hFile;
1579 ovp->async.type = ASYNC_TYPE_READ;
1580 ovp->async.func = FILE_AsyncReadService;
1581 ovp->async.event = hEvent;
1582 ovp->lpOverlapped = overlapped;
1583 ovp->count = bytesToRead;
1584 ovp->completion_func = lpCompletionRoutine;
1585 ovp->buffer = buffer;
1586 ovp->fd_type = type;
1588 return !register_new_async (&ovp->async);
1596 /***********************************************************************
1597 * ReadFileEx (KERNEL32.@)
1599 BOOL WINAPI ReadFileEx(HANDLE hFile, LPVOID buffer, DWORD bytesToRead,
1600 LPOVERLAPPED overlapped,
1601 LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine)
1603 overlapped->InternalHigh = 0;
1604 return FILE_ReadFileEx(hFile,buffer,bytesToRead,overlapped,lpCompletionRoutine, INVALID_HANDLE_VALUE);
1607 static BOOL FILE_TimeoutRead(HANDLE hFile, LPVOID buffer, DWORD bytesToRead, LPDWORD bytesRead)
1612 TRACE("%d %p %ld %p\n", hFile, buffer, bytesToRead, bytesRead );
1614 ZeroMemory(&ov, sizeof (OVERLAPPED));
1615 if(STATUS_SUCCESS==NtCreateEvent(&ov.hEvent, SYNCHRONIZE, NULL, 0, 0))
1617 if(FILE_ReadFileEx(hFile, buffer, bytesToRead, &ov, NULL, ov.hEvent))
1619 r = GetOverlappedResult(hFile, &ov, bytesRead, TRUE);
1622 CloseHandle(ov.hEvent);
1626 /***********************************************************************
1627 * ReadFile (KERNEL32.@)
1629 BOOL WINAPI ReadFile( HANDLE hFile, LPVOID buffer, DWORD bytesToRead,
1630 LPDWORD bytesRead, LPOVERLAPPED overlapped )
1632 int unix_handle, result, flags;
1635 TRACE("%d %p %ld %p %p\n", hFile, buffer, bytesToRead,
1636 bytesRead, overlapped );
1638 if (bytesRead) *bytesRead = 0; /* Do this before anything else */
1639 if (!bytesToRead) return TRUE;
1641 unix_handle = FILE_GetUnixHandleType( hFile, GENERIC_READ, &type, &flags );
1643 if (flags & FD_FLAG_OVERLAPPED)
1645 if (unix_handle == -1) return FALSE;
1646 if ( (overlapped==NULL) || NtResetEvent( overlapped->hEvent, NULL ) )
1648 TRACE("Overlapped not specified or invalid event flag\n");
1650 SetLastError(ERROR_INVALID_PARAMETER);
1655 overlapped->InternalHigh = 0;
1657 if(!FILE_ReadFileEx(hFile, buffer, bytesToRead, overlapped, NULL, overlapped->hEvent))
1660 if ( !GetOverlappedResult (hFile, overlapped, bytesRead, FALSE) )
1662 if ( GetLastError() == ERROR_IO_INCOMPLETE )
1663 SetLastError ( ERROR_IO_PENDING );
1669 if (flags & FD_FLAG_TIMEOUT)
1672 return FILE_TimeoutRead(hFile, buffer, bytesToRead, bytesRead);
1677 return SMB_ReadFile(hFile, buffer, bytesToRead, bytesRead, NULL);
1679 case FD_TYPE_CONSOLE:
1680 return FILE_ReadConsole(hFile, buffer, bytesToRead, bytesRead, NULL);
1682 case FD_TYPE_DEFAULT:
1683 /* normal unix files */
1684 if (unix_handle == -1) return FALSE;
1687 DWORD highOffset = overlapped->OffsetHigh;
1688 if ( (INVALID_SET_FILE_POINTER == SetFilePointer(hFile, overlapped->Offset,
1689 &highOffset, FILE_BEGIN)) &&
1690 (GetLastError() != NO_ERROR) )
1699 if (unix_handle == -1)
1704 SetLastError(ERROR_INVALID_PARAMETER);
1710 /* code for synchronous reads */
1711 while ((result = read( unix_handle, buffer, bytesToRead )) == -1)
1713 if ((errno == EAGAIN) || (errno == EINTR)) continue;
1714 if ((errno == EFAULT) && !IsBadWritePtr( buffer, bytesToRead )) continue;
1718 close( unix_handle );
1719 if (result == -1) return FALSE;
1720 if (bytesRead) *bytesRead = result;
1725 /***********************************************************************
1726 * FILE_AsyncWriteService (INTERNAL)
1728 * This function is called while the client is waiting on the
1729 * server, so we can't make any server calls here.
1731 static void FILE_AsyncWriteService(struct async_private *ovp)
1733 async_fileio *fileio = (async_fileio *) ovp;
1734 LPOVERLAPPED lpOverlapped = fileio->lpOverlapped;
1736 int already = lpOverlapped->InternalHigh;
1738 TRACE("(%p %p)\n",lpOverlapped,fileio->buffer);
1740 /* write some data (non-blocking) */
1742 if ( fileio->fd_type == FD_TYPE_SOCKET )
1743 result = write(ovp->fd, &fileio->buffer[already], fileio->count - already);
1746 result = pwrite(ovp->fd, &fileio->buffer[already], fileio->count - already,
1747 OVERLAPPED_OFFSET (lpOverlapped) + already);
1748 if ((result < 0) && (errno == ESPIPE))
1749 result = write(ovp->fd, &fileio->buffer[already], fileio->count - already);
1752 if ( (result<0) && ((errno == EAGAIN) || (errno == EINTR)))
1758 /* check to see if the transfer is complete */
1761 r = FILE_GetNtStatus ();
1765 lpOverlapped->InternalHigh += result;
1767 TRACE("wrote %d more bytes %ld/%d so far\n",result,lpOverlapped->InternalHigh,fileio->count);
1769 if(lpOverlapped->InternalHigh < fileio->count)
1775 lpOverlapped->Internal = r;
1778 /***********************************************************************
1781 static BOOL FILE_WriteFileEx(HANDLE hFile, LPCVOID buffer, DWORD bytesToWrite,
1782 LPOVERLAPPED overlapped,
1783 LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine,
1791 TRACE("file %d to buf %p num %ld %p func %p handle %d\n",
1792 hFile, buffer, bytesToWrite, overlapped, lpCompletionRoutine, hEvent);
1794 if (overlapped == NULL)
1796 SetLastError(ERROR_INVALID_PARAMETER);
1800 fd = FILE_GetUnixHandleType ( hFile, GENERIC_WRITE, &type, &flags );
1803 TRACE( "Couldn't get FD\n" );
1807 ovp = (async_fileio*) HeapAlloc(GetProcessHeap(), 0, sizeof (async_fileio));
1810 TRACE("HeapAlloc Failed\n");
1811 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1815 ovp->async.ops = ( lpCompletionRoutine ? &fileio_async_ops : &fileio_nocomp_async_ops );
1816 ovp->async.handle = hFile;
1818 ovp->async.type = ASYNC_TYPE_WRITE;
1819 ovp->async.func = FILE_AsyncWriteService;
1820 ovp->lpOverlapped = overlapped;
1821 ovp->async.event = hEvent;
1822 ovp->buffer = (LPVOID) buffer;
1823 ovp->count = bytesToWrite;
1824 ovp->completion_func = lpCompletionRoutine;
1825 ovp->fd_type = type;
1827 return !register_new_async (&ovp->async);
1834 /***********************************************************************
1835 * WriteFileEx (KERNEL32.@)
1837 BOOL WINAPI WriteFileEx(HANDLE hFile, LPCVOID buffer, DWORD bytesToWrite,
1838 LPOVERLAPPED overlapped,
1839 LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine)
1841 overlapped->InternalHigh = 0;
1843 return FILE_WriteFileEx(hFile, buffer, bytesToWrite, overlapped, lpCompletionRoutine, INVALID_HANDLE_VALUE);
1846 /***********************************************************************
1847 * WriteFile (KERNEL32.@)
1849 BOOL WINAPI WriteFile( HANDLE hFile, LPCVOID buffer, DWORD bytesToWrite,
1850 LPDWORD bytesWritten, LPOVERLAPPED overlapped )
1852 int unix_handle, result, flags;
1855 TRACE("%d %p %ld %p %p\n", hFile, buffer, bytesToWrite,
1856 bytesWritten, overlapped );
1858 if (bytesWritten) *bytesWritten = 0; /* Do this before anything else */
1859 if (!bytesToWrite) return TRUE;
1861 unix_handle = FILE_GetUnixHandleType( hFile, GENERIC_WRITE, &type, &flags );
1863 if (flags & FD_FLAG_OVERLAPPED)
1865 if (unix_handle == -1) return FALSE;
1866 if ( (overlapped==NULL) || NtResetEvent( overlapped->hEvent, NULL ) )
1868 TRACE("Overlapped not specified or invalid event flag\n");
1870 SetLastError(ERROR_INVALID_PARAMETER);
1875 overlapped->InternalHigh = 0;
1877 if(!FILE_WriteFileEx(hFile, buffer, bytesToWrite, overlapped, NULL, overlapped->hEvent))
1880 if ( !GetOverlappedResult (hFile, overlapped, bytesWritten, FALSE) )
1882 if ( GetLastError() == ERROR_IO_INCOMPLETE )
1883 SetLastError ( ERROR_IO_PENDING );
1892 case FD_TYPE_CONSOLE:
1893 TRACE("%d %s %ld %p %p\n", hFile, debugstr_an(buffer, bytesToWrite), bytesToWrite,
1894 bytesWritten, overlapped );
1895 return FILE_WriteConsole(hFile, buffer, bytesToWrite, bytesWritten, NULL);
1897 case FD_TYPE_DEFAULT:
1898 if (unix_handle == -1) return FALSE;
1902 DWORD highOffset = overlapped->OffsetHigh;
1903 if ( (INVALID_SET_FILE_POINTER == SetFilePointer(hFile, overlapped->Offset,
1904 &highOffset, FILE_BEGIN)) &&
1905 (GetLastError() != NO_ERROR) )
1914 if (unix_handle == -1)
1919 SetLastError(ERROR_INVALID_PARAMETER);
1925 /* synchronous file write */
1926 while ((result = write( unix_handle, buffer, bytesToWrite )) == -1)
1928 if ((errno == EAGAIN) || (errno == EINTR)) continue;
1929 if ((errno == EFAULT) && !IsBadReadPtr( buffer, bytesToWrite )) continue;
1930 if (errno == ENOSPC)
1931 SetLastError( ERROR_DISK_FULL );
1936 close( unix_handle );
1937 if (result == -1) return FALSE;
1938 if (bytesWritten) *bytesWritten = result;
1943 /***********************************************************************
1944 * _hread (KERNEL.349)
1946 LONG WINAPI WIN16_hread( HFILE16 hFile, SEGPTR buffer, LONG count )
1950 TRACE("%d %08lx %ld\n",
1951 hFile, (DWORD)buffer, count );
1953 /* Some programs pass a count larger than the allocated buffer */
1954 maxlen = GetSelectorLimit16( SELECTOROF(buffer) ) - OFFSETOF(buffer) + 1;
1955 if (count > maxlen) count = maxlen;
1956 return _lread((HFILE)DosFileHandleToWin32Handle(hFile), MapSL(buffer), count );
1960 /***********************************************************************
1961 * _lread (KERNEL.82)
1963 UINT16 WINAPI WIN16_lread( HFILE16 hFile, SEGPTR buffer, UINT16 count )
1965 return (UINT16)WIN16_hread( hFile, buffer, (LONG)count );
1969 /***********************************************************************
1970 * _lread (KERNEL32.@)
1972 UINT WINAPI _lread( HFILE handle, LPVOID buffer, UINT count )
1975 if (!ReadFile( (HANDLE)handle, buffer, count, &result, NULL )) return -1;
1980 /***********************************************************************
1981 * _lread16 (KERNEL.82)
1983 UINT16 WINAPI _lread16( HFILE16 hFile, LPVOID buffer, UINT16 count )
1985 return (UINT16)_lread((HFILE)DosFileHandleToWin32Handle(hFile), buffer, (LONG)count );
1989 /***********************************************************************
1990 * _lcreat (KERNEL.83)
1992 HFILE16 WINAPI _lcreat16( LPCSTR path, INT16 attr )
1994 return Win32HandleToDosFileHandle( (HANDLE)_lcreat( path, attr ) );
1998 /***********************************************************************
1999 * _lcreat (KERNEL32.@)
2001 HFILE WINAPI _lcreat( LPCSTR path, INT attr )
2003 /* Mask off all flags not explicitly allowed by the doc */
2004 attr &= FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM;
2005 TRACE("%s %02x\n", path, attr );
2006 return (HFILE)CreateFileA( path, GENERIC_READ | GENERIC_WRITE,
2007 FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
2008 CREATE_ALWAYS, attr, 0 );
2012 /***********************************************************************
2013 * SetFilePointer (KERNEL32.@)
2015 DWORD WINAPI SetFilePointer( HANDLE hFile, LONG distance, LONG *highword,
2018 DWORD ret = INVALID_SET_FILE_POINTER;
2020 TRACE("handle %d offset %ld high %ld origin %ld\n",
2021 hFile, distance, highword?*highword:0, method );
2023 SERVER_START_REQ( set_file_pointer )
2025 req->handle = hFile;
2026 req->low = distance;
2027 req->high = highword ? *highword : (distance >= 0) ? 0 : -1;
2028 /* FIXME: assumes 1:1 mapping between Windows and Unix seek constants */
2029 req->whence = method;
2031 if (!wine_server_call_err( req ))
2033 ret = reply->new_low;
2034 if (highword) *highword = reply->new_high;
2042 /***********************************************************************
2043 * _llseek (KERNEL.84)
2046 * Seeking before the start of the file should be allowed for _llseek16,
2047 * but cause subsequent I/O operations to fail (cf. interrupt list)
2050 LONG WINAPI _llseek16( HFILE16 hFile, LONG lOffset, INT16 nOrigin )
2052 return SetFilePointer( DosFileHandleToWin32Handle(hFile), lOffset, NULL, nOrigin );
2056 /***********************************************************************
2057 * _llseek (KERNEL32.@)
2059 LONG WINAPI _llseek( HFILE hFile, LONG lOffset, INT nOrigin )
2061 return SetFilePointer( (HANDLE)hFile, lOffset, NULL, nOrigin );
2065 /***********************************************************************
2066 * _lopen (KERNEL.85)
2068 HFILE16 WINAPI _lopen16( LPCSTR path, INT16 mode )
2070 return Win32HandleToDosFileHandle( (HANDLE)_lopen( path, mode ) );
2074 /***********************************************************************
2075 * _lopen (KERNEL32.@)
2077 HFILE WINAPI _lopen( LPCSTR path, INT mode )
2079 DWORD access, sharing;
2081 TRACE("('%s',%04x)\n", path, mode );
2082 FILE_ConvertOFMode( mode, &access, &sharing );
2083 return (HFILE)CreateFileA( path, access, sharing, NULL, OPEN_EXISTING, 0, 0 );
2087 /***********************************************************************
2088 * _lwrite (KERNEL.86)
2090 UINT16 WINAPI _lwrite16( HFILE16 hFile, LPCSTR buffer, UINT16 count )
2092 return (UINT16)_hwrite( (HFILE)DosFileHandleToWin32Handle(hFile), buffer, (LONG)count );
2095 /***********************************************************************
2096 * _lwrite (KERNEL32.@)
2098 UINT WINAPI _lwrite( HFILE hFile, LPCSTR buffer, UINT count )
2100 return (UINT)_hwrite( hFile, buffer, (LONG)count );
2104 /***********************************************************************
2105 * _hread16 (KERNEL.349)
2107 LONG WINAPI _hread16( HFILE16 hFile, LPVOID buffer, LONG count)
2109 return _lread( (HFILE)DosFileHandleToWin32Handle(hFile), buffer, count );
2113 /***********************************************************************
2114 * _hread (KERNEL32.@)
2116 LONG WINAPI _hread( HFILE hFile, LPVOID buffer, LONG count)
2118 return _lread( hFile, buffer, count );
2122 /***********************************************************************
2123 * _hwrite (KERNEL.350)
2125 LONG WINAPI _hwrite16( HFILE16 hFile, LPCSTR buffer, LONG count )
2127 return _hwrite( (HFILE)DosFileHandleToWin32Handle(hFile), buffer, count );
2131 /***********************************************************************
2132 * _hwrite (KERNEL32.@)
2134 * experimentation yields that _lwrite:
2135 * o truncates the file at the current position with
2137 * o returns 0 on a 0 length write
2138 * o works with console handles
2141 LONG WINAPI _hwrite( HFILE handle, LPCSTR buffer, LONG count )
2145 TRACE("%d %p %ld\n", handle, buffer, count );
2149 /* Expand or truncate at current position */
2150 if (!SetEndOfFile( (HANDLE)handle )) return HFILE_ERROR;
2153 if (!WriteFile( (HANDLE)handle, buffer, count, &result, NULL ))
2159 /***********************************************************************
2160 * SetHandleCount (KERNEL.199)
2162 UINT16 WINAPI SetHandleCount16( UINT16 count )
2164 return SetHandleCount( count );
2168 /*************************************************************************
2169 * SetHandleCount (KERNEL32.@)
2171 UINT WINAPI SetHandleCount( UINT count )
2173 return min( 256, count );
2177 /***********************************************************************
2178 * FlushFileBuffers (KERNEL32.@)
2180 BOOL WINAPI FlushFileBuffers( HANDLE hFile )
2183 SERVER_START_REQ( flush_file )
2185 req->handle = hFile;
2186 ret = !wine_server_call_err( req );
2193 /**************************************************************************
2194 * SetEndOfFile (KERNEL32.@)
2196 BOOL WINAPI SetEndOfFile( HANDLE hFile )
2199 SERVER_START_REQ( truncate_file )
2201 req->handle = hFile;
2202 ret = !wine_server_call_err( req );
2209 /***********************************************************************
2210 * DeleteFile (KERNEL.146)
2212 BOOL16 WINAPI DeleteFile16( LPCSTR path )
2214 return DeleteFileA( path );
2218 /***********************************************************************
2219 * DeleteFileA (KERNEL32.@)
2221 BOOL WINAPI DeleteFileA( LPCSTR path )
2223 DOS_FULL_NAME full_name;
2228 SetLastError(ERROR_INVALID_PARAMETER);
2231 TRACE("'%s'\n", path );
2235 ERR("Empty path passed\n");
2238 if (DOSFS_GetDevice( path ))
2240 WARN("cannot remove DOS device '%s'!\n", path);
2241 SetLastError( ERROR_FILE_NOT_FOUND );
2245 if (!DOSFS_GetFullName( path, TRUE, &full_name )) return FALSE;
2247 /* check if we are allowed to delete the source */
2248 hFile = FILE_CreateFile( full_name.long_name, GENERIC_READ|GENERIC_WRITE, 0,
2249 NULL, OPEN_EXISTING, 0, 0, TRUE,
2250 GetDriveTypeA( full_name.short_name ) );
2251 if (!hFile) return FALSE;
2253 if (unlink( full_name.long_name ) == -1)
2264 /***********************************************************************
2265 * DeleteFileW (KERNEL32.@)
2267 BOOL WINAPI DeleteFileW( LPCWSTR path )
2269 LPSTR xpath = HEAP_strdupWtoA( GetProcessHeap(), 0, path );
2270 BOOL ret = DeleteFileA( xpath );
2271 HeapFree( GetProcessHeap(), 0, xpath );
2276 /***********************************************************************
2277 * GetFileType (KERNEL32.@)
2279 DWORD WINAPI GetFileType( HANDLE hFile )
2281 DWORD ret = FILE_TYPE_UNKNOWN;
2282 SERVER_START_REQ( get_file_info )
2284 req->handle = hFile;
2285 if (!wine_server_call_err( req )) ret = reply->type;
2292 /* check if a file name is for an executable file (.exe or .com) */
2293 inline static BOOL is_executable( const char *name )
2295 int len = strlen(name);
2297 if (len < 4) return FALSE;
2298 return (!strcasecmp( name + len - 4, ".exe" ) ||
2299 !strcasecmp( name + len - 4, ".com" ));
2303 /***********************************************************************
2304 * FILE_AddBootRenameEntry
2306 * Adds an entry to the registry that is loaded when windows boots and
2307 * checks if there are some files to be removed or renamed/moved.
2308 * <fn1> has to be valid and <fn2> may be NULL. If both pointers are
2309 * non-NULL then the file is moved, otherwise it is deleted. The
2310 * entry of the registrykey is always appended with two zero
2311 * terminated strings. If <fn2> is NULL then the second entry is
2312 * simply a single 0-byte. Otherwise the second filename goes
2313 * there. The entries are prepended with \??\ before the path and the
2314 * second filename gets also a '!' as the first character if
2315 * MOVEFILE_REPLACE_EXISTING is set. After the final string another
2316 * 0-byte follows to indicate the end of the strings.
2318 * \??\D:\test\file1[0]
2319 * !\??\D:\test\file1_renamed[0]
2320 * \??\D:\Test|delete[0]
2321 * [0] <- file is to be deleted, second string empty
2322 * \??\D:\test\file2[0]
2323 * !\??\D:\test\file2_renamed[0]
2324 * [0] <- indicates end of strings
2327 * \??\D:\test\file1[0]
2328 * !\??\D:\test\file1_renamed[0]
2329 * \??\D:\Test|delete[0]
2330 * [0] <- file is to be deleted, second string empty
2331 * [0] <- indicates end of strings
2334 static BOOL FILE_AddBootRenameEntry( const char *fn1, const char *fn2, DWORD flags )
2336 static const char PreString[] = "\\??\\";
2337 static const char ValueName[] = "PendingFileRenameOperations";
2341 DWORD Type, len1, len2, l;
2343 BYTE *Buffer = NULL;
2345 if(RegCreateKeyA(HKEY_LOCAL_MACHINE, "SYSTEM\\CurrentControlSet\\Control\\Session Manager",
2346 &Reboot) != ERROR_SUCCESS)
2348 WARN("Error creating key for reboot managment [%s]\n",
2349 "SYSTEM\\CurrentControlSet\\Control\\Session Manager");
2353 l = strlen(PreString);
2354 len1 = strlen(fn1) + l + 1;
2357 len2 = strlen(fn2) + l + 1;
2358 if (flags & MOVEFILE_REPLACE_EXISTING) len2++; /* Plus 1 because of the leading '!' */
2360 else len2 = 1; /* minimum is the 0 byte for the empty second string */
2362 /* First we check if the key exists and if so how many bytes it already contains. */
2363 if (RegQueryValueExA(Reboot, ValueName, NULL, &Type, NULL, &DataSize) == ERROR_SUCCESS)
2365 if (Type != REG_MULTI_SZ) goto Quit;
2366 if (!(Buffer = HeapAlloc( GetProcessHeap(), 0, DataSize + len1 + len2 + 1 ))) goto Quit;
2367 if (RegQueryValueExA(Reboot, ValueName, NULL, &Type, Buffer, &DataSize) != ERROR_SUCCESS)
2369 if (DataSize) DataSize--; /* remove terminating null (will be added back later) */
2373 if (!(Buffer = HeapAlloc( GetProcessHeap(), 0, len1 + len2 + 1 ))) goto Quit;
2376 sprintf( Buffer + DataSize, "%s%s", PreString, fn1 );
2380 sprintf( Buffer + DataSize, "%s%s%s",
2381 (flags & MOVEFILE_REPLACE_EXISTING) ? "!" : "", PreString, fn2 );
2384 else Buffer[DataSize++] = 0;
2386 Buffer[DataSize++] = 0; /* add final null */
2387 rc = !RegSetValueExA( Reboot, ValueName, 0, REG_MULTI_SZ, Buffer, DataSize );
2390 if (Reboot) RegCloseKey(Reboot);
2391 if (Buffer) HeapFree( GetProcessHeap(), 0, Buffer );
2396 /**************************************************************************
2397 * MoveFileExA (KERNEL32.@)
2399 BOOL WINAPI MoveFileExA( LPCSTR fn1, LPCSTR fn2, DWORD flag )
2401 DOS_FULL_NAME full_name1, full_name2;
2404 TRACE("(%s,%s,%04lx)\n", fn1, fn2, flag);
2406 /* FIXME: <Gerhard W. Gruber>sparhawk@gmx.at
2407 In case of W9x and lesser this function should return 120 (ERROR_CALL_NOT_IMPLEMENTED)
2408 to be really compatible. Most programs wont have any problems though. In case
2409 you encounter one, this is what you should return here. I don't know what's up
2410 with NT 3.5. Is this function available there or not?
2411 Does anybody really care about 3.5? :)
2414 /* Filename1 has to be always set to a valid path. Filename2 may be NULL
2415 if the source file has to be deleted.
2418 SetLastError(ERROR_INVALID_PARAMETER);
2422 /* This function has to be run through in order to process the name properly.
2423 If the BOOTDELAY flag is set, the file doesn't need to exist though. At least
2424 that is the behaviour on NT 4.0. The operation accepts the filenames as
2425 they are given but it can't reply with a reasonable returncode. Success
2426 means in that case success for entering the values into the registry.
2428 if(!DOSFS_GetFullName( fn1, TRUE, &full_name1 ))
2430 if(!(flag & MOVEFILE_DELAY_UNTIL_REBOOT))
2434 if (fn2) /* !fn2 means delete fn1 */
2436 if (DOSFS_GetFullName( fn2, TRUE, &full_name2 ))
2438 if(!(flag & MOVEFILE_DELAY_UNTIL_REBOOT))
2440 /* target exists, check if we may overwrite */
2441 if (!(flag & MOVEFILE_REPLACE_EXISTING))
2443 /* FIXME: Use right error code */
2444 SetLastError( ERROR_ACCESS_DENIED );
2451 if (!DOSFS_GetFullName( fn2, FALSE, &full_name2 ))
2453 if(!(flag & MOVEFILE_DELAY_UNTIL_REBOOT))
2458 /* Source name and target path are valid */
2460 if (flag & MOVEFILE_DELAY_UNTIL_REBOOT)
2462 /* FIXME: (bon@elektron.ikp.physik.th-darmstadt.de 970706)
2463 Perhaps we should queue these command and execute it
2464 when exiting... What about using on_exit(2)
2466 FIXME("Please move existing file '%s' to file '%s' when Wine has finished\n",
2468 return FILE_AddBootRenameEntry( fn1, fn2, flag );
2471 /* check if we are allowed to delete the source */
2472 hFile = FILE_CreateFile( full_name1.long_name, GENERIC_READ|GENERIC_WRITE, 0,
2473 NULL, OPEN_EXISTING, 0, 0, TRUE,
2474 GetDriveTypeA( full_name1.short_name ) );
2475 if (!hFile) return FALSE;
2478 /* check, if we are allowed to delete the destination,
2479 ** (but the file not being there is fine) */
2480 hFile = FILE_CreateFile( full_name2.long_name, GENERIC_READ|GENERIC_WRITE, 0,
2481 NULL, OPEN_EXISTING, 0, 0, TRUE,
2482 GetDriveTypeA( full_name2.short_name ) );
2483 if(!hFile && GetLastError() != ERROR_FILE_NOT_FOUND) return FALSE;
2486 if (full_name1.drive != full_name2.drive)
2488 /* use copy, if allowed */
2489 if (!(flag & MOVEFILE_COPY_ALLOWED))
2491 /* FIXME: Use right error code */
2492 SetLastError( ERROR_FILE_EXISTS );
2495 return CopyFileA( fn1, fn2, !(flag & MOVEFILE_REPLACE_EXISTING) );
2497 if (rename( full_name1.long_name, full_name2.long_name ) == -1)
2502 if (is_executable( full_name1.long_name ) != is_executable( full_name2.long_name ))
2505 if (stat( full_name2.long_name, &fstat ) != -1)
2507 if (is_executable( full_name2.long_name ))
2508 /* set executable bit where read bit is set */
2509 fstat.st_mode |= (fstat.st_mode & 0444) >> 2;
2511 fstat.st_mode &= ~0111;
2512 chmod( full_name2.long_name, fstat.st_mode );
2517 else /* fn2 == NULL means delete source */
2519 if (flag & MOVEFILE_DELAY_UNTIL_REBOOT)
2521 if (flag & MOVEFILE_COPY_ALLOWED) {
2522 WARN("Illegal flag\n");
2523 SetLastError( ERROR_GEN_FAILURE );
2526 /* FIXME: (bon@elektron.ikp.physik.th-darmstadt.de 970706)
2527 Perhaps we should queue these command and execute it
2528 when exiting... What about using on_exit(2)
2530 FIXME("Please delete file '%s' when Wine has finished\n", fn1);
2531 return FILE_AddBootRenameEntry( fn1, NULL, flag );
2534 if (unlink( full_name1.long_name ) == -1)
2539 return TRUE; /* successfully deleted */
2543 /**************************************************************************
2544 * MoveFileExW (KERNEL32.@)
2546 BOOL WINAPI MoveFileExW( LPCWSTR fn1, LPCWSTR fn2, DWORD flag )
2548 LPSTR afn1 = HEAP_strdupWtoA( GetProcessHeap(), 0, fn1 );
2549 LPSTR afn2 = HEAP_strdupWtoA( GetProcessHeap(), 0, fn2 );
2550 BOOL res = MoveFileExA( afn1, afn2, flag );
2551 HeapFree( GetProcessHeap(), 0, afn1 );
2552 HeapFree( GetProcessHeap(), 0, afn2 );
2557 /**************************************************************************
2558 * MoveFileA (KERNEL32.@)
2560 * Move file or directory
2562 BOOL WINAPI MoveFileA( LPCSTR fn1, LPCSTR fn2 )
2564 DOS_FULL_NAME full_name1, full_name2;
2567 TRACE("(%s,%s)\n", fn1, fn2 );
2569 if (!DOSFS_GetFullName( fn1, TRUE, &full_name1 )) return FALSE;
2570 if (DOSFS_GetFullName( fn2, TRUE, &full_name2 )) {
2571 /* The new name must not already exist */
2572 SetLastError(ERROR_ALREADY_EXISTS);
2575 if (!DOSFS_GetFullName( fn2, FALSE, &full_name2 )) return FALSE;
2577 if (full_name1.drive == full_name2.drive) /* move */
2578 return MoveFileExA( fn1, fn2, MOVEFILE_COPY_ALLOWED );
2581 if (stat( full_name1.long_name, &fstat ))
2583 WARN("Invalid source file %s\n",
2584 full_name1.long_name);
2588 if (S_ISDIR(fstat.st_mode)) {
2589 /* No Move for directories across file systems */
2590 /* FIXME: Use right error code */
2591 SetLastError( ERROR_GEN_FAILURE );
2594 return CopyFileA(fn1, fn2, TRUE); /*fail, if exist */
2598 /**************************************************************************
2599 * MoveFileW (KERNEL32.@)
2601 BOOL WINAPI MoveFileW( LPCWSTR fn1, LPCWSTR fn2 )
2603 LPSTR afn1 = HEAP_strdupWtoA( GetProcessHeap(), 0, fn1 );
2604 LPSTR afn2 = HEAP_strdupWtoA( GetProcessHeap(), 0, fn2 );
2605 BOOL res = MoveFileA( afn1, afn2 );
2606 HeapFree( GetProcessHeap(), 0, afn1 );
2607 HeapFree( GetProcessHeap(), 0, afn2 );
2612 /**************************************************************************
2613 * CopyFileA (KERNEL32.@)
2615 BOOL WINAPI CopyFileA( LPCSTR source, LPCSTR dest, BOOL fail_if_exists )
2618 BY_HANDLE_FILE_INFORMATION info;
2624 if ((h1 = CreateFileA( source, GENERIC_READ, FILE_SHARE_READ|FILE_SHARE_WRITE, NULL,
2625 OPEN_EXISTING, 0, 0 )) == INVALID_HANDLE_VALUE)
2627 if (!GetFileInformationByHandle( h1, &info ))
2632 mode = (info.dwFileAttributes & FILE_ATTRIBUTE_READONLY) ? 0444 : 0666;
2633 if ((h2 = CreateFileA( dest, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
2634 fail_if_exists ? CREATE_NEW : CREATE_ALWAYS,
2635 info.dwFileAttributes, h1 )) == INVALID_HANDLE_VALUE)
2641 while (ReadFile( h1, buffer, sizeof(buffer), &count, NULL ) && count > 0)
2647 if (!WriteFile( h2, p, count, &res, NULL ) || !res) goto done;
2660 /**************************************************************************
2661 * CopyFileW (KERNEL32.@)
2663 BOOL WINAPI CopyFileW( LPCWSTR source, LPCWSTR dest, BOOL fail_if_exists)
2665 LPSTR sourceA = HEAP_strdupWtoA( GetProcessHeap(), 0, source );
2666 LPSTR destA = HEAP_strdupWtoA( GetProcessHeap(), 0, dest );
2667 BOOL ret = CopyFileA( sourceA, destA, fail_if_exists );
2668 HeapFree( GetProcessHeap(), 0, sourceA );
2669 HeapFree( GetProcessHeap(), 0, destA );
2674 /**************************************************************************
2675 * CopyFileExA (KERNEL32.@)
2677 * This implementation ignores most of the extra parameters passed-in into
2678 * the "ex" version of the method and calls the CopyFile method.
2679 * It will have to be fixed eventually.
2681 BOOL WINAPI CopyFileExA(LPCSTR sourceFilename,
2682 LPCSTR destFilename,
2683 LPPROGRESS_ROUTINE progressRoutine,
2685 LPBOOL cancelFlagPointer,
2688 BOOL failIfExists = FALSE;
2691 * Interpret the only flag that CopyFile can interpret.
2693 if ( (copyFlags & COPY_FILE_FAIL_IF_EXISTS) != 0)
2695 failIfExists = TRUE;
2698 return CopyFileA(sourceFilename, destFilename, failIfExists);
2701 /**************************************************************************
2702 * CopyFileExW (KERNEL32.@)
2704 BOOL WINAPI CopyFileExW(LPCWSTR sourceFilename,
2705 LPCWSTR destFilename,
2706 LPPROGRESS_ROUTINE progressRoutine,
2708 LPBOOL cancelFlagPointer,
2711 LPSTR sourceA = HEAP_strdupWtoA( GetProcessHeap(), 0, sourceFilename );
2712 LPSTR destA = HEAP_strdupWtoA( GetProcessHeap(), 0, destFilename );
2714 BOOL ret = CopyFileExA(sourceA,
2721 HeapFree( GetProcessHeap(), 0, sourceA );
2722 HeapFree( GetProcessHeap(), 0, destA );
2728 /***********************************************************************
2729 * SetFileTime (KERNEL32.@)
2731 BOOL WINAPI SetFileTime( HANDLE hFile,
2732 const FILETIME *lpCreationTime,
2733 const FILETIME *lpLastAccessTime,
2734 const FILETIME *lpLastWriteTime )
2737 SERVER_START_REQ( set_file_time )
2739 req->handle = hFile;
2740 if (lpLastAccessTime)
2741 RtlTimeToSecondsSince1970( lpLastAccessTime, (DWORD *)&req->access_time );
2743 req->access_time = 0; /* FIXME */
2744 if (lpLastWriteTime)
2745 RtlTimeToSecondsSince1970( lpLastWriteTime, (DWORD *)&req->write_time );
2747 req->write_time = 0; /* FIXME */
2748 ret = !wine_server_call_err( req );
2755 /**************************************************************************
2756 * LockFile (KERNEL32.@)
2758 BOOL WINAPI LockFile( HANDLE hFile, DWORD dwFileOffsetLow, DWORD dwFileOffsetHigh,
2759 DWORD nNumberOfBytesToLockLow, DWORD nNumberOfBytesToLockHigh )
2763 FIXME("not implemented in server\n");
2765 SERVER_START_REQ( lock_file )
2767 req->handle = hFile;
2768 req->offset_low = dwFileOffsetLow;
2769 req->offset_high = dwFileOffsetHigh;
2770 req->count_low = nNumberOfBytesToLockLow;
2771 req->count_high = nNumberOfBytesToLockHigh;
2772 ret = !wine_server_call_err( req );
2778 /**************************************************************************
2779 * LockFileEx [KERNEL32.@]
2781 * Locks a byte range within an open file for shared or exclusive access.
2788 * Per Microsoft docs, the third parameter (reserved) must be set to 0.
2790 BOOL WINAPI LockFileEx( HANDLE hFile, DWORD flags, DWORD reserved,
2791 DWORD nNumberOfBytesToLockLow, DWORD nNumberOfBytesToLockHigh,
2792 LPOVERLAPPED pOverlapped )
2794 FIXME("hFile=%d,flags=%ld,reserved=%ld,lowbytes=%ld,highbytes=%ld,overlapped=%p: stub.\n",
2795 hFile, flags, reserved, nNumberOfBytesToLockLow, nNumberOfBytesToLockHigh,
2798 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
2801 ERR("reserved == %ld: Supposed to be 0??\n", reserved);
2802 SetLastError(ERROR_INVALID_PARAMETER);
2809 /**************************************************************************
2810 * UnlockFile (KERNEL32.@)
2812 BOOL WINAPI UnlockFile( HANDLE hFile, DWORD dwFileOffsetLow, DWORD dwFileOffsetHigh,
2813 DWORD nNumberOfBytesToUnlockLow, DWORD nNumberOfBytesToUnlockHigh )
2817 FIXME("not implemented in server\n");
2819 SERVER_START_REQ( unlock_file )
2821 req->handle = hFile;
2822 req->offset_low = dwFileOffsetLow;
2823 req->offset_high = dwFileOffsetHigh;
2824 req->count_low = nNumberOfBytesToUnlockLow;
2825 req->count_high = nNumberOfBytesToUnlockHigh;
2826 ret = !wine_server_call_err( req );
2833 /**************************************************************************
2834 * UnlockFileEx (KERNEL32.@)
2836 BOOL WINAPI UnlockFileEx(
2839 DWORD nNumberOfBytesToUnlockLow,
2840 DWORD nNumberOfBytesToUnlockHigh,
2841 LPOVERLAPPED lpOverlapped
2844 FIXME("hFile=%d,reserved=%ld,lowbytes=%ld,highbytes=%ld,overlapped=%p: stub.\n",
2845 hFile, dwReserved, nNumberOfBytesToUnlockLow, nNumberOfBytesToUnlockHigh,
2847 if (dwReserved == 0)
2848 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
2851 ERR("reserved == %ld: Supposed to be 0??\n", dwReserved);
2852 SetLastError(ERROR_INVALID_PARAMETER);
2861 struct DOS_FILE_LOCK {
2862 struct DOS_FILE_LOCK * next;
2866 FILE_OBJECT * dos_file;
2867 /* char * unix_name;*/
2870 typedef struct DOS_FILE_LOCK DOS_FILE_LOCK;
2872 static DOS_FILE_LOCK *locks = NULL;
2873 static void DOS_RemoveFileLocks(FILE_OBJECT *file);
2876 /* Locks need to be mirrored because unix file locking is based
2877 * on the pid. Inside of wine there can be multiple WINE processes
2878 * that share the same unix pid.
2879 * Read's and writes should check these locks also - not sure
2880 * how critical that is at this point (FIXME).
2883 static BOOL DOS_AddLock(FILE_OBJECT *file, struct flock *f)
2885 DOS_FILE_LOCK *curr;
2888 processId = GetCurrentProcessId();
2890 /* check if lock overlaps a current lock for the same file */
2892 for (curr = locks; curr; curr = curr->next) {
2893 if (strcmp(curr->unix_name, file->unix_name) == 0) {
2894 if ((f->l_start == curr->base) && (f->l_len == curr->len))
2895 return TRUE;/* region is identic */
2896 if ((f->l_start < (curr->base + curr->len)) &&
2897 ((f->l_start + f->l_len) > curr->base)) {
2898 /* region overlaps */
2905 curr = HeapAlloc( GetProcessHeap(), 0, sizeof(DOS_FILE_LOCK) );
2906 curr->processId = GetCurrentProcessId();
2907 curr->base = f->l_start;
2908 curr->len = f->l_len;
2909 /* curr->unix_name = HEAP_strdupA( GetProcessHeap(), 0, file->unix_name);*/
2911 curr->dos_file = file;
2916 static void DOS_RemoveFileLocks(FILE_OBJECT *file)
2919 DOS_FILE_LOCK **curr;
2922 processId = GetCurrentProcessId();
2925 if ((*curr)->dos_file == file) {
2927 *curr = (*curr)->next;
2928 /* HeapFree( GetProcessHeap(), 0, rem->unix_name );*/
2929 HeapFree( GetProcessHeap(), 0, rem );
2932 curr = &(*curr)->next;
2936 static BOOL DOS_RemoveLock(FILE_OBJECT *file, struct flock *f)
2939 DOS_FILE_LOCK **curr;
2942 processId = GetCurrentProcessId();
2943 for (curr = &locks; *curr; curr = &(*curr)->next) {
2944 if ((*curr)->processId == processId &&
2945 (*curr)->dos_file == file &&
2946 (*curr)->base == f->l_start &&
2947 (*curr)->len == f->l_len) {
2948 /* this is the same lock */
2950 *curr = (*curr)->next;
2951 /* HeapFree( GetProcessHeap(), 0, rem->unix_name );*/
2952 HeapFree( GetProcessHeap(), 0, rem );
2956 /* no matching lock found */
2961 /**************************************************************************
2962 * LockFile (KERNEL32.@)
2964 BOOL WINAPI LockFile(
2965 HANDLE hFile,DWORD dwFileOffsetLow,DWORD dwFileOffsetHigh,
2966 DWORD nNumberOfBytesToLockLow,DWORD nNumberOfBytesToLockHigh )
2971 TRACE("handle %d offsetlow=%ld offsethigh=%ld nbyteslow=%ld nbyteshigh=%ld\n",
2972 hFile, dwFileOffsetLow, dwFileOffsetHigh,
2973 nNumberOfBytesToLockLow, nNumberOfBytesToLockHigh);
2975 if (dwFileOffsetHigh || nNumberOfBytesToLockHigh) {
2976 FIXME("Unimplemented bytes > 32bits\n");
2980 f.l_start = dwFileOffsetLow;
2981 f.l_len = nNumberOfBytesToLockLow;
2982 f.l_whence = SEEK_SET;
2986 if (!(file = FILE_GetFile(hFile,0,NULL))) return FALSE;
2988 /* shadow locks internally */
2989 if (!DOS_AddLock(file, &f)) {
2990 SetLastError( ERROR_LOCK_VIOLATION );
2994 /* FIXME: Unix locking commented out for now, doesn't work with Excel */
2995 #ifdef USE_UNIX_LOCKS
2996 if (fcntl(file->unix_handle, F_SETLK, &f) == -1) {
2997 if (errno == EACCES || errno == EAGAIN) {
2998 SetLastError( ERROR_LOCK_VIOLATION );
3003 /* remove our internal copy of the lock */
3004 DOS_RemoveLock(file, &f);
3012 /**************************************************************************
3013 * UnlockFile (KERNEL32.@)
3015 BOOL WINAPI UnlockFile(
3016 HANDLE hFile,DWORD dwFileOffsetLow,DWORD dwFileOffsetHigh,
3017 DWORD nNumberOfBytesToUnlockLow,DWORD nNumberOfBytesToUnlockHigh )
3022 TRACE("handle %d offsetlow=%ld offsethigh=%ld nbyteslow=%ld nbyteshigh=%ld\n",
3023 hFile, dwFileOffsetLow, dwFileOffsetHigh,
3024 nNumberOfBytesToUnlockLow, nNumberOfBytesToUnlockHigh);
3026 if (dwFileOffsetHigh || nNumberOfBytesToUnlockHigh) {
3027 WARN("Unimplemented bytes > 32bits\n");
3031 f.l_start = dwFileOffsetLow;
3032 f.l_len = nNumberOfBytesToUnlockLow;
3033 f.l_whence = SEEK_SET;
3037 if (!(file = FILE_GetFile(hFile,0,NULL))) return FALSE;
3039 DOS_RemoveLock(file, &f); /* ok if fails - may be another wine */
3041 /* FIXME: Unix locking commented out for now, doesn't work with Excel */
3042 #ifdef USE_UNIX_LOCKS
3043 if (fcntl(file->unix_handle, F_SETLK, &f) == -1) {
3052 /**************************************************************************
3053 * GetFileAttributesExA [KERNEL32.@]
3055 BOOL WINAPI GetFileAttributesExA(
3056 LPCSTR lpFileName, GET_FILEEX_INFO_LEVELS fInfoLevelId,
3057 LPVOID lpFileInformation)
3059 DOS_FULL_NAME full_name;
3060 BY_HANDLE_FILE_INFORMATION info;
3062 if (lpFileName == NULL) return FALSE;
3063 if (lpFileInformation == NULL) return FALSE;
3065 if (fInfoLevelId == GetFileExInfoStandard) {
3066 LPWIN32_FILE_ATTRIBUTE_DATA lpFad =
3067 (LPWIN32_FILE_ATTRIBUTE_DATA) lpFileInformation;
3068 if (!DOSFS_GetFullName( lpFileName, TRUE, &full_name )) return FALSE;
3069 if (!FILE_Stat( full_name.long_name, &info )) return FALSE;
3071 lpFad->dwFileAttributes = info.dwFileAttributes;
3072 lpFad->ftCreationTime = info.ftCreationTime;
3073 lpFad->ftLastAccessTime = info.ftLastAccessTime;
3074 lpFad->ftLastWriteTime = info.ftLastWriteTime;
3075 lpFad->nFileSizeHigh = info.nFileSizeHigh;
3076 lpFad->nFileSizeLow = info.nFileSizeLow;
3079 FIXME("invalid info level %d!\n", fInfoLevelId);
3087 /**************************************************************************
3088 * GetFileAttributesExW [KERNEL32.@]
3090 BOOL WINAPI GetFileAttributesExW(
3091 LPCWSTR lpFileName, GET_FILEEX_INFO_LEVELS fInfoLevelId,
3092 LPVOID lpFileInformation)
3094 LPSTR nameA = HEAP_strdupWtoA( GetProcessHeap(), 0, lpFileName );
3096 GetFileAttributesExA( nameA, fInfoLevelId, lpFileInformation);
3097 HeapFree( GetProcessHeap(), 0, nameA );