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
44 #ifdef HAVE_SYS_TIME_H
45 # include <sys/time.h>
57 #include "wine/winbase16.h"
58 #include "wine/server.h"
68 #include "wine/debug.h"
70 WINE_DEFAULT_DEBUG_CHANNEL(file);
72 #if defined(MAP_ANONYMOUS) && !defined(MAP_ANON)
73 #define MAP_ANON MAP_ANONYMOUS
76 /* Size of per-process table of DOS handles */
77 #define DOS_TABLE_SIZE 256
79 /* Macro to derive file offset from OVERLAPPED struct */
80 #define OVERLAPPED_OFFSET(overlapped) ((off_t) (overlapped)->Offset + ((off_t) (overlapped)->OffsetHigh << 32))
82 static HANDLE dos_handles[DOS_TABLE_SIZE];
86 extern HANDLE WINAPI FILE_SmbOpen(LPCSTR name);
88 /***********************************************************************
89 * Asynchronous file I/O *
91 static DWORD fileio_get_async_status (const async_private *ovp);
92 static DWORD fileio_get_async_count (const async_private *ovp);
93 static void fileio_set_async_status (async_private *ovp, const DWORD status);
94 static void CALLBACK fileio_call_completion_func (ULONG_PTR data);
95 static void fileio_async_cleanup (async_private *ovp);
97 static async_ops fileio_async_ops =
99 fileio_get_async_status, /* get_status */
100 fileio_set_async_status, /* set_status */
101 fileio_get_async_count, /* get_count */
102 fileio_call_completion_func, /* call_completion */
103 fileio_async_cleanup /* cleanup */
106 static async_ops fileio_nocomp_async_ops =
108 fileio_get_async_status, /* get_status */
109 fileio_set_async_status, /* set_status */
110 fileio_get_async_count, /* get_count */
111 NULL, /* call_completion */
112 fileio_async_cleanup /* cleanup */
115 typedef struct async_fileio
117 struct async_private async;
118 LPOVERLAPPED lpOverlapped;
119 LPOVERLAPPED_COMPLETION_ROUTINE completion_func;
122 enum fd_type fd_type;
125 static DWORD fileio_get_async_status (const struct async_private *ovp)
127 return ((async_fileio*) ovp)->lpOverlapped->Internal;
130 static void fileio_set_async_status (async_private *ovp, const DWORD status)
132 ((async_fileio*) ovp)->lpOverlapped->Internal = status;
135 static DWORD fileio_get_async_count (const struct async_private *ovp)
137 async_fileio *fileio = (async_fileio*) ovp;
138 DWORD ret = fileio->count - fileio->lpOverlapped->InternalHigh;
139 return (ret < 0 ? 0 : ret);
142 static void CALLBACK fileio_call_completion_func (ULONG_PTR data)
144 async_fileio *ovp = (async_fileio*) data;
145 TRACE ("data: %p\n", ovp);
147 ovp->completion_func( ovp->lpOverlapped->Internal,
148 ovp->lpOverlapped->InternalHigh,
151 fileio_async_cleanup ( &ovp->async );
154 static void fileio_async_cleanup ( struct async_private *ovp )
156 HeapFree ( GetProcessHeap(), 0, ovp );
159 /***********************************************************************
162 * Convert OF_* mode into flags for CreateFile.
164 static void FILE_ConvertOFMode( INT mode, DWORD *access, DWORD *sharing )
168 case OF_READ: *access = GENERIC_READ; break;
169 case OF_WRITE: *access = GENERIC_WRITE; break;
170 case OF_READWRITE: *access = GENERIC_READ | GENERIC_WRITE; break;
171 default: *access = 0; break;
175 case OF_SHARE_EXCLUSIVE: *sharing = 0; break;
176 case OF_SHARE_DENY_WRITE: *sharing = FILE_SHARE_READ; break;
177 case OF_SHARE_DENY_READ: *sharing = FILE_SHARE_WRITE; break;
178 case OF_SHARE_DENY_NONE:
179 case OF_SHARE_COMPAT:
180 default: *sharing = FILE_SHARE_READ | FILE_SHARE_WRITE; break;
185 /***********************************************************************
188 * locale-independent case conversion for file I/O
190 int FILE_strcasecmp( const char *str1, const char *str2 )
194 int ret = FILE_toupper(*str1) - FILE_toupper(*str2);
195 if (ret || !*str1) return ret;
202 /***********************************************************************
205 * locale-independent case conversion for file I/O
207 int FILE_strncasecmp( const char *str1, const char *str2, int len )
210 for ( ; len > 0; len--, str1++, str2++)
211 if ((ret = FILE_toupper(*str1) - FILE_toupper(*str2)) || !*str1) break;
216 /***********************************************************************
217 * FILE_GetNtStatus(void)
219 * Retrieve the Nt Status code from errno.
220 * Try to be consistent with FILE_SetDosError().
222 DWORD FILE_GetNtStatus(void)
226 TRACE ( "errno = %d\n", errno );
229 case EAGAIN: nt = STATUS_SHARING_VIOLATION; break;
230 case EBADF: nt = STATUS_INVALID_HANDLE; break;
231 case ENOSPC: nt = STATUS_DISK_FULL; break;
234 case EACCES: nt = STATUS_ACCESS_DENIED; break;
235 case ENOENT: nt = STATUS_SHARING_VIOLATION; break;
236 case EISDIR: nt = STATUS_FILE_IS_A_DIRECTORY; break;
238 case ENFILE: nt = STATUS_NO_MORE_FILES; break;
240 case ENOTEMPTY: nt = STATUS_DIRECTORY_NOT_EMPTY; break;
241 case EPIPE: nt = STATUS_PIPE_BROKEN; break;
242 case ENOEXEC: /* ?? */
243 case ESPIPE: /* ?? */
244 case EEXIST: /* ?? */
246 FIXME ( "Converting errno %d to STATUS_UNSUCCESSFUL\n", err );
247 nt = STATUS_UNSUCCESSFUL;
252 /***********************************************************************
255 * Set the DOS error code from errno.
257 void FILE_SetDosError(void)
259 int save_errno = errno; /* errno gets overwritten by printf */
261 TRACE("errno = %d %s\n", errno, strerror(errno));
265 SetLastError( ERROR_SHARING_VIOLATION );
268 SetLastError( ERROR_INVALID_HANDLE );
271 SetLastError( ERROR_HANDLE_DISK_FULL );
276 SetLastError( ERROR_ACCESS_DENIED );
279 SetLastError( ERROR_LOCK_VIOLATION );
282 SetLastError( ERROR_FILE_NOT_FOUND );
285 SetLastError( ERROR_CANNOT_MAKE );
289 SetLastError( ERROR_NO_MORE_FILES );
292 SetLastError( ERROR_FILE_EXISTS );
296 SetLastError( ERROR_SEEK );
299 SetLastError( ERROR_DIR_NOT_EMPTY );
302 SetLastError( ERROR_BAD_FORMAT );
305 WARN("unknown file error: %s\n", strerror(save_errno) );
306 SetLastError( ERROR_GEN_FAILURE );
313 /***********************************************************************
314 * FILE_GetUnixHandleType
316 * Retrieve the Unix handle corresponding to a file handle.
317 * Returns -1 on failure.
319 static int FILE_GetUnixHandleType( HANDLE handle, DWORD access, enum fd_type *type, int *flags_ptr )
321 int ret, flags, fd = -1;
323 ret = wine_server_handle_to_fd( handle, access, &fd, type, &flags );
324 if (flags_ptr) *flags_ptr = flags;
325 if (ret) SetLastError( RtlNtStatusToDosError(ret) );
326 else if (((access & GENERIC_READ) && (flags & FD_FLAG_RECV_SHUTDOWN)) ||
327 ((access & GENERIC_WRITE) && (flags & FD_FLAG_SEND_SHUTDOWN)))
330 SetLastError ( ERROR_PIPE_NOT_CONNECTED );
336 /***********************************************************************
339 * Retrieve the Unix handle corresponding to a file handle.
340 * Returns -1 on failure.
342 int FILE_GetUnixHandle( HANDLE handle, DWORD access )
344 return FILE_GetUnixHandleType( handle, access, NULL, NULL );
347 /*************************************************************************
350 * Open a handle to the current process console.
351 * Returns 0 on failure.
353 static HANDLE FILE_OpenConsole( BOOL output, DWORD access, DWORD sharing, LPSECURITY_ATTRIBUTES sa )
357 SERVER_START_REQ( open_console )
360 req->access = access;
361 req->share = sharing;
362 req->inherit = (sa && (sa->nLength>=sizeof(*sa)) && sa->bInheritHandle);
364 wine_server_call_err( req );
371 /* FIXME: those routines defined as pointers are needed, because this file is
372 * currently compiled into NTDLL whereas it belongs to kernel32.
373 * this shall go away once all the DLL separation process is done
375 typedef BOOL (WINAPI* pRW)(HANDLE, const void*, DWORD, DWORD*, void*);
377 static BOOL FILE_ReadConsole(HANDLE hCon, void* buf, DWORD nb, DWORD* nr, void* p)
379 static HANDLE hKernel /* = 0 */;
380 static pRW pReadConsole /* = 0 */;
382 if ((!hKernel && !(hKernel = LoadLibraryA("kernel32"))) ||
384 !(pReadConsole = GetProcAddress(hKernel, "ReadConsoleA"))))
389 return (pReadConsole)(hCon, buf, nb, nr, p);
392 static BOOL FILE_WriteConsole(HANDLE hCon, const void* buf, DWORD nb, DWORD* nr, void* p)
394 static HANDLE hKernel /* = 0 */;
395 static pRW pWriteConsole /* = 0 */;
397 if ((!hKernel && !(hKernel = LoadLibraryA("kernel32"))) ||
399 !(pWriteConsole = GetProcAddress(hKernel, "WriteConsoleA"))))
404 return (pWriteConsole)(hCon, buf, nb, nr, p);
408 /***********************************************************************
411 * Implementation of CreateFile. Takes a Unix path name.
412 * Returns 0 on failure.
414 HANDLE FILE_CreateFile( LPCSTR filename, DWORD access, DWORD sharing,
415 LPSECURITY_ATTRIBUTES sa, DWORD creation,
416 DWORD attributes, HANDLE template, BOOL fail_read_only,
424 SERVER_START_REQ( create_file )
426 req->access = access;
427 req->inherit = (sa && (sa->nLength>=sizeof(*sa)) && sa->bInheritHandle);
428 req->sharing = sharing;
429 req->create = creation;
430 req->attrs = attributes;
431 req->drive_type = drive_type;
432 wine_server_add_data( req, filename, strlen(filename) );
434 err = wine_server_call( req );
439 /* If write access failed, retry without GENERIC_WRITE */
441 if (!ret && !fail_read_only && (access & GENERIC_WRITE))
443 if ((err == STATUS_MEDIA_WRITE_PROTECTED) || (err == STATUS_ACCESS_DENIED))
445 TRACE("Write access failed for file '%s', trying without "
446 "write access\n", filename);
447 access &= ~GENERIC_WRITE;
452 if (err) SetLastError( RtlNtStatusToDosError(err) );
454 if (!ret) WARN("Unable to create file '%s' (GLE %ld)\n", filename, GetLastError());
460 /***********************************************************************
463 * Same as FILE_CreateFile but for a device
464 * Returns 0 on failure.
466 HANDLE FILE_CreateDevice( int client_id, DWORD access, LPSECURITY_ATTRIBUTES sa )
469 SERVER_START_REQ( create_device )
471 req->access = access;
472 req->inherit = (sa && (sa->nLength>=sizeof(*sa)) && sa->bInheritHandle);
475 wine_server_call_err( req );
482 static HANDLE FILE_OpenPipe(LPCSTR name, DWORD access)
484 WCHAR buffer[MAX_PATH];
488 if (name && !(len = MultiByteToWideChar( CP_ACP, 0, name, strlen(name), buffer, MAX_PATH )))
490 SetLastError( ERROR_FILENAME_EXCED_RANGE );
493 SERVER_START_REQ( open_named_pipe )
495 req->access = access;
497 wine_server_add_data( req, buffer, len * sizeof(WCHAR) );
498 wine_server_call_err( req );
502 TRACE("Returned %d\n",ret);
506 /*************************************************************************
507 * CreateFileA [KERNEL32.@] Creates or opens a file or other object
509 * Creates or opens an object, and returns a handle that can be used to
510 * access that object.
514 * filename [in] pointer to filename to be accessed
515 * access [in] access mode requested
516 * sharing [in] share mode
517 * sa [in] pointer to security attributes
518 * creation [in] how to create the file
519 * attributes [in] attributes for newly created file
520 * template [in] handle to file with extended attributes to copy
523 * Success: Open handle to specified file
524 * Failure: INVALID_HANDLE_VALUE
527 * Should call SetLastError() on failure.
531 * Doesn't support character devices, template files, or a
532 * lot of the 'attributes' flags yet.
534 HANDLE WINAPI CreateFileA( LPCSTR filename, DWORD access, DWORD sharing,
535 LPSECURITY_ATTRIBUTES sa, DWORD creation,
536 DWORD attributes, HANDLE template )
538 DOS_FULL_NAME full_name;
543 SetLastError( ERROR_INVALID_PARAMETER );
544 return INVALID_HANDLE_VALUE;
546 TRACE("%s %s%s%s%s%s%s%s\n",filename,
547 ((access & GENERIC_READ)==GENERIC_READ)?"GENERIC_READ ":"",
548 ((access & GENERIC_WRITE)==GENERIC_WRITE)?"GENERIC_WRITE ":"",
549 (!access)?"QUERY_ACCESS ":"",
550 ((sharing & FILE_SHARE_READ)==FILE_SHARE_READ)?"FILE_SHARE_READ ":"",
551 ((sharing & FILE_SHARE_WRITE)==FILE_SHARE_WRITE)?"FILE_SHARE_WRITE ":"",
552 ((sharing & FILE_SHARE_DELETE)==FILE_SHARE_DELETE)?"FILE_SHARE_DELETE ":"",
553 (creation ==CREATE_NEW)?"CREATE_NEW":
554 (creation ==CREATE_ALWAYS)?"CREATE_ALWAYS ":
555 (creation ==OPEN_EXISTING)?"OPEN_EXISTING ":
556 (creation ==OPEN_ALWAYS)?"OPEN_ALWAYS ":
557 (creation ==TRUNCATE_EXISTING)?"TRUNCATE_EXISTING ":"");
559 /* If the name starts with '\\?\', ignore the first 4 chars. */
560 if (!strncmp(filename, "\\\\?\\", 4))
563 if (!strncmp(filename, "UNC\\", 4))
565 FIXME("UNC name (%s) not supported.\n", filename );
566 SetLastError( ERROR_PATH_NOT_FOUND );
567 return INVALID_HANDLE_VALUE;
571 if (!strncmp(filename, "\\\\.\\", 4)) {
572 if(!strncasecmp(&filename[4],"pipe\\",5))
574 TRACE("Opening a pipe: %s\n",filename);
575 ret = FILE_OpenPipe(filename,access);
578 else if (isalpha(filename[4]) && filename[5] == ':' && filename[6] == '\0')
580 ret = FILE_CreateDevice( (toupper(filename[4]) - 'A') | 0x20000, access, sa );
583 else if (!DOSFS_GetDevice( filename ))
585 ret = DEVICE_Open( filename+4, access, sa );
589 filename+=4; /* fall into DOSFS_Device case below */
592 /* If the name still starts with '\\', it's a UNC name. */
593 if (!strncmp(filename, "\\\\", 2))
595 ret = SMB_CreateFileA(filename, access, sharing, sa, creation, attributes, template );
599 /* If the name contains a DOS wild card (* or ?), do no create a file */
600 if(strchr(filename,'*') || strchr(filename,'?'))
601 return INVALID_HANDLE_VALUE;
603 /* Open a console for CONIN$ or CONOUT$ */
604 if (!strcasecmp(filename, "CONIN$"))
606 ret = FILE_OpenConsole( FALSE, access, sharing, sa );
609 if (!strcasecmp(filename, "CONOUT$"))
611 ret = FILE_OpenConsole( TRUE, access, sharing, sa );
615 if (DOSFS_GetDevice( filename ))
617 TRACE("opening device '%s'\n", filename );
619 if (!(ret = DOSFS_OpenDevice( filename, access, attributes, sa )))
621 /* Do not silence this please. It is a critical error. -MM */
622 ERR("Couldn't open device '%s'!\n",filename);
623 SetLastError( ERROR_FILE_NOT_FOUND );
628 /* check for filename, don't check for last entry if creating */
629 if (!DOSFS_GetFullName( filename,
630 (creation == OPEN_EXISTING) ||
631 (creation == TRUNCATE_EXISTING),
633 WARN("Unable to get full filename from '%s' (GLE %ld)\n",
634 filename, GetLastError());
635 return INVALID_HANDLE_VALUE;
638 ret = FILE_CreateFile( full_name.long_name, access, sharing,
639 sa, creation, attributes, template,
640 DRIVE_GetFlags(full_name.drive) & DRIVE_FAIL_READ_ONLY,
641 GetDriveTypeA( full_name.short_name ) );
643 if (!ret) ret = INVALID_HANDLE_VALUE;
649 /*************************************************************************
650 * CreateFileW (KERNEL32.@)
652 HANDLE WINAPI CreateFileW( LPCWSTR filename, DWORD access, DWORD sharing,
653 LPSECURITY_ATTRIBUTES sa, DWORD creation,
654 DWORD attributes, HANDLE template)
656 LPSTR afn = HEAP_strdupWtoA( GetProcessHeap(), 0, filename );
657 HANDLE res = CreateFileA( afn, access, sharing, sa, creation, attributes, template );
658 HeapFree( GetProcessHeap(), 0, afn );
663 /***********************************************************************
666 * Fill a file information from a struct stat.
668 static void FILE_FillInfo( struct stat *st, BY_HANDLE_FILE_INFORMATION *info )
670 if (S_ISDIR(st->st_mode))
671 info->dwFileAttributes = FILE_ATTRIBUTE_DIRECTORY;
673 info->dwFileAttributes = FILE_ATTRIBUTE_ARCHIVE;
674 if (!(st->st_mode & S_IWUSR))
675 info->dwFileAttributes |= FILE_ATTRIBUTE_READONLY;
677 RtlSecondsSince1970ToTime( st->st_mtime, &info->ftCreationTime );
678 RtlSecondsSince1970ToTime( st->st_mtime, &info->ftLastWriteTime );
679 RtlSecondsSince1970ToTime( st->st_atime, &info->ftLastAccessTime );
681 info->dwVolumeSerialNumber = 0; /* FIXME */
682 info->nFileSizeHigh = 0;
683 info->nFileSizeLow = 0;
684 if (!S_ISDIR(st->st_mode)) {
685 info->nFileSizeHigh = st->st_size >> 32;
686 info->nFileSizeLow = st->st_size & 0xffffffff;
688 info->nNumberOfLinks = st->st_nlink;
689 info->nFileIndexHigh = 0;
690 info->nFileIndexLow = st->st_ino;
694 /***********************************************************************
697 * Stat a Unix path name. Return TRUE if OK.
699 BOOL FILE_Stat( LPCSTR unixName, BY_HANDLE_FILE_INFORMATION *info )
703 if (lstat( unixName, &st ) == -1)
708 if (!S_ISLNK(st.st_mode)) FILE_FillInfo( &st, info );
711 /* do a "real" stat to find out
712 about the type of the symlink destination */
713 if (stat( unixName, &st ) == -1)
718 FILE_FillInfo( &st, info );
719 info->dwFileAttributes |= FILE_ATTRIBUTE_SYMLINK;
725 /***********************************************************************
726 * GetFileInformationByHandle (KERNEL32.@)
728 DWORD WINAPI GetFileInformationByHandle( HANDLE hFile,
729 BY_HANDLE_FILE_INFORMATION *info )
734 SERVER_START_REQ( get_file_info )
737 if ((ret = !wine_server_call_err( req )))
739 /* FIXME: which file types are supported ?
740 * Serial ports (FILE_TYPE_CHAR) are not,
741 * and MSDN also says that pipes are not supported.
742 * FILE_TYPE_REMOTE seems to be supported according to
743 * MSDN q234741.txt */
744 if ((reply->type == FILE_TYPE_DISK) || (reply->type == FILE_TYPE_REMOTE))
746 RtlSecondsSince1970ToTime( reply->write_time, &info->ftCreationTime );
747 RtlSecondsSince1970ToTime( reply->write_time, &info->ftLastWriteTime );
748 RtlSecondsSince1970ToTime( reply->access_time, &info->ftLastAccessTime );
749 info->dwFileAttributes = reply->attr;
750 info->dwVolumeSerialNumber = reply->serial;
751 info->nFileSizeHigh = reply->size_high;
752 info->nFileSizeLow = reply->size_low;
753 info->nNumberOfLinks = reply->links;
754 info->nFileIndexHigh = reply->index_high;
755 info->nFileIndexLow = reply->index_low;
759 SetLastError(ERROR_NOT_SUPPORTED);
769 /**************************************************************************
770 * GetFileAttributes (KERNEL.420)
772 DWORD WINAPI GetFileAttributes16( LPCSTR name )
774 return GetFileAttributesA( name );
778 /**************************************************************************
779 * GetFileAttributesA (KERNEL32.@)
781 DWORD WINAPI GetFileAttributesA( LPCSTR name )
783 DOS_FULL_NAME full_name;
784 BY_HANDLE_FILE_INFORMATION info;
788 SetLastError( ERROR_INVALID_PARAMETER );
791 if (!DOSFS_GetFullName( name, TRUE, &full_name) )
793 if (!FILE_Stat( full_name.long_name, &info )) return -1;
794 return info.dwFileAttributes;
798 /**************************************************************************
799 * GetFileAttributesW (KERNEL32.@)
801 DWORD WINAPI GetFileAttributesW( LPCWSTR name )
803 LPSTR nameA = HEAP_strdupWtoA( GetProcessHeap(), 0, name );
804 DWORD res = GetFileAttributesA( nameA );
805 HeapFree( GetProcessHeap(), 0, nameA );
810 /**************************************************************************
811 * SetFileAttributes (KERNEL.421)
813 BOOL16 WINAPI SetFileAttributes16( LPCSTR lpFileName, DWORD attributes )
815 return SetFileAttributesA( lpFileName, attributes );
819 /**************************************************************************
820 * SetFileAttributesA (KERNEL32.@)
822 BOOL WINAPI SetFileAttributesA(LPCSTR lpFileName, DWORD attributes)
825 DOS_FULL_NAME full_name;
827 if (!DOSFS_GetFullName( lpFileName, TRUE, &full_name ))
830 TRACE("(%s,%lx)\n",lpFileName,attributes);
831 if(stat(full_name.long_name,&buf)==-1)
836 if (attributes & FILE_ATTRIBUTE_READONLY)
838 if(S_ISDIR(buf.st_mode))
840 WARN("FILE_ATTRIBUTE_READONLY ignored for directory.\n");
842 buf.st_mode &= ~0222; /* octal!, clear write permission bits */
843 attributes &= ~FILE_ATTRIBUTE_READONLY;
847 /* add write permission */
848 buf.st_mode |= (0600 | ((buf.st_mode & 044) >> 1)) & (~FILE_umask);
850 if (attributes & FILE_ATTRIBUTE_DIRECTORY)
852 if (!S_ISDIR(buf.st_mode))
853 FIXME("SetFileAttributes expected the file '%s' to be a directory\n",
855 attributes &= ~FILE_ATTRIBUTE_DIRECTORY;
857 attributes &= ~(FILE_ATTRIBUTE_NORMAL|FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_HIDDEN|FILE_ATTRIBUTE_SYSTEM);
859 FIXME("(%s):%lx attribute(s) not implemented.\n", lpFileName,attributes);
860 if (-1==chmod(full_name.long_name,buf.st_mode))
862 if(GetDriveTypeA(lpFileName) == DRIVE_CDROM) {
863 SetLastError( ERROR_ACCESS_DENIED );
868 * FIXME: We don't return FALSE here because of differences between
869 * Linux and Windows privileges. Under Linux only the owner of
870 * the file is allowed to change file attributes. Under Windows,
871 * applications expect that if you can write to a file, you can also
872 * change its attributes (see GENERIC_WRITE). We could try to be
873 * clever here but that would break multi-user installations where
874 * users share read-only DLLs. This is because some installers like
875 * to change attributes of already installed DLLs.
877 FIXME("Couldn't set file attributes for existing file \"%s\".\n"
878 "Check permissions or set VFAT \"quiet\" mount flag\n", full_name.long_name);
884 /**************************************************************************
885 * SetFileAttributesW (KERNEL32.@)
887 BOOL WINAPI SetFileAttributesW(LPCWSTR lpFileName, DWORD attributes)
890 DWORD len = WideCharToMultiByte( CP_ACP, 0, lpFileName, -1, NULL, 0, NULL, NULL );
891 LPSTR afn = HeapAlloc( GetProcessHeap(), 0, len );
893 WideCharToMultiByte( CP_ACP, 0, lpFileName, -1, afn, len, NULL, NULL );
894 res = SetFileAttributesA( afn, attributes );
895 HeapFree( GetProcessHeap(), 0, afn );
900 /***********************************************************************
901 * GetFileSize (KERNEL32.@)
903 DWORD WINAPI GetFileSize( HANDLE hFile, LPDWORD filesizehigh )
905 BY_HANDLE_FILE_INFORMATION info;
906 if (!GetFileInformationByHandle( hFile, &info )) return -1;
907 if (filesizehigh) *filesizehigh = info.nFileSizeHigh;
908 return info.nFileSizeLow;
912 /***********************************************************************
913 * GetFileTime (KERNEL32.@)
915 BOOL WINAPI GetFileTime( HANDLE hFile, FILETIME *lpCreationTime,
916 FILETIME *lpLastAccessTime,
917 FILETIME *lpLastWriteTime )
919 BY_HANDLE_FILE_INFORMATION info;
920 if (!GetFileInformationByHandle( hFile, &info )) return FALSE;
921 if (lpCreationTime) *lpCreationTime = info.ftCreationTime;
922 if (lpLastAccessTime) *lpLastAccessTime = info.ftLastAccessTime;
923 if (lpLastWriteTime) *lpLastWriteTime = info.ftLastWriteTime;
927 /***********************************************************************
928 * CompareFileTime (KERNEL32.@)
930 INT WINAPI CompareFileTime( LPFILETIME x, LPFILETIME y )
932 if (!x || !y) return -1;
934 if (x->dwHighDateTime > y->dwHighDateTime)
936 if (x->dwHighDateTime < y->dwHighDateTime)
938 if (x->dwLowDateTime > y->dwLowDateTime)
940 if (x->dwLowDateTime < y->dwLowDateTime)
945 /***********************************************************************
946 * FILE_GetTempFileName : utility for GetTempFileName
948 static UINT FILE_GetTempFileName( LPCSTR path, LPCSTR prefix, UINT unique,
949 LPSTR buffer, BOOL isWin16 )
951 static UINT unique_temp;
952 DOS_FULL_NAME full_name;
957 if ( !path || !prefix || !buffer ) return 0;
959 if (!unique_temp) unique_temp = time(NULL) & 0xffff;
960 num = unique ? (unique & 0xffff) : (unique_temp++ & 0xffff);
962 strcpy( buffer, path );
963 p = buffer + strlen(buffer);
965 /* add a \, if there isn't one and path is more than just the drive letter ... */
966 if ( !((strlen(buffer) == 2) && (buffer[1] == ':'))
967 && ((p == buffer) || (p[-1] != '\\'))) *p++ = '\\';
969 if (isWin16) *p++ = '~';
970 for (i = 3; (i > 0) && (*prefix); i--) *p++ = *prefix++;
971 sprintf( p, "%04x.tmp", num );
973 /* Now try to create it */
979 HANDLE handle = CreateFileA( buffer, GENERIC_WRITE, 0, NULL,
980 CREATE_NEW, FILE_ATTRIBUTE_NORMAL, 0 );
981 if (handle != INVALID_HANDLE_VALUE)
982 { /* We created it */
983 TRACE("created %s\n",
985 CloseHandle( handle );
988 if (GetLastError() != ERROR_FILE_EXISTS)
989 break; /* No need to go on */
991 sprintf( p, "%04x.tmp", num );
992 } while (num != (unique & 0xffff));
995 /* Get the full path name */
997 if (DOSFS_GetFullName( buffer, FALSE, &full_name ))
999 /* Check if we have write access in the directory */
1000 if ((p = strrchr( full_name.long_name, '/' ))) *p = '\0';
1001 if (access( full_name.long_name, W_OK ) == -1)
1002 WARN("returns '%s', which doesn't seem to be writeable.\n",
1005 TRACE("returning %s\n", buffer );
1006 return unique ? unique : num;
1010 /***********************************************************************
1011 * GetTempFileNameA (KERNEL32.@)
1013 UINT WINAPI GetTempFileNameA( LPCSTR path, LPCSTR prefix, UINT unique,
1016 return FILE_GetTempFileName(path, prefix, unique, buffer, FALSE);
1019 /***********************************************************************
1020 * GetTempFileNameW (KERNEL32.@)
1022 UINT WINAPI GetTempFileNameW( LPCWSTR path, LPCWSTR prefix, UINT unique,
1025 LPSTR patha,prefixa;
1029 if (!path) return 0;
1030 patha = HEAP_strdupWtoA( GetProcessHeap(), 0, path );
1031 prefixa = HEAP_strdupWtoA( GetProcessHeap(), 0, prefix );
1032 ret = FILE_GetTempFileName( patha, prefixa, unique, buffera, FALSE );
1033 MultiByteToWideChar( CP_ACP, 0, buffera, -1, buffer, MAX_PATH );
1034 HeapFree( GetProcessHeap(), 0, patha );
1035 HeapFree( GetProcessHeap(), 0, prefixa );
1040 /***********************************************************************
1041 * GetTempFileName (KERNEL.97)
1043 UINT16 WINAPI GetTempFileName16( BYTE drive, LPCSTR prefix, UINT16 unique,
1048 if (!(drive & ~TF_FORCEDRIVE)) /* drive 0 means current default drive */
1049 drive |= DRIVE_GetCurrentDrive() + 'A';
1051 if ((drive & TF_FORCEDRIVE) &&
1052 !DRIVE_IsValid( toupper(drive & ~TF_FORCEDRIVE) - 'A' ))
1054 drive &= ~TF_FORCEDRIVE;
1055 WARN("invalid drive %d specified\n", drive );
1058 if (drive & TF_FORCEDRIVE)
1059 sprintf(temppath,"%c:", drive & ~TF_FORCEDRIVE );
1061 GetTempPathA( 132, temppath );
1062 return (UINT16)FILE_GetTempFileName( temppath, prefix, unique, buffer, TRUE );
1065 /***********************************************************************
1068 * Implementation of OpenFile16() and OpenFile32().
1070 static HFILE FILE_DoOpenFile( LPCSTR name, OFSTRUCT *ofs, UINT mode,
1076 WORD filedatetime[2];
1077 DOS_FULL_NAME full_name;
1078 DWORD access, sharing;
1081 if (!ofs) return HFILE_ERROR;
1083 TRACE("%s %s %s %s%s%s%s%s%s%s%s%s\n",name,
1084 ((mode & 0x3 )==OF_READ)?"OF_READ":
1085 ((mode & 0x3 )==OF_WRITE)?"OF_WRITE":
1086 ((mode & 0x3 )==OF_READWRITE)?"OF_READWRITE":"unknown",
1087 ((mode & 0x70 )==OF_SHARE_COMPAT)?"OF_SHARE_COMPAT":
1088 ((mode & 0x70 )==OF_SHARE_DENY_NONE)?"OF_SHARE_DENY_NONE":
1089 ((mode & 0x70 )==OF_SHARE_DENY_READ)?"OF_SHARE_DENY_READ":
1090 ((mode & 0x70 )==OF_SHARE_DENY_WRITE)?"OF_SHARE_DENY_WRITE":
1091 ((mode & 0x70 )==OF_SHARE_EXCLUSIVE)?"OF_SHARE_EXCLUSIVE":"unknown",
1092 ((mode & OF_PARSE )==OF_PARSE)?"OF_PARSE ":"",
1093 ((mode & OF_DELETE )==OF_DELETE)?"OF_DELETE ":"",
1094 ((mode & OF_VERIFY )==OF_VERIFY)?"OF_VERIFY ":"",
1095 ((mode & OF_SEARCH )==OF_SEARCH)?"OF_SEARCH ":"",
1096 ((mode & OF_CANCEL )==OF_CANCEL)?"OF_CANCEL ":"",
1097 ((mode & OF_CREATE )==OF_CREATE)?"OF_CREATE ":"",
1098 ((mode & OF_PROMPT )==OF_PROMPT)?"OF_PROMPT ":"",
1099 ((mode & OF_EXIST )==OF_EXIST)?"OF_EXIST ":"",
1100 ((mode & OF_REOPEN )==OF_REOPEN)?"OF_REOPEN ":""
1104 ofs->cBytes = sizeof(OFSTRUCT);
1106 if (mode & OF_REOPEN) name = ofs->szPathName;
1109 ERR("called with `name' set to NULL ! Please debug.\n");
1113 TRACE("%s %04x\n", name, mode );
1115 /* the watcom 10.6 IDE relies on a valid path returned in ofs->szPathName
1116 Are there any cases where getting the path here is wrong?
1117 Uwe Bonnes 1997 Apr 2 */
1118 if (!GetFullPathNameA( name, sizeof(ofs->szPathName),
1119 ofs->szPathName, NULL )) goto error;
1120 FILE_ConvertOFMode( mode, &access, &sharing );
1122 /* OF_PARSE simply fills the structure */
1124 if (mode & OF_PARSE)
1126 ofs->fFixedDisk = (GetDriveType16( ofs->szPathName[0]-'A' )
1127 != DRIVE_REMOVABLE);
1128 TRACE("(%s): OF_PARSE, res = '%s'\n",
1129 name, ofs->szPathName );
1133 /* OF_CREATE is completely different from all other options, so
1136 if (mode & OF_CREATE)
1138 if ((handle = CreateFileA( name, GENERIC_READ | GENERIC_WRITE,
1139 sharing, NULL, CREATE_ALWAYS,
1140 FILE_ATTRIBUTE_NORMAL, 0 ))== INVALID_HANDLE_VALUE)
1145 /* If OF_SEARCH is set, ignore the given path */
1147 if ((mode & OF_SEARCH) && !(mode & OF_REOPEN))
1149 /* First try the file name as is */
1150 if (DOSFS_GetFullName( name, TRUE, &full_name )) goto found;
1151 /* Now remove the path */
1152 if (name[0] && (name[1] == ':')) name += 2;
1153 if ((p = strrchr( name, '\\' ))) name = p + 1;
1154 if ((p = strrchr( name, '/' ))) name = p + 1;
1155 if (!name[0]) goto not_found;
1158 /* Now look for the file */
1160 if (!DIR_SearchPath( NULL, name, NULL, &full_name, win32 )) goto not_found;
1163 TRACE("found %s = %s\n",
1164 full_name.long_name, full_name.short_name );
1165 lstrcpynA( ofs->szPathName, full_name.short_name,
1166 sizeof(ofs->szPathName) );
1168 if (mode & OF_SHARE_EXCLUSIVE)
1169 /* Some InstallShield version uses OF_SHARE_EXCLUSIVE
1170 on the file <tempdir>/_ins0432._mp to determine how
1171 far installation has proceeded.
1172 _ins0432._mp is an executable and while running the
1173 application expects the open with OF_SHARE_ to fail*/
1175 As our loader closes the files after loading the executable,
1176 we can't find the running executable with FILE_InUse.
1177 The loader should keep the file open, as Windows does that, too.
1180 char *last = strrchr(full_name.long_name,'/');
1182 last = full_name.long_name - 1;
1183 if (GetModuleHandle16(last+1))
1185 TRACE("Denying shared open for %s\n",full_name.long_name);
1190 if (mode & OF_DELETE)
1192 if (unlink( full_name.long_name ) == -1) goto not_found;
1193 TRACE("(%s): OF_DELETE return = OK\n", name);
1197 handle = FILE_CreateFile( full_name.long_name, access, sharing,
1198 NULL, OPEN_EXISTING, 0, 0,
1199 DRIVE_GetFlags(full_name.drive) & DRIVE_FAIL_READ_ONLY,
1200 GetDriveTypeA( full_name.short_name ) );
1201 if (!handle) goto not_found;
1203 GetFileTime( handle, NULL, NULL, &filetime );
1204 FileTimeToDosDateTime( &filetime, &filedatetime[0], &filedatetime[1] );
1205 if ((mode & OF_VERIFY) && (mode & OF_REOPEN))
1207 if (memcmp( ofs->reserved, filedatetime, sizeof(ofs->reserved) ))
1209 CloseHandle( handle );
1210 WARN("(%s): OF_VERIFY failed\n", name );
1211 /* FIXME: what error here? */
1212 SetLastError( ERROR_FILE_NOT_FOUND );
1216 memcpy( ofs->reserved, filedatetime, sizeof(ofs->reserved) );
1218 success: /* We get here if the open was successful */
1219 TRACE("(%s): OK, return = %x\n", name, handle );
1222 hFileRet = (HFILE)handle;
1223 if (mode & OF_EXIST) /* Return the handle, but close it first */
1224 CloseHandle( handle );
1228 hFileRet = Win32HandleToDosFileHandle( handle );
1229 if (hFileRet == HFILE_ERROR16) goto error;
1230 if (mode & OF_EXIST) /* Return the handle, but close it first */
1231 _lclose16( hFileRet );
1235 not_found: /* We get here if the file does not exist */
1236 WARN("'%s' not found or sharing violation\n", name );
1237 SetLastError( ERROR_FILE_NOT_FOUND );
1240 error: /* We get here if there was an error opening the file */
1241 ofs->nErrCode = GetLastError();
1242 WARN("(%s): return = HFILE_ERROR error= %d\n",
1243 name,ofs->nErrCode );
1248 /***********************************************************************
1249 * OpenFile (KERNEL.74)
1250 * OpenFileEx (KERNEL.360)
1252 HFILE16 WINAPI OpenFile16( LPCSTR name, OFSTRUCT *ofs, UINT16 mode )
1254 return FILE_DoOpenFile( name, ofs, mode, FALSE );
1258 /***********************************************************************
1259 * OpenFile (KERNEL32.@)
1261 HFILE WINAPI OpenFile( LPCSTR name, OFSTRUCT *ofs, UINT mode )
1263 return FILE_DoOpenFile( name, ofs, mode, TRUE );
1267 /***********************************************************************
1268 * FILE_InitProcessDosHandles
1270 * Allocates the default DOS handles for a process. Called either by
1271 * Win32HandleToDosFileHandle below or by the DOSVM stuff.
1273 static void FILE_InitProcessDosHandles( void )
1275 HANDLE cp = GetCurrentProcess();
1276 DuplicateHandle(cp, GetStdHandle(STD_INPUT_HANDLE), cp, &dos_handles[0],
1277 0, TRUE, DUPLICATE_SAME_ACCESS);
1278 DuplicateHandle(cp, GetStdHandle(STD_OUTPUT_HANDLE), cp, &dos_handles[1],
1279 0, TRUE, DUPLICATE_SAME_ACCESS);
1280 DuplicateHandle(cp, GetStdHandle(STD_ERROR_HANDLE), cp, &dos_handles[2],
1281 0, TRUE, DUPLICATE_SAME_ACCESS);
1282 DuplicateHandle(cp, GetStdHandle(STD_ERROR_HANDLE), cp, &dos_handles[3],
1283 0, TRUE, DUPLICATE_SAME_ACCESS);
1284 DuplicateHandle(cp, GetStdHandle(STD_ERROR_HANDLE), cp, &dos_handles[4],
1285 0, TRUE, DUPLICATE_SAME_ACCESS);
1288 /***********************************************************************
1289 * Win32HandleToDosFileHandle (KERNEL32.21)
1291 * Allocate a DOS handle for a Win32 handle. The Win32 handle is no
1292 * longer valid after this function (even on failure).
1294 * Note: this is not exactly right, since on Win95 the Win32 handles
1295 * are on top of DOS handles and we do it the other way
1296 * around. Should be good enough though.
1298 HFILE WINAPI Win32HandleToDosFileHandle( HANDLE handle )
1302 if (!handle || (handle == INVALID_HANDLE_VALUE))
1305 for (i = 5; i < DOS_TABLE_SIZE; i++)
1306 if (!dos_handles[i])
1308 dos_handles[i] = handle;
1309 TRACE("Got %d for h32 %d\n", i, handle );
1312 CloseHandle( handle );
1313 SetLastError( ERROR_TOO_MANY_OPEN_FILES );
1318 /***********************************************************************
1319 * DosFileHandleToWin32Handle (KERNEL32.20)
1321 * Return the Win32 handle for a DOS handle.
1323 * Note: this is not exactly right, since on Win95 the Win32 handles
1324 * are on top of DOS handles and we do it the other way
1325 * around. Should be good enough though.
1327 HANDLE WINAPI DosFileHandleToWin32Handle( HFILE handle )
1329 HFILE16 hfile = (HFILE16)handle;
1330 if (hfile < 5 && !dos_handles[hfile]) FILE_InitProcessDosHandles();
1331 if ((hfile >= DOS_TABLE_SIZE) || !dos_handles[hfile])
1333 SetLastError( ERROR_INVALID_HANDLE );
1334 return INVALID_HANDLE_VALUE;
1336 return dos_handles[hfile];
1340 /***********************************************************************
1341 * DisposeLZ32Handle (KERNEL32.22)
1343 * Note: this is not entirely correct, we should only close the
1344 * 32-bit handle and not the 16-bit one, but we cannot do
1345 * this because of the way our DOS handles are implemented.
1346 * It shouldn't break anything though.
1348 void WINAPI DisposeLZ32Handle( HANDLE handle )
1352 if (!handle || (handle == INVALID_HANDLE_VALUE)) return;
1354 for (i = 5; i < DOS_TABLE_SIZE; i++)
1355 if (dos_handles[i] == handle)
1358 CloseHandle( handle );
1364 /***********************************************************************
1367 * dup2() function for DOS handles.
1369 HFILE16 FILE_Dup2( HFILE16 hFile1, HFILE16 hFile2 )
1373 if (hFile1 < 5 && !dos_handles[hFile1]) FILE_InitProcessDosHandles();
1375 if ((hFile1 >= DOS_TABLE_SIZE) || (hFile2 >= DOS_TABLE_SIZE) || !dos_handles[hFile1])
1377 SetLastError( ERROR_INVALID_HANDLE );
1378 return HFILE_ERROR16;
1380 if (!DuplicateHandle( GetCurrentProcess(), dos_handles[hFile1],
1381 GetCurrentProcess(), &new_handle,
1382 0, FALSE, DUPLICATE_SAME_ACCESS ))
1383 return HFILE_ERROR16;
1384 if (dos_handles[hFile2]) CloseHandle( dos_handles[hFile2] );
1385 dos_handles[hFile2] = new_handle;
1390 /***********************************************************************
1391 * _lclose (KERNEL.81)
1393 HFILE16 WINAPI _lclose16( HFILE16 hFile )
1395 if ((hFile >= DOS_TABLE_SIZE) || !dos_handles[hFile])
1397 SetLastError( ERROR_INVALID_HANDLE );
1398 return HFILE_ERROR16;
1400 TRACE("%d (handle32=%d)\n", hFile, dos_handles[hFile] );
1401 CloseHandle( dos_handles[hFile] );
1402 dos_handles[hFile] = 0;
1407 /***********************************************************************
1408 * _lclose (KERNEL32.@)
1410 HFILE WINAPI _lclose( HFILE hFile )
1412 TRACE("handle %d\n", hFile );
1413 return CloseHandle( (HANDLE)hFile ) ? 0 : HFILE_ERROR;
1416 /***********************************************************************
1417 * GetOverlappedResult (KERNEL32.@)
1419 * Check the result of an Asynchronous data transfer from a file.
1425 * If successful (and relevant) lpTransferred will hold the number of
1426 * bytes transferred during the async operation.
1430 * Currently only works for WaitCommEvent, ReadFile, WriteFile
1431 * with communications ports.
1434 BOOL WINAPI GetOverlappedResult(
1435 HANDLE hFile, /* [in] handle of file to check on */
1436 LPOVERLAPPED lpOverlapped, /* [in/out] pointer to overlapped */
1437 LPDWORD lpTransferred, /* [in/out] number of bytes transferred */
1438 BOOL bWait /* [in] wait for the transfer to complete ? */
1442 TRACE("(%d %p %p %x)\n", hFile, lpOverlapped, lpTransferred, bWait);
1444 if(lpOverlapped==NULL)
1446 ERR("lpOverlapped was null\n");
1449 if(!lpOverlapped->hEvent)
1451 ERR("lpOverlapped->hEvent was null\n");
1456 TRACE("waiting on %p\n",lpOverlapped);
1457 r = WaitForSingleObjectEx(lpOverlapped->hEvent, bWait?INFINITE:0, TRUE);
1458 TRACE("wait on %p returned %ld\n",lpOverlapped,r);
1459 } while (r==STATUS_USER_APC);
1462 *lpTransferred = lpOverlapped->InternalHigh;
1464 SetLastError ( lpOverlapped->Internal == STATUS_PENDING ?
1465 ERROR_IO_INCOMPLETE : RtlNtStatusToDosError ( lpOverlapped->Internal ) );
1467 return (r==WAIT_OBJECT_0);
1470 /***********************************************************************
1471 * CancelIo (KERNEL32.@)
1473 BOOL WINAPI CancelIo(HANDLE handle)
1475 async_private *ovp,*t;
1477 TRACE("handle = %x\n",handle);
1479 for (ovp = NtCurrentTeb()->pending_list; ovp; ovp = t)
1482 if ( ovp->handle == handle )
1483 cancel_async ( ovp );
1485 WaitForMultipleObjectsEx(0,NULL,FALSE,1,TRUE);
1489 /***********************************************************************
1490 * FILE_AsyncReadService (INTERNAL)
1492 * This function is called while the client is waiting on the
1493 * server, so we can't make any server calls here.
1495 static void FILE_AsyncReadService(async_private *ovp)
1497 async_fileio *fileio = (async_fileio*) ovp;
1498 LPOVERLAPPED lpOverlapped = fileio->lpOverlapped;
1500 int already = lpOverlapped->InternalHigh;
1502 TRACE("%p %p\n", lpOverlapped, fileio->buffer );
1504 /* check to see if the data is ready (non-blocking) */
1506 if ( fileio->fd_type == FD_TYPE_SOCKET )
1507 result = read (ovp->fd, &fileio->buffer[already], fileio->count - already);
1510 result = pread (ovp->fd, &fileio->buffer[already], fileio->count - already,
1511 OVERLAPPED_OFFSET (lpOverlapped) + already);
1512 if ((result < 0) && (errno == ESPIPE))
1513 result = read (ovp->fd, &fileio->buffer[already], fileio->count - already);
1516 if ( (result<0) && ((errno == EAGAIN) || (errno == EINTR)))
1518 TRACE("Deferred read %d\n",errno);
1523 /* check to see if the transfer is complete */
1526 r = FILE_GetNtStatus ();
1530 lpOverlapped->InternalHigh += result;
1531 TRACE("read %d more bytes %ld/%d so far\n",result,lpOverlapped->InternalHigh,fileio->count);
1533 if(lpOverlapped->InternalHigh >= fileio->count || fileio->fd_type == FD_TYPE_SOCKET )
1539 lpOverlapped->Internal = r;
1542 /***********************************************************************
1543 * FILE_ReadFileEx (INTERNAL)
1545 static BOOL FILE_ReadFileEx(HANDLE hFile, LPVOID buffer, DWORD bytesToRead,
1546 LPOVERLAPPED overlapped,
1547 LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine,
1555 TRACE("file %d to buf %p num %ld %p func %p\n",
1556 hFile, buffer, bytesToRead, overlapped, lpCompletionRoutine);
1558 /* check that there is an overlapped struct */
1559 if (overlapped==NULL)
1561 SetLastError(ERROR_INVALID_PARAMETER);
1565 fd = FILE_GetUnixHandleType ( hFile, GENERIC_READ, &type, &flags);
1568 WARN ( "Couldn't get FD\n" );
1572 ovp = (async_fileio*) HeapAlloc(GetProcessHeap(), 0, sizeof (async_fileio));
1575 TRACE("HeapAlloc Failed\n");
1576 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1580 ovp->async.ops = ( lpCompletionRoutine ? &fileio_async_ops : &fileio_nocomp_async_ops );
1581 ovp->async.handle = hFile;
1583 ovp->async.type = ASYNC_TYPE_READ;
1584 ovp->async.func = FILE_AsyncReadService;
1585 ovp->async.event = hEvent;
1586 ovp->lpOverlapped = overlapped;
1587 ovp->count = bytesToRead;
1588 ovp->completion_func = lpCompletionRoutine;
1589 ovp->buffer = buffer;
1590 ovp->fd_type = type;
1592 return !register_new_async (&ovp->async);
1600 /***********************************************************************
1601 * ReadFileEx (KERNEL32.@)
1603 BOOL WINAPI ReadFileEx(HANDLE hFile, LPVOID buffer, DWORD bytesToRead,
1604 LPOVERLAPPED overlapped,
1605 LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine)
1607 overlapped->InternalHigh = 0;
1608 return FILE_ReadFileEx(hFile,buffer,bytesToRead,overlapped,lpCompletionRoutine, INVALID_HANDLE_VALUE);
1611 static BOOL FILE_TimeoutRead(HANDLE hFile, LPVOID buffer, DWORD bytesToRead, LPDWORD bytesRead)
1616 TRACE("%d %p %ld %p\n", hFile, buffer, bytesToRead, bytesRead );
1618 ZeroMemory(&ov, sizeof (OVERLAPPED));
1619 if(STATUS_SUCCESS==NtCreateEvent(&ov.hEvent, SYNCHRONIZE, NULL, 0, 0))
1621 if(FILE_ReadFileEx(hFile, buffer, bytesToRead, &ov, NULL, ov.hEvent))
1623 r = GetOverlappedResult(hFile, &ov, bytesRead, TRUE);
1626 CloseHandle(ov.hEvent);
1630 /***********************************************************************
1631 * ReadFile (KERNEL32.@)
1633 BOOL WINAPI ReadFile( HANDLE hFile, LPVOID buffer, DWORD bytesToRead,
1634 LPDWORD bytesRead, LPOVERLAPPED overlapped )
1636 int unix_handle, result, flags;
1639 TRACE("%d %p %ld %p %p\n", hFile, buffer, bytesToRead,
1640 bytesRead, overlapped );
1642 if (bytesRead) *bytesRead = 0; /* Do this before anything else */
1643 if (!bytesToRead) return TRUE;
1645 unix_handle = FILE_GetUnixHandleType( hFile, GENERIC_READ, &type, &flags );
1647 if (flags & FD_FLAG_OVERLAPPED)
1649 if (unix_handle == -1) return FALSE;
1650 if ( (overlapped==NULL) || NtResetEvent( overlapped->hEvent, NULL ) )
1652 TRACE("Overlapped not specified or invalid event flag\n");
1654 SetLastError(ERROR_INVALID_PARAMETER);
1659 overlapped->InternalHigh = 0;
1661 if(!FILE_ReadFileEx(hFile, buffer, bytesToRead, overlapped, NULL, overlapped->hEvent))
1664 if ( !GetOverlappedResult (hFile, overlapped, bytesRead, FALSE) )
1666 if ( GetLastError() == ERROR_IO_INCOMPLETE )
1667 SetLastError ( ERROR_IO_PENDING );
1673 if (flags & FD_FLAG_TIMEOUT)
1676 return FILE_TimeoutRead(hFile, buffer, bytesToRead, bytesRead);
1681 return SMB_ReadFile(hFile, buffer, bytesToRead, bytesRead, NULL);
1683 case FD_TYPE_CONSOLE:
1684 return FILE_ReadConsole(hFile, buffer, bytesToRead, bytesRead, NULL);
1686 case FD_TYPE_DEFAULT:
1687 /* normal unix files */
1688 if (unix_handle == -1) return FALSE;
1691 DWORD highOffset = overlapped->OffsetHigh;
1692 if ( (INVALID_SET_FILE_POINTER == SetFilePointer(hFile, overlapped->Offset,
1693 &highOffset, FILE_BEGIN)) &&
1694 (GetLastError() != NO_ERROR) )
1703 if (unix_handle == -1)
1708 SetLastError(ERROR_INVALID_PARAMETER);
1714 /* code for synchronous reads */
1715 while ((result = read( unix_handle, buffer, bytesToRead )) == -1)
1717 if ((errno == EAGAIN) || (errno == EINTR)) continue;
1718 if ((errno == EFAULT) && !IsBadWritePtr( buffer, bytesToRead )) continue;
1722 close( unix_handle );
1723 if (result == -1) return FALSE;
1724 if (bytesRead) *bytesRead = result;
1729 /***********************************************************************
1730 * FILE_AsyncWriteService (INTERNAL)
1732 * This function is called while the client is waiting on the
1733 * server, so we can't make any server calls here.
1735 static void FILE_AsyncWriteService(struct async_private *ovp)
1737 async_fileio *fileio = (async_fileio *) ovp;
1738 LPOVERLAPPED lpOverlapped = fileio->lpOverlapped;
1740 int already = lpOverlapped->InternalHigh;
1742 TRACE("(%p %p)\n",lpOverlapped,fileio->buffer);
1744 /* write some data (non-blocking) */
1746 if ( fileio->fd_type == FD_TYPE_SOCKET )
1747 result = write(ovp->fd, &fileio->buffer[already], fileio->count - already);
1750 result = pwrite(ovp->fd, &fileio->buffer[already], fileio->count - already,
1751 OVERLAPPED_OFFSET (lpOverlapped) + already);
1752 if ((result < 0) && (errno == ESPIPE))
1753 result = write(ovp->fd, &fileio->buffer[already], fileio->count - already);
1756 if ( (result<0) && ((errno == EAGAIN) || (errno == EINTR)))
1762 /* check to see if the transfer is complete */
1765 r = FILE_GetNtStatus ();
1769 lpOverlapped->InternalHigh += result;
1771 TRACE("wrote %d more bytes %ld/%d so far\n",result,lpOverlapped->InternalHigh,fileio->count);
1773 if(lpOverlapped->InternalHigh < fileio->count)
1779 lpOverlapped->Internal = r;
1782 /***********************************************************************
1785 static BOOL FILE_WriteFileEx(HANDLE hFile, LPCVOID buffer, DWORD bytesToWrite,
1786 LPOVERLAPPED overlapped,
1787 LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine,
1795 TRACE("file %d to buf %p num %ld %p func %p handle %d\n",
1796 hFile, buffer, bytesToWrite, overlapped, lpCompletionRoutine, hEvent);
1798 if (overlapped == NULL)
1800 SetLastError(ERROR_INVALID_PARAMETER);
1804 fd = FILE_GetUnixHandleType ( hFile, GENERIC_WRITE, &type, &flags );
1807 TRACE( "Couldn't get FD\n" );
1811 ovp = (async_fileio*) HeapAlloc(GetProcessHeap(), 0, sizeof (async_fileio));
1814 TRACE("HeapAlloc Failed\n");
1815 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1819 ovp->async.ops = ( lpCompletionRoutine ? &fileio_async_ops : &fileio_nocomp_async_ops );
1820 ovp->async.handle = hFile;
1822 ovp->async.type = ASYNC_TYPE_WRITE;
1823 ovp->async.func = FILE_AsyncWriteService;
1824 ovp->lpOverlapped = overlapped;
1825 ovp->async.event = hEvent;
1826 ovp->buffer = (LPVOID) buffer;
1827 ovp->count = bytesToWrite;
1828 ovp->completion_func = lpCompletionRoutine;
1829 ovp->fd_type = type;
1831 return !register_new_async (&ovp->async);
1838 /***********************************************************************
1839 * WriteFileEx (KERNEL32.@)
1841 BOOL WINAPI WriteFileEx(HANDLE hFile, LPCVOID buffer, DWORD bytesToWrite,
1842 LPOVERLAPPED overlapped,
1843 LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine)
1845 overlapped->InternalHigh = 0;
1847 return FILE_WriteFileEx(hFile, buffer, bytesToWrite, overlapped, lpCompletionRoutine, INVALID_HANDLE_VALUE);
1850 /***********************************************************************
1851 * WriteFile (KERNEL32.@)
1853 BOOL WINAPI WriteFile( HANDLE hFile, LPCVOID buffer, DWORD bytesToWrite,
1854 LPDWORD bytesWritten, LPOVERLAPPED overlapped )
1856 int unix_handle, result, flags;
1859 TRACE("%d %p %ld %p %p\n", hFile, buffer, bytesToWrite,
1860 bytesWritten, overlapped );
1862 if (bytesWritten) *bytesWritten = 0; /* Do this before anything else */
1863 if (!bytesToWrite) return TRUE;
1865 unix_handle = FILE_GetUnixHandleType( hFile, GENERIC_WRITE, &type, &flags );
1867 if (flags & FD_FLAG_OVERLAPPED)
1869 if (unix_handle == -1) return FALSE;
1870 if ( (overlapped==NULL) || NtResetEvent( overlapped->hEvent, NULL ) )
1872 TRACE("Overlapped not specified or invalid event flag\n");
1874 SetLastError(ERROR_INVALID_PARAMETER);
1879 overlapped->InternalHigh = 0;
1881 if(!FILE_WriteFileEx(hFile, buffer, bytesToWrite, overlapped, NULL, overlapped->hEvent))
1884 if ( !GetOverlappedResult (hFile, overlapped, bytesWritten, FALSE) )
1886 if ( GetLastError() == ERROR_IO_INCOMPLETE )
1887 SetLastError ( ERROR_IO_PENDING );
1896 case FD_TYPE_CONSOLE:
1897 TRACE("%d %s %ld %p %p\n", hFile, debugstr_an(buffer, bytesToWrite), bytesToWrite,
1898 bytesWritten, overlapped );
1899 return FILE_WriteConsole(hFile, buffer, bytesToWrite, bytesWritten, NULL);
1901 case FD_TYPE_DEFAULT:
1902 if (unix_handle == -1) return FALSE;
1906 DWORD highOffset = overlapped->OffsetHigh;
1907 if ( (INVALID_SET_FILE_POINTER == SetFilePointer(hFile, overlapped->Offset,
1908 &highOffset, FILE_BEGIN)) &&
1909 (GetLastError() != NO_ERROR) )
1918 if (unix_handle == -1)
1923 SetLastError(ERROR_INVALID_PARAMETER);
1929 /* synchronous file write */
1930 while ((result = write( unix_handle, buffer, bytesToWrite )) == -1)
1932 if ((errno == EAGAIN) || (errno == EINTR)) continue;
1933 if ((errno == EFAULT) && !IsBadReadPtr( buffer, bytesToWrite )) continue;
1934 if (errno == ENOSPC)
1935 SetLastError( ERROR_DISK_FULL );
1940 close( unix_handle );
1941 if (result == -1) return FALSE;
1942 if (bytesWritten) *bytesWritten = result;
1947 /***********************************************************************
1948 * _hread (KERNEL.349)
1950 LONG WINAPI WIN16_hread( HFILE16 hFile, SEGPTR buffer, LONG count )
1954 TRACE("%d %08lx %ld\n",
1955 hFile, (DWORD)buffer, count );
1957 /* Some programs pass a count larger than the allocated buffer */
1958 maxlen = GetSelectorLimit16( SELECTOROF(buffer) ) - OFFSETOF(buffer) + 1;
1959 if (count > maxlen) count = maxlen;
1960 return _lread((HFILE)DosFileHandleToWin32Handle(hFile), MapSL(buffer), count );
1964 /***********************************************************************
1965 * _lread (KERNEL.82)
1967 UINT16 WINAPI WIN16_lread( HFILE16 hFile, SEGPTR buffer, UINT16 count )
1969 return (UINT16)WIN16_hread( hFile, buffer, (LONG)count );
1973 /***********************************************************************
1974 * _lread (KERNEL32.@)
1976 UINT WINAPI _lread( HFILE handle, LPVOID buffer, UINT count )
1979 if (!ReadFile( (HANDLE)handle, buffer, count, &result, NULL )) return -1;
1984 /***********************************************************************
1985 * _lread16 (KERNEL.82)
1987 UINT16 WINAPI _lread16( HFILE16 hFile, LPVOID buffer, UINT16 count )
1989 return (UINT16)_lread((HFILE)DosFileHandleToWin32Handle(hFile), buffer, (LONG)count );
1993 /***********************************************************************
1994 * _lcreat (KERNEL.83)
1996 HFILE16 WINAPI _lcreat16( LPCSTR path, INT16 attr )
1998 return Win32HandleToDosFileHandle( (HANDLE)_lcreat( path, attr ) );
2002 /***********************************************************************
2003 * _lcreat (KERNEL32.@)
2005 HFILE WINAPI _lcreat( LPCSTR path, INT attr )
2007 /* Mask off all flags not explicitly allowed by the doc */
2008 attr &= FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM;
2009 TRACE("%s %02x\n", path, attr );
2010 return (HFILE)CreateFileA( path, GENERIC_READ | GENERIC_WRITE,
2011 FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
2012 CREATE_ALWAYS, attr, 0 );
2016 /***********************************************************************
2017 * SetFilePointer (KERNEL32.@)
2019 DWORD WINAPI SetFilePointer( HANDLE hFile, LONG distance, LONG *highword,
2022 DWORD ret = INVALID_SET_FILE_POINTER;
2024 TRACE("handle %d offset %ld high %ld origin %ld\n",
2025 hFile, distance, highword?*highword:0, method );
2027 SERVER_START_REQ( set_file_pointer )
2029 req->handle = hFile;
2030 req->low = distance;
2031 req->high = highword ? *highword : (distance >= 0) ? 0 : -1;
2032 /* FIXME: assumes 1:1 mapping between Windows and Unix seek constants */
2033 req->whence = method;
2035 if (!wine_server_call_err( req ))
2037 ret = reply->new_low;
2038 if (highword) *highword = reply->new_high;
2046 /***********************************************************************
2047 * _llseek (KERNEL.84)
2050 * Seeking before the start of the file should be allowed for _llseek16,
2051 * but cause subsequent I/O operations to fail (cf. interrupt list)
2054 LONG WINAPI _llseek16( HFILE16 hFile, LONG lOffset, INT16 nOrigin )
2056 return SetFilePointer( DosFileHandleToWin32Handle(hFile), lOffset, NULL, nOrigin );
2060 /***********************************************************************
2061 * _llseek (KERNEL32.@)
2063 LONG WINAPI _llseek( HFILE hFile, LONG lOffset, INT nOrigin )
2065 return SetFilePointer( (HANDLE)hFile, lOffset, NULL, nOrigin );
2069 /***********************************************************************
2070 * _lopen (KERNEL.85)
2072 HFILE16 WINAPI _lopen16( LPCSTR path, INT16 mode )
2074 return Win32HandleToDosFileHandle( (HANDLE)_lopen( path, mode ) );
2078 /***********************************************************************
2079 * _lopen (KERNEL32.@)
2081 HFILE WINAPI _lopen( LPCSTR path, INT mode )
2083 DWORD access, sharing;
2085 TRACE("('%s',%04x)\n", path, mode );
2086 FILE_ConvertOFMode( mode, &access, &sharing );
2087 return (HFILE)CreateFileA( path, access, sharing, NULL, OPEN_EXISTING, 0, 0 );
2091 /***********************************************************************
2092 * _lwrite (KERNEL.86)
2094 UINT16 WINAPI _lwrite16( HFILE16 hFile, LPCSTR buffer, UINT16 count )
2096 return (UINT16)_hwrite( (HFILE)DosFileHandleToWin32Handle(hFile), buffer, (LONG)count );
2099 /***********************************************************************
2100 * _lwrite (KERNEL32.@)
2102 UINT WINAPI _lwrite( HFILE hFile, LPCSTR buffer, UINT count )
2104 return (UINT)_hwrite( hFile, buffer, (LONG)count );
2108 /***********************************************************************
2109 * _hread16 (KERNEL.349)
2111 LONG WINAPI _hread16( HFILE16 hFile, LPVOID buffer, LONG count)
2113 return _lread( (HFILE)DosFileHandleToWin32Handle(hFile), buffer, count );
2117 /***********************************************************************
2118 * _hread (KERNEL32.@)
2120 LONG WINAPI _hread( HFILE hFile, LPVOID buffer, LONG count)
2122 return _lread( hFile, buffer, count );
2126 /***********************************************************************
2127 * _hwrite (KERNEL.350)
2129 LONG WINAPI _hwrite16( HFILE16 hFile, LPCSTR buffer, LONG count )
2131 return _hwrite( (HFILE)DosFileHandleToWin32Handle(hFile), buffer, count );
2135 /***********************************************************************
2136 * _hwrite (KERNEL32.@)
2138 * experimentation yields that _lwrite:
2139 * o truncates the file at the current position with
2141 * o returns 0 on a 0 length write
2142 * o works with console handles
2145 LONG WINAPI _hwrite( HFILE handle, LPCSTR buffer, LONG count )
2149 TRACE("%d %p %ld\n", handle, buffer, count );
2153 /* Expand or truncate at current position */
2154 if (!SetEndOfFile( (HANDLE)handle )) return HFILE_ERROR;
2157 if (!WriteFile( (HANDLE)handle, buffer, count, &result, NULL ))
2163 /***********************************************************************
2164 * SetHandleCount (KERNEL.199)
2166 UINT16 WINAPI SetHandleCount16( UINT16 count )
2168 return SetHandleCount( count );
2172 /*************************************************************************
2173 * SetHandleCount (KERNEL32.@)
2175 UINT WINAPI SetHandleCount( UINT count )
2177 return min( 256, count );
2181 /***********************************************************************
2182 * FlushFileBuffers (KERNEL32.@)
2184 BOOL WINAPI FlushFileBuffers( HANDLE hFile )
2187 SERVER_START_REQ( flush_file )
2189 req->handle = hFile;
2190 ret = !wine_server_call_err( req );
2197 /**************************************************************************
2198 * SetEndOfFile (KERNEL32.@)
2200 BOOL WINAPI SetEndOfFile( HANDLE hFile )
2203 SERVER_START_REQ( truncate_file )
2205 req->handle = hFile;
2206 ret = !wine_server_call_err( req );
2213 /***********************************************************************
2214 * DeleteFile (KERNEL.146)
2216 BOOL16 WINAPI DeleteFile16( LPCSTR path )
2218 return DeleteFileA( path );
2222 /***********************************************************************
2223 * DeleteFileA (KERNEL32.@)
2225 BOOL WINAPI DeleteFileA( LPCSTR path )
2227 DOS_FULL_NAME full_name;
2232 SetLastError(ERROR_INVALID_PARAMETER);
2235 TRACE("'%s'\n", path );
2239 ERR("Empty path passed\n");
2242 if (DOSFS_GetDevice( path ))
2244 WARN("cannot remove DOS device '%s'!\n", path);
2245 SetLastError( ERROR_FILE_NOT_FOUND );
2249 if (!DOSFS_GetFullName( path, TRUE, &full_name )) return FALSE;
2251 /* check if we are allowed to delete the source */
2252 hFile = FILE_CreateFile( full_name.long_name, GENERIC_READ|GENERIC_WRITE, 0,
2253 NULL, OPEN_EXISTING, 0, 0, TRUE,
2254 GetDriveTypeA( full_name.short_name ) );
2255 if (!hFile) return FALSE;
2257 if (unlink( full_name.long_name ) == -1)
2268 /***********************************************************************
2269 * DeleteFileW (KERNEL32.@)
2271 BOOL WINAPI DeleteFileW( LPCWSTR path )
2273 LPSTR xpath = HEAP_strdupWtoA( GetProcessHeap(), 0, path );
2274 BOOL ret = DeleteFileA( xpath );
2275 HeapFree( GetProcessHeap(), 0, xpath );
2280 /***********************************************************************
2281 * GetFileType (KERNEL32.@)
2283 DWORD WINAPI GetFileType( HANDLE hFile )
2285 DWORD ret = FILE_TYPE_UNKNOWN;
2286 SERVER_START_REQ( get_file_info )
2288 req->handle = hFile;
2289 if (!wine_server_call_err( req )) ret = reply->type;
2296 /* check if a file name is for an executable file (.exe or .com) */
2297 inline static BOOL is_executable( const char *name )
2299 int len = strlen(name);
2301 if (len < 4) return FALSE;
2302 return (!strcasecmp( name + len - 4, ".exe" ) ||
2303 !strcasecmp( name + len - 4, ".com" ));
2307 /***********************************************************************
2308 * FILE_AddBootRenameEntry
2310 * Adds an entry to the registry that is loaded when windows boots and
2311 * checks if there are some files to be removed or renamed/moved.
2312 * <fn1> has to be valid and <fn2> may be NULL. If both pointers are
2313 * non-NULL then the file is moved, otherwise it is deleted. The
2314 * entry of the registrykey is always appended with two zero
2315 * terminated strings. If <fn2> is NULL then the second entry is
2316 * simply a single 0-byte. Otherwise the second filename goes
2317 * there. The entries are prepended with \??\ before the path and the
2318 * second filename gets also a '!' as the first character if
2319 * MOVEFILE_REPLACE_EXISTING is set. After the final string another
2320 * 0-byte follows to indicate the end of the strings.
2322 * \??\D:\test\file1[0]
2323 * !\??\D:\test\file1_renamed[0]
2324 * \??\D:\Test|delete[0]
2325 * [0] <- file is to be deleted, second string empty
2326 * \??\D:\test\file2[0]
2327 * !\??\D:\test\file2_renamed[0]
2328 * [0] <- indicates end of strings
2331 * \??\D:\test\file1[0]
2332 * !\??\D:\test\file1_renamed[0]
2333 * \??\D:\Test|delete[0]
2334 * [0] <- file is to be deleted, second string empty
2335 * [0] <- indicates end of strings
2338 static BOOL FILE_AddBootRenameEntry( const char *fn1, const char *fn2, DWORD flags )
2340 static const char PreString[] = "\\??\\";
2341 static const char ValueName[] = "PendingFileRenameOperations";
2345 DWORD Type, len1, len2, l;
2347 BYTE *Buffer = NULL;
2349 if(RegCreateKeyA(HKEY_LOCAL_MACHINE, "SYSTEM\\CurrentControlSet\\Control\\Session Manager",
2350 &Reboot) != ERROR_SUCCESS)
2352 WARN("Error creating key for reboot managment [%s]\n",
2353 "SYSTEM\\CurrentControlSet\\Control\\Session Manager");
2357 l = strlen(PreString);
2358 len1 = strlen(fn1) + l + 1;
2361 len2 = strlen(fn2) + l + 1;
2362 if (flags & MOVEFILE_REPLACE_EXISTING) len2++; /* Plus 1 because of the leading '!' */
2364 else len2 = 1; /* minimum is the 0 byte for the empty second string */
2366 /* First we check if the key exists and if so how many bytes it already contains. */
2367 if (RegQueryValueExA(Reboot, ValueName, NULL, &Type, NULL, &DataSize) == ERROR_SUCCESS)
2369 if (Type != REG_MULTI_SZ) goto Quit;
2370 if (!(Buffer = HeapAlloc( GetProcessHeap(), 0, DataSize + len1 + len2 + 1 ))) goto Quit;
2371 if (RegQueryValueExA(Reboot, ValueName, NULL, &Type, Buffer, &DataSize) != ERROR_SUCCESS)
2373 if (DataSize) DataSize--; /* remove terminating null (will be added back later) */
2377 if (!(Buffer = HeapAlloc( GetProcessHeap(), 0, len1 + len2 + 1 ))) goto Quit;
2380 sprintf( Buffer + DataSize, "%s%s", PreString, fn1 );
2384 sprintf( Buffer + DataSize, "%s%s%s",
2385 (flags & MOVEFILE_REPLACE_EXISTING) ? "!" : "", PreString, fn2 );
2388 else Buffer[DataSize++] = 0;
2390 Buffer[DataSize++] = 0; /* add final null */
2391 rc = !RegSetValueExA( Reboot, ValueName, 0, REG_MULTI_SZ, Buffer, DataSize );
2394 if (Reboot) RegCloseKey(Reboot);
2395 if (Buffer) HeapFree( GetProcessHeap(), 0, Buffer );
2400 /**************************************************************************
2401 * MoveFileExA (KERNEL32.@)
2403 BOOL WINAPI MoveFileExA( LPCSTR fn1, LPCSTR fn2, DWORD flag )
2405 DOS_FULL_NAME full_name1, full_name2;
2408 TRACE("(%s,%s,%04lx)\n", fn1, fn2, flag);
2410 /* FIXME: <Gerhard W. Gruber>sparhawk@gmx.at
2411 In case of W9x and lesser this function should return 120 (ERROR_CALL_NOT_IMPLEMENTED)
2412 to be really compatible. Most programs wont have any problems though. In case
2413 you encounter one, this is what you should return here. I don't know what's up
2414 with NT 3.5. Is this function available there or not?
2415 Does anybody really care about 3.5? :)
2418 /* Filename1 has to be always set to a valid path. Filename2 may be NULL
2419 if the source file has to be deleted.
2422 SetLastError(ERROR_INVALID_PARAMETER);
2426 /* This function has to be run through in order to process the name properly.
2427 If the BOOTDELAY flag is set, the file doesn't need to exist though. At least
2428 that is the behaviour on NT 4.0. The operation accepts the filenames as
2429 they are given but it can't reply with a reasonable returncode. Success
2430 means in that case success for entering the values into the registry.
2432 if(!DOSFS_GetFullName( fn1, TRUE, &full_name1 ))
2434 if(!(flag & MOVEFILE_DELAY_UNTIL_REBOOT))
2438 if (fn2) /* !fn2 means delete fn1 */
2440 if (DOSFS_GetFullName( fn2, TRUE, &full_name2 ))
2442 if(!(flag & MOVEFILE_DELAY_UNTIL_REBOOT))
2444 /* target exists, check if we may overwrite */
2445 if (!(flag & MOVEFILE_REPLACE_EXISTING))
2447 /* FIXME: Use right error code */
2448 SetLastError( ERROR_ACCESS_DENIED );
2455 if (!DOSFS_GetFullName( fn2, FALSE, &full_name2 ))
2457 if(!(flag & MOVEFILE_DELAY_UNTIL_REBOOT))
2462 /* Source name and target path are valid */
2464 if (flag & MOVEFILE_DELAY_UNTIL_REBOOT)
2466 /* FIXME: (bon@elektron.ikp.physik.th-darmstadt.de 970706)
2467 Perhaps we should queue these command and execute it
2468 when exiting... What about using on_exit(2)
2470 FIXME("Please move existing file '%s' to file '%s' when Wine has finished\n",
2472 return FILE_AddBootRenameEntry( fn1, fn2, flag );
2475 /* check if we are allowed to delete the source */
2476 hFile = FILE_CreateFile( full_name1.long_name, GENERIC_READ|GENERIC_WRITE, 0,
2477 NULL, OPEN_EXISTING, 0, 0, TRUE,
2478 GetDriveTypeA( full_name1.short_name ) );
2479 if (!hFile) return FALSE;
2482 /* check, if we are allowed to delete the destination,
2483 ** (but the file not being there is fine) */
2484 hFile = FILE_CreateFile( full_name2.long_name, GENERIC_READ|GENERIC_WRITE, 0,
2485 NULL, OPEN_EXISTING, 0, 0, TRUE,
2486 GetDriveTypeA( full_name2.short_name ) );
2487 if(!hFile && GetLastError() != ERROR_FILE_NOT_FOUND) return FALSE;
2490 if (full_name1.drive != full_name2.drive)
2492 /* use copy, if allowed */
2493 if (!(flag & MOVEFILE_COPY_ALLOWED))
2495 /* FIXME: Use right error code */
2496 SetLastError( ERROR_FILE_EXISTS );
2499 return CopyFileA( fn1, fn2, !(flag & MOVEFILE_REPLACE_EXISTING) );
2501 if (rename( full_name1.long_name, full_name2.long_name ) == -1)
2506 if (is_executable( full_name1.long_name ) != is_executable( full_name2.long_name ))
2509 if (stat( full_name2.long_name, &fstat ) != -1)
2511 if (is_executable( full_name2.long_name ))
2512 /* set executable bit where read bit is set */
2513 fstat.st_mode |= (fstat.st_mode & 0444) >> 2;
2515 fstat.st_mode &= ~0111;
2516 chmod( full_name2.long_name, fstat.st_mode );
2521 else /* fn2 == NULL means delete source */
2523 if (flag & MOVEFILE_DELAY_UNTIL_REBOOT)
2525 if (flag & MOVEFILE_COPY_ALLOWED) {
2526 WARN("Illegal flag\n");
2527 SetLastError( ERROR_GEN_FAILURE );
2530 /* FIXME: (bon@elektron.ikp.physik.th-darmstadt.de 970706)
2531 Perhaps we should queue these command and execute it
2532 when exiting... What about using on_exit(2)
2534 FIXME("Please delete file '%s' when Wine has finished\n", fn1);
2535 return FILE_AddBootRenameEntry( fn1, NULL, flag );
2538 if (unlink( full_name1.long_name ) == -1)
2543 return TRUE; /* successfully deleted */
2547 /**************************************************************************
2548 * MoveFileExW (KERNEL32.@)
2550 BOOL WINAPI MoveFileExW( LPCWSTR fn1, LPCWSTR fn2, DWORD flag )
2552 LPSTR afn1 = HEAP_strdupWtoA( GetProcessHeap(), 0, fn1 );
2553 LPSTR afn2 = HEAP_strdupWtoA( GetProcessHeap(), 0, fn2 );
2554 BOOL res = MoveFileExA( afn1, afn2, flag );
2555 HeapFree( GetProcessHeap(), 0, afn1 );
2556 HeapFree( GetProcessHeap(), 0, afn2 );
2561 /**************************************************************************
2562 * MoveFileA (KERNEL32.@)
2564 * Move file or directory
2566 BOOL WINAPI MoveFileA( LPCSTR fn1, LPCSTR fn2 )
2568 DOS_FULL_NAME full_name1, full_name2;
2571 TRACE("(%s,%s)\n", fn1, fn2 );
2573 if (!DOSFS_GetFullName( fn1, TRUE, &full_name1 )) return FALSE;
2574 if (DOSFS_GetFullName( fn2, TRUE, &full_name2 )) {
2575 /* The new name must not already exist */
2576 SetLastError(ERROR_ALREADY_EXISTS);
2579 if (!DOSFS_GetFullName( fn2, FALSE, &full_name2 )) return FALSE;
2581 if (full_name1.drive == full_name2.drive) /* move */
2582 return MoveFileExA( fn1, fn2, MOVEFILE_COPY_ALLOWED );
2585 if (stat( full_name1.long_name, &fstat ))
2587 WARN("Invalid source file %s\n",
2588 full_name1.long_name);
2592 if (S_ISDIR(fstat.st_mode)) {
2593 /* No Move for directories across file systems */
2594 /* FIXME: Use right error code */
2595 SetLastError( ERROR_GEN_FAILURE );
2598 return CopyFileA(fn1, fn2, TRUE); /*fail, if exist */
2602 /**************************************************************************
2603 * MoveFileW (KERNEL32.@)
2605 BOOL WINAPI MoveFileW( LPCWSTR fn1, LPCWSTR fn2 )
2607 LPSTR afn1 = HEAP_strdupWtoA( GetProcessHeap(), 0, fn1 );
2608 LPSTR afn2 = HEAP_strdupWtoA( GetProcessHeap(), 0, fn2 );
2609 BOOL res = MoveFileA( afn1, afn2 );
2610 HeapFree( GetProcessHeap(), 0, afn1 );
2611 HeapFree( GetProcessHeap(), 0, afn2 );
2616 /**************************************************************************
2617 * CopyFileA (KERNEL32.@)
2619 BOOL WINAPI CopyFileA( LPCSTR source, LPCSTR dest, BOOL fail_if_exists )
2622 BY_HANDLE_FILE_INFORMATION info;
2628 if ((h1 = CreateFileA( source, GENERIC_READ, FILE_SHARE_READ|FILE_SHARE_WRITE, NULL,
2629 OPEN_EXISTING, 0, 0 )) == INVALID_HANDLE_VALUE)
2631 if (!GetFileInformationByHandle( h1, &info ))
2636 mode = (info.dwFileAttributes & FILE_ATTRIBUTE_READONLY) ? 0444 : 0666;
2637 if ((h2 = CreateFileA( dest, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
2638 fail_if_exists ? CREATE_NEW : CREATE_ALWAYS,
2639 info.dwFileAttributes, h1 )) == INVALID_HANDLE_VALUE)
2645 while (ReadFile( h1, buffer, sizeof(buffer), &count, NULL ) && count > 0)
2651 if (!WriteFile( h2, p, count, &res, NULL ) || !res) goto done;
2664 /**************************************************************************
2665 * CopyFileW (KERNEL32.@)
2667 BOOL WINAPI CopyFileW( LPCWSTR source, LPCWSTR dest, BOOL fail_if_exists)
2669 LPSTR sourceA = HEAP_strdupWtoA( GetProcessHeap(), 0, source );
2670 LPSTR destA = HEAP_strdupWtoA( GetProcessHeap(), 0, dest );
2671 BOOL ret = CopyFileA( sourceA, destA, fail_if_exists );
2672 HeapFree( GetProcessHeap(), 0, sourceA );
2673 HeapFree( GetProcessHeap(), 0, destA );
2678 /**************************************************************************
2679 * CopyFileExA (KERNEL32.@)
2681 * This implementation ignores most of the extra parameters passed-in into
2682 * the "ex" version of the method and calls the CopyFile method.
2683 * It will have to be fixed eventually.
2685 BOOL WINAPI CopyFileExA(LPCSTR sourceFilename,
2686 LPCSTR destFilename,
2687 LPPROGRESS_ROUTINE progressRoutine,
2689 LPBOOL cancelFlagPointer,
2692 BOOL failIfExists = FALSE;
2695 * Interpret the only flag that CopyFile can interpret.
2697 if ( (copyFlags & COPY_FILE_FAIL_IF_EXISTS) != 0)
2699 failIfExists = TRUE;
2702 return CopyFileA(sourceFilename, destFilename, failIfExists);
2705 /**************************************************************************
2706 * CopyFileExW (KERNEL32.@)
2708 BOOL WINAPI CopyFileExW(LPCWSTR sourceFilename,
2709 LPCWSTR destFilename,
2710 LPPROGRESS_ROUTINE progressRoutine,
2712 LPBOOL cancelFlagPointer,
2715 LPSTR sourceA = HEAP_strdupWtoA( GetProcessHeap(), 0, sourceFilename );
2716 LPSTR destA = HEAP_strdupWtoA( GetProcessHeap(), 0, destFilename );
2718 BOOL ret = CopyFileExA(sourceA,
2725 HeapFree( GetProcessHeap(), 0, sourceA );
2726 HeapFree( GetProcessHeap(), 0, destA );
2732 /***********************************************************************
2733 * SetFileTime (KERNEL32.@)
2735 BOOL WINAPI SetFileTime( HANDLE hFile,
2736 const FILETIME *lpCreationTime,
2737 const FILETIME *lpLastAccessTime,
2738 const FILETIME *lpLastWriteTime )
2741 SERVER_START_REQ( set_file_time )
2743 req->handle = hFile;
2744 if (lpLastAccessTime)
2745 RtlTimeToSecondsSince1970( lpLastAccessTime, (DWORD *)&req->access_time );
2747 req->access_time = 0; /* FIXME */
2748 if (lpLastWriteTime)
2749 RtlTimeToSecondsSince1970( lpLastWriteTime, (DWORD *)&req->write_time );
2751 req->write_time = 0; /* FIXME */
2752 ret = !wine_server_call_err( req );
2759 /**************************************************************************
2760 * LockFile (KERNEL32.@)
2762 BOOL WINAPI LockFile( HANDLE hFile, DWORD dwFileOffsetLow, DWORD dwFileOffsetHigh,
2763 DWORD nNumberOfBytesToLockLow, DWORD nNumberOfBytesToLockHigh )
2767 FIXME("not implemented in server\n");
2769 SERVER_START_REQ( lock_file )
2771 req->handle = hFile;
2772 req->offset_low = dwFileOffsetLow;
2773 req->offset_high = dwFileOffsetHigh;
2774 req->count_low = nNumberOfBytesToLockLow;
2775 req->count_high = nNumberOfBytesToLockHigh;
2776 ret = !wine_server_call_err( req );
2782 /**************************************************************************
2783 * LockFileEx [KERNEL32.@]
2785 * Locks a byte range within an open file for shared or exclusive access.
2792 * Per Microsoft docs, the third parameter (reserved) must be set to 0.
2794 BOOL WINAPI LockFileEx( HANDLE hFile, DWORD flags, DWORD reserved,
2795 DWORD nNumberOfBytesToLockLow, DWORD nNumberOfBytesToLockHigh,
2796 LPOVERLAPPED pOverlapped )
2798 FIXME("hFile=%d,flags=%ld,reserved=%ld,lowbytes=%ld,highbytes=%ld,overlapped=%p: stub.\n",
2799 hFile, flags, reserved, nNumberOfBytesToLockLow, nNumberOfBytesToLockHigh,
2802 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
2805 ERR("reserved == %ld: Supposed to be 0??\n", reserved);
2806 SetLastError(ERROR_INVALID_PARAMETER);
2813 /**************************************************************************
2814 * UnlockFile (KERNEL32.@)
2816 BOOL WINAPI UnlockFile( HANDLE hFile, DWORD dwFileOffsetLow, DWORD dwFileOffsetHigh,
2817 DWORD nNumberOfBytesToUnlockLow, DWORD nNumberOfBytesToUnlockHigh )
2821 FIXME("not implemented in server\n");
2823 SERVER_START_REQ( unlock_file )
2825 req->handle = hFile;
2826 req->offset_low = dwFileOffsetLow;
2827 req->offset_high = dwFileOffsetHigh;
2828 req->count_low = nNumberOfBytesToUnlockLow;
2829 req->count_high = nNumberOfBytesToUnlockHigh;
2830 ret = !wine_server_call_err( req );
2837 /**************************************************************************
2838 * UnlockFileEx (KERNEL32.@)
2840 BOOL WINAPI UnlockFileEx(
2843 DWORD nNumberOfBytesToUnlockLow,
2844 DWORD nNumberOfBytesToUnlockHigh,
2845 LPOVERLAPPED lpOverlapped
2848 FIXME("hFile=%d,reserved=%ld,lowbytes=%ld,highbytes=%ld,overlapped=%p: stub.\n",
2849 hFile, dwReserved, nNumberOfBytesToUnlockLow, nNumberOfBytesToUnlockHigh,
2851 if (dwReserved == 0)
2852 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
2855 ERR("reserved == %ld: Supposed to be 0??\n", dwReserved);
2856 SetLastError(ERROR_INVALID_PARAMETER);
2865 struct DOS_FILE_LOCK {
2866 struct DOS_FILE_LOCK * next;
2870 FILE_OBJECT * dos_file;
2871 /* char * unix_name;*/
2874 typedef struct DOS_FILE_LOCK DOS_FILE_LOCK;
2876 static DOS_FILE_LOCK *locks = NULL;
2877 static void DOS_RemoveFileLocks(FILE_OBJECT *file);
2880 /* Locks need to be mirrored because unix file locking is based
2881 * on the pid. Inside of wine there can be multiple WINE processes
2882 * that share the same unix pid.
2883 * Read's and writes should check these locks also - not sure
2884 * how critical that is at this point (FIXME).
2887 static BOOL DOS_AddLock(FILE_OBJECT *file, struct flock *f)
2889 DOS_FILE_LOCK *curr;
2892 processId = GetCurrentProcessId();
2894 /* check if lock overlaps a current lock for the same file */
2896 for (curr = locks; curr; curr = curr->next) {
2897 if (strcmp(curr->unix_name, file->unix_name) == 0) {
2898 if ((f->l_start == curr->base) && (f->l_len == curr->len))
2899 return TRUE;/* region is identic */
2900 if ((f->l_start < (curr->base + curr->len)) &&
2901 ((f->l_start + f->l_len) > curr->base)) {
2902 /* region overlaps */
2909 curr = HeapAlloc( GetProcessHeap(), 0, sizeof(DOS_FILE_LOCK) );
2910 curr->processId = GetCurrentProcessId();
2911 curr->base = f->l_start;
2912 curr->len = f->l_len;
2913 /* curr->unix_name = HEAP_strdupA( GetProcessHeap(), 0, file->unix_name);*/
2915 curr->dos_file = file;
2920 static void DOS_RemoveFileLocks(FILE_OBJECT *file)
2923 DOS_FILE_LOCK **curr;
2926 processId = GetCurrentProcessId();
2929 if ((*curr)->dos_file == file) {
2931 *curr = (*curr)->next;
2932 /* HeapFree( GetProcessHeap(), 0, rem->unix_name );*/
2933 HeapFree( GetProcessHeap(), 0, rem );
2936 curr = &(*curr)->next;
2940 static BOOL DOS_RemoveLock(FILE_OBJECT *file, struct flock *f)
2943 DOS_FILE_LOCK **curr;
2946 processId = GetCurrentProcessId();
2947 for (curr = &locks; *curr; curr = &(*curr)->next) {
2948 if ((*curr)->processId == processId &&
2949 (*curr)->dos_file == file &&
2950 (*curr)->base == f->l_start &&
2951 (*curr)->len == f->l_len) {
2952 /* this is the same lock */
2954 *curr = (*curr)->next;
2955 /* HeapFree( GetProcessHeap(), 0, rem->unix_name );*/
2956 HeapFree( GetProcessHeap(), 0, rem );
2960 /* no matching lock found */
2965 /**************************************************************************
2966 * LockFile (KERNEL32.@)
2968 BOOL WINAPI LockFile(
2969 HANDLE hFile,DWORD dwFileOffsetLow,DWORD dwFileOffsetHigh,
2970 DWORD nNumberOfBytesToLockLow,DWORD nNumberOfBytesToLockHigh )
2975 TRACE("handle %d offsetlow=%ld offsethigh=%ld nbyteslow=%ld nbyteshigh=%ld\n",
2976 hFile, dwFileOffsetLow, dwFileOffsetHigh,
2977 nNumberOfBytesToLockLow, nNumberOfBytesToLockHigh);
2979 if (dwFileOffsetHigh || nNumberOfBytesToLockHigh) {
2980 FIXME("Unimplemented bytes > 32bits\n");
2984 f.l_start = dwFileOffsetLow;
2985 f.l_len = nNumberOfBytesToLockLow;
2986 f.l_whence = SEEK_SET;
2990 if (!(file = FILE_GetFile(hFile,0,NULL))) return FALSE;
2992 /* shadow locks internally */
2993 if (!DOS_AddLock(file, &f)) {
2994 SetLastError( ERROR_LOCK_VIOLATION );
2998 /* FIXME: Unix locking commented out for now, doesn't work with Excel */
2999 #ifdef USE_UNIX_LOCKS
3000 if (fcntl(file->unix_handle, F_SETLK, &f) == -1) {
3001 if (errno == EACCES || errno == EAGAIN) {
3002 SetLastError( ERROR_LOCK_VIOLATION );
3007 /* remove our internal copy of the lock */
3008 DOS_RemoveLock(file, &f);
3016 /**************************************************************************
3017 * UnlockFile (KERNEL32.@)
3019 BOOL WINAPI UnlockFile(
3020 HANDLE hFile,DWORD dwFileOffsetLow,DWORD dwFileOffsetHigh,
3021 DWORD nNumberOfBytesToUnlockLow,DWORD nNumberOfBytesToUnlockHigh )
3026 TRACE("handle %d offsetlow=%ld offsethigh=%ld nbyteslow=%ld nbyteshigh=%ld\n",
3027 hFile, dwFileOffsetLow, dwFileOffsetHigh,
3028 nNumberOfBytesToUnlockLow, nNumberOfBytesToUnlockHigh);
3030 if (dwFileOffsetHigh || nNumberOfBytesToUnlockHigh) {
3031 WARN("Unimplemented bytes > 32bits\n");
3035 f.l_start = dwFileOffsetLow;
3036 f.l_len = nNumberOfBytesToUnlockLow;
3037 f.l_whence = SEEK_SET;
3041 if (!(file = FILE_GetFile(hFile,0,NULL))) return FALSE;
3043 DOS_RemoveLock(file, &f); /* ok if fails - may be another wine */
3045 /* FIXME: Unix locking commented out for now, doesn't work with Excel */
3046 #ifdef USE_UNIX_LOCKS
3047 if (fcntl(file->unix_handle, F_SETLK, &f) == -1) {
3056 /**************************************************************************
3057 * GetFileAttributesExA [KERNEL32.@]
3059 BOOL WINAPI GetFileAttributesExA(
3060 LPCSTR lpFileName, GET_FILEEX_INFO_LEVELS fInfoLevelId,
3061 LPVOID lpFileInformation)
3063 DOS_FULL_NAME full_name;
3064 BY_HANDLE_FILE_INFORMATION info;
3066 if (lpFileName == NULL) return FALSE;
3067 if (lpFileInformation == NULL) return FALSE;
3069 if (fInfoLevelId == GetFileExInfoStandard) {
3070 LPWIN32_FILE_ATTRIBUTE_DATA lpFad =
3071 (LPWIN32_FILE_ATTRIBUTE_DATA) lpFileInformation;
3072 if (!DOSFS_GetFullName( lpFileName, TRUE, &full_name )) return FALSE;
3073 if (!FILE_Stat( full_name.long_name, &info )) return FALSE;
3075 lpFad->dwFileAttributes = info.dwFileAttributes;
3076 lpFad->ftCreationTime = info.ftCreationTime;
3077 lpFad->ftLastAccessTime = info.ftLastAccessTime;
3078 lpFad->ftLastWriteTime = info.ftLastWriteTime;
3079 lpFad->nFileSizeHigh = info.nFileSizeHigh;
3080 lpFad->nFileSizeLow = info.nFileSizeLow;
3083 FIXME("invalid info level %d!\n", fInfoLevelId);
3091 /**************************************************************************
3092 * GetFileAttributesExW [KERNEL32.@]
3094 BOOL WINAPI GetFileAttributesExW(
3095 LPCWSTR lpFileName, GET_FILEEX_INFO_LEVELS fInfoLevelId,
3096 LPVOID lpFileInformation)
3098 LPSTR nameA = HEAP_strdupWtoA( GetProcessHeap(), 0, lpFileName );
3100 GetFileAttributesExA( nameA, fInfoLevelId, lpFileInformation);
3101 HeapFree( GetProcessHeap(), 0, nameA );