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>
47 #ifdef HAVE_SYS_POLL_H
48 # include <sys/poll.h>
63 #include "wine/winbase16.h"
64 #include "wine/server.h"
74 #include "wine/unicode.h"
75 #include "wine/debug.h"
77 WINE_DEFAULT_DEBUG_CHANNEL(file);
79 #if defined(MAP_ANONYMOUS) && !defined(MAP_ANON)
80 #define MAP_ANON MAP_ANONYMOUS
83 /* Size of per-process table of DOS handles */
84 #define DOS_TABLE_SIZE 256
86 /* Macro to derive file offset from OVERLAPPED struct */
87 #define OVERLAPPED_OFFSET(overlapped) ((off_t) (overlapped)->Offset + ((off_t) (overlapped)->OffsetHigh << 32))
89 static HANDLE dos_handles[DOS_TABLE_SIZE];
93 extern HANDLE WINAPI FILE_SmbOpen(LPCSTR name);
95 /***********************************************************************
96 * Asynchronous file I/O *
98 static DWORD fileio_get_async_status (const async_private *ovp);
99 static DWORD fileio_get_async_count (const async_private *ovp);
100 static void fileio_set_async_status (async_private *ovp, const DWORD status);
101 static void CALLBACK fileio_call_completion_func (ULONG_PTR data);
102 static void fileio_async_cleanup (async_private *ovp);
104 static async_ops fileio_async_ops =
106 fileio_get_async_status, /* get_status */
107 fileio_set_async_status, /* set_status */
108 fileio_get_async_count, /* get_count */
109 fileio_call_completion_func, /* call_completion */
110 fileio_async_cleanup /* cleanup */
113 static async_ops fileio_nocomp_async_ops =
115 fileio_get_async_status, /* get_status */
116 fileio_set_async_status, /* set_status */
117 fileio_get_async_count, /* get_count */
118 NULL, /* call_completion */
119 fileio_async_cleanup /* cleanup */
122 typedef struct async_fileio
124 struct async_private async;
125 LPOVERLAPPED lpOverlapped;
126 LPOVERLAPPED_COMPLETION_ROUTINE completion_func;
129 enum fd_type fd_type;
132 static DWORD fileio_get_async_status (const struct async_private *ovp)
134 return ((async_fileio*) ovp)->lpOverlapped->Internal;
137 static void fileio_set_async_status (async_private *ovp, const DWORD status)
139 ((async_fileio*) ovp)->lpOverlapped->Internal = status;
142 static DWORD fileio_get_async_count (const struct async_private *ovp)
144 async_fileio *fileio = (async_fileio*) ovp;
145 DWORD ret = fileio->count - fileio->lpOverlapped->InternalHigh;
146 return (ret < 0 ? 0 : ret);
149 static void CALLBACK fileio_call_completion_func (ULONG_PTR data)
151 async_fileio *ovp = (async_fileio*) data;
152 TRACE ("data: %p\n", ovp);
154 ovp->completion_func( ovp->lpOverlapped->Internal,
155 ovp->lpOverlapped->InternalHigh,
158 fileio_async_cleanup ( &ovp->async );
161 static void fileio_async_cleanup ( struct async_private *ovp )
163 HeapFree ( GetProcessHeap(), 0, ovp );
166 /***********************************************************************
169 * Convert OF_* mode into flags for CreateFile.
171 static void FILE_ConvertOFMode( INT mode, DWORD *access, DWORD *sharing )
175 case OF_READ: *access = GENERIC_READ; break;
176 case OF_WRITE: *access = GENERIC_WRITE; break;
177 case OF_READWRITE: *access = GENERIC_READ | GENERIC_WRITE; break;
178 default: *access = 0; break;
182 case OF_SHARE_EXCLUSIVE: *sharing = 0; break;
183 case OF_SHARE_DENY_WRITE: *sharing = FILE_SHARE_READ; break;
184 case OF_SHARE_DENY_READ: *sharing = FILE_SHARE_WRITE; break;
185 case OF_SHARE_DENY_NONE:
186 case OF_SHARE_COMPAT:
187 default: *sharing = FILE_SHARE_READ | FILE_SHARE_WRITE; break;
192 /***********************************************************************
195 * locale-independent case conversion for file I/O
197 int FILE_strcasecmp( const char *str1, const char *str2 )
200 for ( ; ; str1++, str2++)
201 if ((ret = FILE_toupper(*str1) - FILE_toupper(*str2)) || !*str1) break;
206 /***********************************************************************
209 * locale-independent case conversion for file I/O
211 int FILE_strncasecmp( const char *str1, const char *str2, int len )
214 for ( ; len > 0; len--, str1++, str2++)
215 if ((ret = FILE_toupper(*str1) - FILE_toupper(*str2)) || !*str1) break;
220 /***********************************************************************
221 * FILE_GetNtStatus(void)
223 * Retrieve the Nt Status code from errno.
224 * Try to be consistent with FILE_SetDosError().
226 DWORD FILE_GetNtStatus(void)
230 TRACE ( "errno = %d\n", errno );
233 case EAGAIN: nt = STATUS_SHARING_VIOLATION; break;
234 case EBADF: nt = STATUS_INVALID_HANDLE; break;
235 case ENOSPC: nt = STATUS_DISK_FULL; break;
238 case EACCES: nt = STATUS_ACCESS_DENIED; break;
239 case ENOENT: nt = STATUS_SHARING_VIOLATION; break;
240 case EISDIR: nt = STATUS_FILE_IS_A_DIRECTORY; break;
242 case ENFILE: nt = STATUS_NO_MORE_FILES; break;
244 case ENOTEMPTY: nt = STATUS_DIRECTORY_NOT_EMPTY; break;
245 case EPIPE: nt = STATUS_PIPE_BROKEN; break;
246 case ENOEXEC: /* ?? */
247 case ESPIPE: /* ?? */
248 case EEXIST: /* ?? */
250 FIXME ( "Converting errno %d to STATUS_UNSUCCESSFUL\n", err );
251 nt = STATUS_UNSUCCESSFUL;
256 /***********************************************************************
259 * Set the DOS error code from errno.
261 void FILE_SetDosError(void)
263 int save_errno = errno; /* errno gets overwritten by printf */
265 TRACE("errno = %d %s\n", errno, strerror(errno));
269 SetLastError( ERROR_SHARING_VIOLATION );
272 SetLastError( ERROR_INVALID_HANDLE );
275 SetLastError( ERROR_HANDLE_DISK_FULL );
280 SetLastError( ERROR_ACCESS_DENIED );
283 SetLastError( ERROR_LOCK_VIOLATION );
286 SetLastError( ERROR_FILE_NOT_FOUND );
289 SetLastError( ERROR_CANNOT_MAKE );
293 SetLastError( ERROR_NO_MORE_FILES );
296 SetLastError( ERROR_FILE_EXISTS );
300 SetLastError( ERROR_SEEK );
303 SetLastError( ERROR_DIR_NOT_EMPTY );
306 SetLastError( ERROR_BAD_FORMAT );
309 WARN("unknown file error: %s\n", strerror(save_errno) );
310 SetLastError( ERROR_GEN_FAILURE );
317 /***********************************************************************
318 * FILE_GetUnixHandleType
320 * Retrieve the Unix handle corresponding to a file handle.
321 * Returns -1 on failure.
323 static int FILE_GetUnixHandleType( HANDLE handle, DWORD access, enum fd_type *type, int *flags_ptr )
325 int ret, flags, fd = -1;
327 ret = wine_server_handle_to_fd( handle, access, &fd, type, &flags );
328 if (flags_ptr) *flags_ptr = flags;
329 if (ret) SetLastError( RtlNtStatusToDosError(ret) );
330 else if (((access & GENERIC_READ) && (flags & FD_FLAG_RECV_SHUTDOWN)) ||
331 ((access & GENERIC_WRITE) && (flags & FD_FLAG_SEND_SHUTDOWN)))
334 SetLastError ( ERROR_PIPE_NOT_CONNECTED );
340 /***********************************************************************
343 * Retrieve the Unix handle corresponding to a file handle.
344 * Returns -1 on failure.
346 int FILE_GetUnixHandle( HANDLE handle, DWORD access )
348 return FILE_GetUnixHandleType( handle, access, NULL, NULL );
351 /*************************************************************************
354 * Open a handle to the current process console.
355 * Returns 0 on failure.
357 static HANDLE FILE_OpenConsole( BOOL output, DWORD access, DWORD sharing, LPSECURITY_ATTRIBUTES sa )
361 SERVER_START_REQ( open_console )
364 req->access = access;
365 req->share = sharing;
366 req->inherit = (sa && (sa->nLength>=sizeof(*sa)) && sa->bInheritHandle);
368 wine_server_call_err( req );
375 /* FIXME: those routines defined as pointers are needed, because this file is
376 * currently compiled into NTDLL whereas it belongs to kernel32.
377 * this shall go away once all the DLL separation process is done
379 typedef BOOL (WINAPI* pRW)(HANDLE, const void*, DWORD, DWORD*, void*);
381 static BOOL FILE_ReadConsole(HANDLE hCon, void* buf, DWORD nb, DWORD* nr, void* p)
383 static HANDLE hKernel /* = 0 */;
384 static pRW pReadConsole /* = 0 */;
386 if ((!hKernel && !(hKernel = LoadLibraryA("kernel32"))) ||
388 !(pReadConsole = GetProcAddress(hKernel, "ReadConsoleA"))))
393 return (pReadConsole)(hCon, buf, nb, nr, p);
396 static BOOL FILE_WriteConsole(HANDLE hCon, const void* buf, DWORD nb, DWORD* nr, void* p)
398 static HANDLE hKernel /* = 0 */;
399 static pRW pWriteConsole /* = 0 */;
401 if ((!hKernel && !(hKernel = LoadLibraryA("kernel32"))) ||
403 !(pWriteConsole = GetProcAddress(hKernel, "WriteConsoleA"))))
408 return (pWriteConsole)(hCon, buf, nb, nr, p);
412 /***********************************************************************
415 * Implementation of CreateFile. Takes a Unix path name.
416 * Returns 0 on failure.
418 HANDLE FILE_CreateFile( LPCSTR filename, DWORD access, DWORD sharing,
419 LPSECURITY_ATTRIBUTES sa, DWORD creation,
420 DWORD attributes, HANDLE template, BOOL fail_read_only,
428 SERVER_START_REQ( create_file )
430 req->access = access;
431 req->inherit = (sa && (sa->nLength>=sizeof(*sa)) && sa->bInheritHandle);
432 req->sharing = sharing;
433 req->create = creation;
434 req->attrs = attributes;
435 req->drive_type = drive_type;
436 wine_server_add_data( req, filename, strlen(filename) );
438 err = wine_server_call( req );
443 /* If write access failed, retry without GENERIC_WRITE */
445 if (!ret && !fail_read_only && (access & GENERIC_WRITE))
447 if ((err == STATUS_MEDIA_WRITE_PROTECTED) || (err == STATUS_ACCESS_DENIED))
449 TRACE("Write access failed for file '%s', trying without "
450 "write access\n", filename);
451 access &= ~GENERIC_WRITE;
458 /* In the case file creation was rejected due to CREATE_NEW flag
459 * was specified and file with that name already exists, correct
460 * last error is ERROR_FILE_EXISTS and not ERROR_ALREADY_EXISTS.
461 * Note: RtlNtStatusToDosError is not the subject to blame here.
463 if (err == STATUS_OBJECT_NAME_COLLISION)
464 SetLastError( ERROR_FILE_EXISTS );
466 SetLastError( RtlNtStatusToDosError(err) );
469 if (!ret) WARN("Unable to create file '%s' (GLE %ld)\n", filename, GetLastError());
475 /***********************************************************************
478 * Same as FILE_CreateFile but for a device
479 * Returns 0 on failure.
481 HANDLE FILE_CreateDevice( int client_id, DWORD access, LPSECURITY_ATTRIBUTES sa )
484 SERVER_START_REQ( create_device )
486 req->access = access;
487 req->inherit = (sa && (sa->nLength>=sizeof(*sa)) && sa->bInheritHandle);
490 wine_server_call_err( req );
497 static HANDLE FILE_OpenPipe(LPCWSTR name, DWORD access)
502 if (name && (len = strlenW(name)) > MAX_PATH)
504 SetLastError( ERROR_FILENAME_EXCED_RANGE );
507 SERVER_START_REQ( open_named_pipe )
509 req->access = access;
511 wine_server_add_data( req, name, len * sizeof(WCHAR) );
512 wine_server_call_err( req );
516 TRACE("Returned %d\n",ret);
520 /*************************************************************************
521 * CreateFileW [KERNEL32.@] Creates or opens a file or other object
523 * Creates or opens an object, and returns a handle that can be used to
524 * access that object.
528 * filename [in] pointer to filename to be accessed
529 * access [in] access mode requested
530 * sharing [in] share mode
531 * sa [in] pointer to security attributes
532 * creation [in] how to create the file
533 * attributes [in] attributes for newly created file
534 * template [in] handle to file with extended attributes to copy
537 * Success: Open handle to specified file
538 * Failure: INVALID_HANDLE_VALUE
541 * Should call SetLastError() on failure.
545 * Doesn't support character devices, template files, or a
546 * lot of the 'attributes' flags yet.
548 HANDLE WINAPI CreateFileW( LPCWSTR filename, DWORD access, DWORD sharing,
549 LPSECURITY_ATTRIBUTES sa, DWORD creation,
550 DWORD attributes, HANDLE template )
552 DOS_FULL_NAME full_name;
554 static const WCHAR bkslashes_with_question_markW[] = {'\\','\\','?','\\',0};
555 static const WCHAR bkslashes_with_dotW[] = {'\\','\\','.','\\',0};
556 static const WCHAR bkslashesW[] = {'\\','\\',0};
557 static const WCHAR coninW[] = {'C','O','N','I','N','$',0};
558 static const WCHAR conoutW[] = {'C','O','N','O','U','T','$',0};
562 SetLastError( ERROR_INVALID_PARAMETER );
563 return INVALID_HANDLE_VALUE;
565 TRACE("%s %s%s%s%s%s%s%s attributes 0x%lx\n", debugstr_w(filename),
566 ((access & GENERIC_READ)==GENERIC_READ)?"GENERIC_READ ":"",
567 ((access & GENERIC_WRITE)==GENERIC_WRITE)?"GENERIC_WRITE ":"",
568 (!access)?"QUERY_ACCESS ":"",
569 ((sharing & FILE_SHARE_READ)==FILE_SHARE_READ)?"FILE_SHARE_READ ":"",
570 ((sharing & FILE_SHARE_WRITE)==FILE_SHARE_WRITE)?"FILE_SHARE_WRITE ":"",
571 ((sharing & FILE_SHARE_DELETE)==FILE_SHARE_DELETE)?"FILE_SHARE_DELETE ":"",
572 (creation ==CREATE_NEW)?"CREATE_NEW":
573 (creation ==CREATE_ALWAYS)?"CREATE_ALWAYS ":
574 (creation ==OPEN_EXISTING)?"OPEN_EXISTING ":
575 (creation ==OPEN_ALWAYS)?"OPEN_ALWAYS ":
576 (creation ==TRUNCATE_EXISTING)?"TRUNCATE_EXISTING ":"", attributes);
578 /* If the name starts with '\\?\', ignore the first 4 chars. */
579 if (!strncmpW(filename, bkslashes_with_question_markW, 4))
581 static const WCHAR uncW[] = {'U','N','C','\\',0};
583 if (!strncmpiW(filename, uncW, 4))
585 FIXME("UNC name (%s) not supported.\n", debugstr_w(filename) );
586 SetLastError( ERROR_PATH_NOT_FOUND );
587 return INVALID_HANDLE_VALUE;
591 if (!strncmpW(filename, bkslashes_with_dotW, 4))
593 static const WCHAR pipeW[] = {'P','I','P','E','\\',0};
594 if(!strncmpiW(filename + 4, pipeW, 5))
596 TRACE("Opening a pipe: %s\n", debugstr_w(filename));
597 ret = FILE_OpenPipe(filename,access);
600 else if (isalphaW(filename[4]) && filename[5] == ':' && filename[6] == '\0')
602 ret = FILE_CreateDevice( (toupperW(filename[4]) - 'A') | 0x20000, access, sa );
605 else if (!DOSFS_GetDevice( filename ))
607 ret = DEVICE_Open( filename+4, access, sa );
611 filename+=4; /* fall into DOSFS_Device case below */
614 /* If the name still starts with '\\', it's a UNC name. */
615 if (!strncmpW(filename, bkslashesW, 2))
617 ret = SMB_CreateFileW(filename, access, sharing, sa, creation, attributes, template );
621 /* If the name contains a DOS wild card (* or ?), do no create a file */
622 if(strchrW(filename, '*') || strchrW(filename, '?'))
623 return INVALID_HANDLE_VALUE;
625 /* Open a console for CONIN$ or CONOUT$ */
626 if (!strcmpiW(filename, coninW))
628 ret = FILE_OpenConsole( FALSE, access, sharing, sa );
631 if (!strcmpiW(filename, conoutW))
633 ret = FILE_OpenConsole( TRUE, access, sharing, sa );
637 if (DOSFS_GetDevice( filename ))
639 TRACE("opening device %s\n", debugstr_w(filename) );
641 if (!(ret = DOSFS_OpenDevice( filename, access, attributes, sa )))
643 /* Do not silence this please. It is a critical error. -MM */
644 ERR("Couldn't open device %s!\n", debugstr_w(filename));
645 SetLastError( ERROR_FILE_NOT_FOUND );
650 /* check for filename, don't check for last entry if creating */
651 if (!DOSFS_GetFullName( filename,
652 (creation == OPEN_EXISTING) ||
653 (creation == TRUNCATE_EXISTING),
655 WARN("Unable to get full filename from %s (GLE %ld)\n",
656 debugstr_w(filename), GetLastError());
657 return INVALID_HANDLE_VALUE;
660 ret = FILE_CreateFile( full_name.long_name, access, sharing,
661 sa, creation, attributes, template,
662 DRIVE_GetFlags(full_name.drive) & DRIVE_FAIL_READ_ONLY,
663 GetDriveTypeW( full_name.short_name ) );
665 if (!ret) ret = INVALID_HANDLE_VALUE;
666 TRACE("returning %08x\n", ret);
672 /*************************************************************************
673 * CreateFileA (KERNEL32.@)
675 HANDLE WINAPI CreateFileA( LPCSTR filename, DWORD access, DWORD sharing,
676 LPSECURITY_ATTRIBUTES sa, DWORD creation,
677 DWORD attributes, HANDLE template)
679 UNICODE_STRING filenameW;
680 HANDLE ret = INVALID_HANDLE_VALUE;
684 SetLastError( ERROR_INVALID_PARAMETER );
685 return INVALID_HANDLE_VALUE;
688 if (RtlCreateUnicodeStringFromAsciiz(&filenameW, filename))
690 ret = CreateFileW(filenameW.Buffer, access, sharing, sa, creation,
691 attributes, template);
692 RtlFreeUnicodeString(&filenameW);
695 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
700 /***********************************************************************
703 * Fill a file information from a struct stat.
705 static void FILE_FillInfo( struct stat *st, BY_HANDLE_FILE_INFORMATION *info )
707 if (S_ISDIR(st->st_mode))
708 info->dwFileAttributes = FILE_ATTRIBUTE_DIRECTORY;
710 info->dwFileAttributes = FILE_ATTRIBUTE_ARCHIVE;
711 if (!(st->st_mode & S_IWUSR))
712 info->dwFileAttributes |= FILE_ATTRIBUTE_READONLY;
714 RtlSecondsSince1970ToTime( st->st_mtime, &info->ftCreationTime );
715 RtlSecondsSince1970ToTime( st->st_mtime, &info->ftLastWriteTime );
716 RtlSecondsSince1970ToTime( st->st_atime, &info->ftLastAccessTime );
718 info->dwVolumeSerialNumber = 0; /* FIXME */
719 info->nFileSizeHigh = 0;
720 info->nFileSizeLow = 0;
721 if (!S_ISDIR(st->st_mode)) {
722 info->nFileSizeHigh = st->st_size >> 32;
723 info->nFileSizeLow = st->st_size & 0xffffffff;
725 info->nNumberOfLinks = st->st_nlink;
726 info->nFileIndexHigh = 0;
727 info->nFileIndexLow = st->st_ino;
731 /***********************************************************************
734 * Stat a Unix path name. Return TRUE if OK.
736 BOOL FILE_Stat( LPCSTR unixName, BY_HANDLE_FILE_INFORMATION *info )
740 if (lstat( unixName, &st ) == -1)
745 if (!S_ISLNK(st.st_mode)) FILE_FillInfo( &st, info );
748 /* do a "real" stat to find out
749 about the type of the symlink destination */
750 if (stat( unixName, &st ) == -1)
755 FILE_FillInfo( &st, info );
756 info->dwFileAttributes |= FILE_ATTRIBUTE_SYMLINK;
762 /***********************************************************************
763 * GetFileInformationByHandle (KERNEL32.@)
765 DWORD WINAPI GetFileInformationByHandle( HANDLE hFile,
766 BY_HANDLE_FILE_INFORMATION *info )
771 TRACE("%08x\n", hFile);
773 SERVER_START_REQ( get_file_info )
776 if ((ret = !wine_server_call_err( req )))
778 /* FIXME: which file types are supported ?
779 * Serial ports (FILE_TYPE_CHAR) are not,
780 * and MSDN also says that pipes are not supported.
781 * FILE_TYPE_REMOTE seems to be supported according to
782 * MSDN q234741.txt */
783 if ((reply->type == FILE_TYPE_DISK) || (reply->type == FILE_TYPE_REMOTE))
785 RtlSecondsSince1970ToTime( reply->write_time, &info->ftCreationTime );
786 RtlSecondsSince1970ToTime( reply->write_time, &info->ftLastWriteTime );
787 RtlSecondsSince1970ToTime( reply->access_time, &info->ftLastAccessTime );
788 info->dwFileAttributes = reply->attr;
789 info->dwVolumeSerialNumber = reply->serial;
790 info->nFileSizeHigh = reply->size_high;
791 info->nFileSizeLow = reply->size_low;
792 info->nNumberOfLinks = reply->links;
793 info->nFileIndexHigh = reply->index_high;
794 info->nFileIndexLow = reply->index_low;
798 SetLastError(ERROR_NOT_SUPPORTED);
808 /**************************************************************************
809 * GetFileAttributes (KERNEL.420)
811 DWORD WINAPI GetFileAttributes16( LPCSTR name )
813 return GetFileAttributesA( name );
817 /**************************************************************************
818 * GetFileAttributesW (KERNEL32.@)
820 DWORD WINAPI GetFileAttributesW( LPCWSTR name )
822 DOS_FULL_NAME full_name;
823 BY_HANDLE_FILE_INFORMATION info;
827 SetLastError( ERROR_INVALID_PARAMETER );
830 if (!DOSFS_GetFullName( name, TRUE, &full_name) )
832 if (!FILE_Stat( full_name.long_name, &info )) return -1;
833 return info.dwFileAttributes;
837 /**************************************************************************
838 * GetFileAttributesA (KERNEL32.@)
840 DWORD WINAPI GetFileAttributesA( LPCSTR name )
842 UNICODE_STRING nameW;
843 DWORD ret = (DWORD)-1;
847 SetLastError( ERROR_INVALID_PARAMETER );
851 if (RtlCreateUnicodeStringFromAsciiz(&nameW, name))
853 ret = GetFileAttributesW(nameW.Buffer);
854 RtlFreeUnicodeString(&nameW);
857 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
862 /**************************************************************************
863 * SetFileAttributes (KERNEL.421)
865 BOOL16 WINAPI SetFileAttributes16( LPCSTR lpFileName, DWORD attributes )
867 return SetFileAttributesA( lpFileName, attributes );
871 /**************************************************************************
872 * SetFileAttributesW (KERNEL32.@)
874 BOOL WINAPI SetFileAttributesW(LPCWSTR lpFileName, DWORD attributes)
877 DOS_FULL_NAME full_name;
881 SetLastError( ERROR_INVALID_PARAMETER );
885 TRACE("(%s,%lx)\n", debugstr_w(lpFileName), attributes);
887 if (!DOSFS_GetFullName( lpFileName, TRUE, &full_name ))
890 if(stat(full_name.long_name,&buf)==-1)
895 if (attributes & FILE_ATTRIBUTE_READONLY)
897 if(S_ISDIR(buf.st_mode))
899 WARN("FILE_ATTRIBUTE_READONLY ignored for directory.\n");
901 buf.st_mode &= ~0222; /* octal!, clear write permission bits */
902 attributes &= ~FILE_ATTRIBUTE_READONLY;
906 /* add write permission */
907 buf.st_mode |= (0600 | ((buf.st_mode & 044) >> 1)) & (~FILE_umask);
909 if (attributes & FILE_ATTRIBUTE_DIRECTORY)
911 if (!S_ISDIR(buf.st_mode))
912 FIXME("SetFileAttributes expected the file %s to be a directory\n",
913 debugstr_w(lpFileName));
914 attributes &= ~FILE_ATTRIBUTE_DIRECTORY;
916 attributes &= ~(FILE_ATTRIBUTE_NORMAL|FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_HIDDEN|FILE_ATTRIBUTE_SYSTEM);
918 FIXME("(%s):%lx attribute(s) not implemented.\n", debugstr_w(lpFileName), attributes);
919 if (-1==chmod(full_name.long_name,buf.st_mode))
921 if (GetDriveTypeW(lpFileName) == DRIVE_CDROM)
923 SetLastError( ERROR_ACCESS_DENIED );
928 * FIXME: We don't return FALSE here because of differences between
929 * Linux and Windows privileges. Under Linux only the owner of
930 * the file is allowed to change file attributes. Under Windows,
931 * applications expect that if you can write to a file, you can also
932 * change its attributes (see GENERIC_WRITE). We could try to be
933 * clever here but that would break multi-user installations where
934 * users share read-only DLLs. This is because some installers like
935 * to change attributes of already installed DLLs.
937 FIXME("Couldn't set file attributes for existing file \"%s\".\n"
938 "Check permissions or set VFAT \"quiet\" mount flag\n", full_name.long_name);
944 /**************************************************************************
945 * SetFileAttributesA (KERNEL32.@)
947 BOOL WINAPI SetFileAttributesA(LPCSTR lpFileName, DWORD attributes)
949 UNICODE_STRING filenameW;
954 SetLastError( ERROR_INVALID_PARAMETER );
958 if (RtlCreateUnicodeStringFromAsciiz(&filenameW, lpFileName))
960 ret = SetFileAttributesW(filenameW.Buffer, attributes);
961 RtlFreeUnicodeString(&filenameW);
964 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
969 /***********************************************************************
970 * GetFileSize (KERNEL32.@)
972 DWORD WINAPI GetFileSize( HANDLE hFile, LPDWORD filesizehigh )
974 BY_HANDLE_FILE_INFORMATION info;
975 if (!GetFileInformationByHandle( hFile, &info )) return -1;
976 if (filesizehigh) *filesizehigh = info.nFileSizeHigh;
977 return info.nFileSizeLow;
981 /***********************************************************************
982 * GetFileTime (KERNEL32.@)
984 BOOL WINAPI GetFileTime( HANDLE hFile, FILETIME *lpCreationTime,
985 FILETIME *lpLastAccessTime,
986 FILETIME *lpLastWriteTime )
988 BY_HANDLE_FILE_INFORMATION info;
989 if (!GetFileInformationByHandle( hFile, &info )) return FALSE;
990 if (lpCreationTime) *lpCreationTime = info.ftCreationTime;
991 if (lpLastAccessTime) *lpLastAccessTime = info.ftLastAccessTime;
992 if (lpLastWriteTime) *lpLastWriteTime = info.ftLastWriteTime;
996 /***********************************************************************
997 * CompareFileTime (KERNEL32.@)
999 INT WINAPI CompareFileTime( LPFILETIME x, LPFILETIME y )
1001 if (!x || !y) return -1;
1003 if (x->dwHighDateTime > y->dwHighDateTime)
1005 if (x->dwHighDateTime < y->dwHighDateTime)
1007 if (x->dwLowDateTime > y->dwLowDateTime)
1009 if (x->dwLowDateTime < y->dwLowDateTime)
1014 /***********************************************************************
1015 * FILE_GetTempFileName : utility for GetTempFileName
1017 static UINT FILE_GetTempFileName( LPCWSTR path, LPCWSTR prefix, UINT unique,
1020 static UINT unique_temp;
1021 DOS_FULL_NAME full_name;
1027 if ( !path || !prefix || !buffer )
1029 SetLastError( ERROR_INVALID_PARAMETER );
1033 if (!unique_temp) unique_temp = time(NULL) & 0xffff;
1034 num = unique ? (unique & 0xffff) : (unique_temp++ & 0xffff);
1036 strcpyW( buffer, path );
1037 p = buffer + strlenW(buffer);
1039 /* add a \, if there isn't one and path is more than just the drive letter ... */
1040 if ( !((strlenW(buffer) == 2) && (buffer[1] == ':'))
1041 && ((p == buffer) || (p[-1] != '\\'))) *p++ = '\\';
1043 for (i = 3; (i > 0) && (*prefix); i--) *p++ = *prefix++;
1045 sprintf( buf, "%04x.tmp", num );
1046 MultiByteToWideChar(CP_ACP, 0, buf, -1, p, 20);
1048 /* Now try to create it */
1054 HANDLE handle = CreateFileW( buffer, GENERIC_WRITE, 0, NULL,
1055 CREATE_NEW, FILE_ATTRIBUTE_NORMAL, 0 );
1056 if (handle != INVALID_HANDLE_VALUE)
1057 { /* We created it */
1058 TRACE("created %s\n", debugstr_w(buffer) );
1059 CloseHandle( handle );
1062 if (GetLastError() != ERROR_FILE_EXISTS)
1063 break; /* No need to go on */
1065 sprintf( buf, "%04x.tmp", num );
1066 MultiByteToWideChar(CP_ACP, 0, buf, -1, p, 20);
1067 } while (num != (unique & 0xffff));
1070 /* Get the full path name */
1072 if (DOSFS_GetFullName( buffer, FALSE, &full_name ))
1075 /* Check if we have write access in the directory */
1076 if ((slash = strrchr( full_name.long_name, '/' ))) *slash = '\0';
1077 if (access( full_name.long_name, W_OK ) == -1)
1078 WARN("returns %s, which doesn't seem to be writeable.\n",
1079 debugstr_w(buffer) );
1081 TRACE("returning %s\n", debugstr_w(buffer) );
1082 return unique ? unique : num;
1086 /***********************************************************************
1087 * GetTempFileNameA (KERNEL32.@)
1089 UINT WINAPI GetTempFileNameA( LPCSTR path, LPCSTR prefix, UINT unique,
1092 UNICODE_STRING pathW, prefixW;
1093 WCHAR bufferW[MAX_PATH];
1096 if ( !path || !prefix || !buffer )
1098 SetLastError( ERROR_INVALID_PARAMETER );
1102 RtlCreateUnicodeStringFromAsciiz(&pathW, path);
1103 RtlCreateUnicodeStringFromAsciiz(&prefixW, prefix);
1105 ret = GetTempFileNameW(pathW.Buffer, prefixW.Buffer, unique, bufferW);
1107 WideCharToMultiByte(CP_ACP, 0, bufferW, -1, buffer, MAX_PATH, NULL, NULL);
1109 RtlFreeUnicodeString(&pathW);
1110 RtlFreeUnicodeString(&prefixW);
1114 /***********************************************************************
1115 * GetTempFileNameW (KERNEL32.@)
1117 UINT WINAPI GetTempFileNameW( LPCWSTR path, LPCWSTR prefix, UINT unique,
1120 return FILE_GetTempFileName( path, prefix, unique, buffer );
1124 /***********************************************************************
1125 * GetTempFileName (KERNEL.97)
1127 UINT16 WINAPI GetTempFileName16( BYTE drive, LPCSTR prefix, UINT16 unique,
1130 char temppath[MAX_PATH];
1131 char *prefix16 = NULL;
1134 if (!(drive & ~TF_FORCEDRIVE)) /* drive 0 means current default drive */
1135 drive |= DRIVE_GetCurrentDrive() + 'A';
1137 if ((drive & TF_FORCEDRIVE) &&
1138 !DRIVE_IsValid( toupper(drive & ~TF_FORCEDRIVE) - 'A' ))
1140 drive &= ~TF_FORCEDRIVE;
1141 WARN("invalid drive %d specified\n", drive );
1144 if (drive & TF_FORCEDRIVE)
1145 sprintf(temppath,"%c:", drive & ~TF_FORCEDRIVE );
1147 GetTempPathA( MAX_PATH, temppath );
1151 prefix16 = HeapAlloc(GetProcessHeap(), 0, strlen(prefix) + 2);
1153 strcpy(prefix16 + 1, prefix);
1156 ret = GetTempFileNameA( temppath, prefix16, unique, buffer );
1158 if (prefix16) HeapFree(GetProcessHeap(), 0, prefix16);
1162 /***********************************************************************
1165 * Implementation of OpenFile16() and OpenFile32().
1167 static HFILE FILE_DoOpenFile( LPCSTR name, OFSTRUCT *ofs, UINT mode,
1173 WORD filedatetime[2];
1174 DOS_FULL_NAME full_name;
1175 DWORD access, sharing;
1177 WCHAR buffer[MAX_PATH];
1180 if (!ofs) return HFILE_ERROR;
1182 TRACE("%s %s %s %s%s%s%s%s%s%s%s%s\n",name,
1183 ((mode & 0x3 )==OF_READ)?"OF_READ":
1184 ((mode & 0x3 )==OF_WRITE)?"OF_WRITE":
1185 ((mode & 0x3 )==OF_READWRITE)?"OF_READWRITE":"unknown",
1186 ((mode & 0x70 )==OF_SHARE_COMPAT)?"OF_SHARE_COMPAT":
1187 ((mode & 0x70 )==OF_SHARE_DENY_NONE)?"OF_SHARE_DENY_NONE":
1188 ((mode & 0x70 )==OF_SHARE_DENY_READ)?"OF_SHARE_DENY_READ":
1189 ((mode & 0x70 )==OF_SHARE_DENY_WRITE)?"OF_SHARE_DENY_WRITE":
1190 ((mode & 0x70 )==OF_SHARE_EXCLUSIVE)?"OF_SHARE_EXCLUSIVE":"unknown",
1191 ((mode & OF_PARSE )==OF_PARSE)?"OF_PARSE ":"",
1192 ((mode & OF_DELETE )==OF_DELETE)?"OF_DELETE ":"",
1193 ((mode & OF_VERIFY )==OF_VERIFY)?"OF_VERIFY ":"",
1194 ((mode & OF_SEARCH )==OF_SEARCH)?"OF_SEARCH ":"",
1195 ((mode & OF_CANCEL )==OF_CANCEL)?"OF_CANCEL ":"",
1196 ((mode & OF_CREATE )==OF_CREATE)?"OF_CREATE ":"",
1197 ((mode & OF_PROMPT )==OF_PROMPT)?"OF_PROMPT ":"",
1198 ((mode & OF_EXIST )==OF_EXIST)?"OF_EXIST ":"",
1199 ((mode & OF_REOPEN )==OF_REOPEN)?"OF_REOPEN ":""
1203 ofs->cBytes = sizeof(OFSTRUCT);
1205 if (mode & OF_REOPEN) name = ofs->szPathName;
1208 ERR("called with `name' set to NULL ! Please debug.\n");
1212 TRACE("%s %04x\n", name, mode );
1214 /* the watcom 10.6 IDE relies on a valid path returned in ofs->szPathName
1215 Are there any cases where getting the path here is wrong?
1216 Uwe Bonnes 1997 Apr 2 */
1217 if (!GetFullPathNameA( name, sizeof(ofs->szPathName),
1218 ofs->szPathName, NULL )) goto error;
1219 FILE_ConvertOFMode( mode, &access, &sharing );
1221 /* OF_PARSE simply fills the structure */
1223 if (mode & OF_PARSE)
1225 ofs->fFixedDisk = (GetDriveType16( ofs->szPathName[0]-'A' )
1226 != DRIVE_REMOVABLE);
1227 TRACE("(%s): OF_PARSE, res = '%s'\n",
1228 name, ofs->szPathName );
1232 /* OF_CREATE is completely different from all other options, so
1235 if (mode & OF_CREATE)
1237 if ((handle = CreateFileA( name, GENERIC_READ | GENERIC_WRITE,
1238 sharing, NULL, CREATE_ALWAYS,
1239 FILE_ATTRIBUTE_NORMAL, 0 ))== INVALID_HANDLE_VALUE)
1244 MultiByteToWideChar(CP_ACP, 0, name, -1, buffer, MAX_PATH);
1247 /* If OF_SEARCH is set, ignore the given path */
1249 if ((mode & OF_SEARCH) && !(mode & OF_REOPEN))
1251 /* First try the file name as is */
1252 if (DOSFS_GetFullName( nameW, TRUE, &full_name )) goto found;
1253 /* Now remove the path */
1254 if (nameW[0] && (nameW[1] == ':')) nameW += 2;
1255 if ((p = strrchrW( nameW, '\\' ))) nameW = p + 1;
1256 if ((p = strrchrW( nameW, '/' ))) nameW = p + 1;
1257 if (!nameW[0]) goto not_found;
1260 /* Now look for the file */
1262 if (!DIR_SearchPath( NULL, nameW, NULL, &full_name, win32 )) goto not_found;
1265 TRACE("found %s = %s\n",
1266 full_name.long_name, debugstr_w(full_name.short_name) );
1267 WideCharToMultiByte(CP_ACP, 0, full_name.short_name, -1,
1268 ofs->szPathName, sizeof(ofs->szPathName), NULL, NULL);
1270 if (mode & OF_SHARE_EXCLUSIVE)
1271 /* Some InstallShield version uses OF_SHARE_EXCLUSIVE
1272 on the file <tempdir>/_ins0432._mp to determine how
1273 far installation has proceeded.
1274 _ins0432._mp is an executable and while running the
1275 application expects the open with OF_SHARE_ to fail*/
1277 As our loader closes the files after loading the executable,
1278 we can't find the running executable with FILE_InUse.
1279 The loader should keep the file open, as Windows does that, too.
1282 char *last = strrchr(full_name.long_name,'/');
1284 last = full_name.long_name - 1;
1285 if (GetModuleHandle16(last+1))
1287 TRACE("Denying shared open for %s\n",full_name.long_name);
1292 if (mode & OF_DELETE)
1294 if (unlink( full_name.long_name ) == -1) goto not_found;
1295 TRACE("(%s): OF_DELETE return = OK\n", name);
1299 handle = FILE_CreateFile( full_name.long_name, access, sharing,
1300 NULL, OPEN_EXISTING, 0, 0,
1301 DRIVE_GetFlags(full_name.drive) & DRIVE_FAIL_READ_ONLY,
1302 GetDriveTypeW( full_name.short_name ) );
1303 if (!handle) goto not_found;
1305 GetFileTime( handle, NULL, NULL, &filetime );
1306 FileTimeToDosDateTime( &filetime, &filedatetime[0], &filedatetime[1] );
1307 if ((mode & OF_VERIFY) && (mode & OF_REOPEN))
1309 if (memcmp( ofs->reserved, filedatetime, sizeof(ofs->reserved) ))
1311 CloseHandle( handle );
1312 WARN("(%s): OF_VERIFY failed\n", name );
1313 /* FIXME: what error here? */
1314 SetLastError( ERROR_FILE_NOT_FOUND );
1318 memcpy( ofs->reserved, filedatetime, sizeof(ofs->reserved) );
1320 success: /* We get here if the open was successful */
1321 TRACE("(%s): OK, return = %x\n", name, handle );
1324 hFileRet = (HFILE)handle;
1325 if (mode & OF_EXIST) /* Return the handle, but close it first */
1326 CloseHandle( handle );
1330 hFileRet = Win32HandleToDosFileHandle( handle );
1331 if (hFileRet == HFILE_ERROR16) goto error;
1332 if (mode & OF_EXIST) /* Return the handle, but close it first */
1333 _lclose16( hFileRet );
1337 not_found: /* We get here if the file does not exist */
1338 WARN("'%s' not found or sharing violation\n", name );
1339 SetLastError( ERROR_FILE_NOT_FOUND );
1342 error: /* We get here if there was an error opening the file */
1343 ofs->nErrCode = GetLastError();
1344 WARN("(%s): return = HFILE_ERROR error= %d\n",
1345 name,ofs->nErrCode );
1350 /***********************************************************************
1351 * OpenFile (KERNEL.74)
1352 * OpenFileEx (KERNEL.360)
1354 HFILE16 WINAPI OpenFile16( LPCSTR name, OFSTRUCT *ofs, UINT16 mode )
1356 return FILE_DoOpenFile( name, ofs, mode, FALSE );
1360 /***********************************************************************
1361 * OpenFile (KERNEL32.@)
1363 HFILE WINAPI OpenFile( LPCSTR name, OFSTRUCT *ofs, UINT mode )
1365 return FILE_DoOpenFile( name, ofs, mode, TRUE );
1369 /***********************************************************************
1370 * FILE_InitProcessDosHandles
1372 * Allocates the default DOS handles for a process. Called either by
1373 * Win32HandleToDosFileHandle below or by the DOSVM stuff.
1375 static void FILE_InitProcessDosHandles( void )
1377 HANDLE cp = GetCurrentProcess();
1378 DuplicateHandle(cp, GetStdHandle(STD_INPUT_HANDLE), cp, &dos_handles[0],
1379 0, TRUE, DUPLICATE_SAME_ACCESS);
1380 DuplicateHandle(cp, GetStdHandle(STD_OUTPUT_HANDLE), cp, &dos_handles[1],
1381 0, TRUE, DUPLICATE_SAME_ACCESS);
1382 DuplicateHandle(cp, GetStdHandle(STD_ERROR_HANDLE), cp, &dos_handles[2],
1383 0, TRUE, DUPLICATE_SAME_ACCESS);
1384 DuplicateHandle(cp, GetStdHandle(STD_ERROR_HANDLE), cp, &dos_handles[3],
1385 0, TRUE, DUPLICATE_SAME_ACCESS);
1386 DuplicateHandle(cp, GetStdHandle(STD_ERROR_HANDLE), cp, &dos_handles[4],
1387 0, TRUE, DUPLICATE_SAME_ACCESS);
1390 /***********************************************************************
1391 * Win32HandleToDosFileHandle (KERNEL32.21)
1393 * Allocate a DOS handle for a Win32 handle. The Win32 handle is no
1394 * longer valid after this function (even on failure).
1396 * Note: this is not exactly right, since on Win95 the Win32 handles
1397 * are on top of DOS handles and we do it the other way
1398 * around. Should be good enough though.
1400 HFILE WINAPI Win32HandleToDosFileHandle( HANDLE handle )
1404 if (!handle || (handle == INVALID_HANDLE_VALUE))
1407 for (i = 5; i < DOS_TABLE_SIZE; i++)
1408 if (!dos_handles[i])
1410 dos_handles[i] = handle;
1411 TRACE("Got %d for h32 %d\n", i, handle );
1414 CloseHandle( handle );
1415 SetLastError( ERROR_TOO_MANY_OPEN_FILES );
1420 /***********************************************************************
1421 * DosFileHandleToWin32Handle (KERNEL32.20)
1423 * Return the Win32 handle for a DOS handle.
1425 * Note: this is not exactly right, since on Win95 the Win32 handles
1426 * are on top of DOS handles and we do it the other way
1427 * around. Should be good enough though.
1429 HANDLE WINAPI DosFileHandleToWin32Handle( HFILE handle )
1431 HFILE16 hfile = (HFILE16)handle;
1432 if (hfile < 5 && !dos_handles[hfile]) FILE_InitProcessDosHandles();
1433 if ((hfile >= DOS_TABLE_SIZE) || !dos_handles[hfile])
1435 SetLastError( ERROR_INVALID_HANDLE );
1436 return INVALID_HANDLE_VALUE;
1438 return dos_handles[hfile];
1442 /***********************************************************************
1443 * DisposeLZ32Handle (KERNEL32.22)
1445 * Note: this is not entirely correct, we should only close the
1446 * 32-bit handle and not the 16-bit one, but we cannot do
1447 * this because of the way our DOS handles are implemented.
1448 * It shouldn't break anything though.
1450 void WINAPI DisposeLZ32Handle( HANDLE handle )
1454 if (!handle || (handle == INVALID_HANDLE_VALUE)) return;
1456 for (i = 5; i < DOS_TABLE_SIZE; i++)
1457 if (dos_handles[i] == handle)
1460 CloseHandle( handle );
1466 /***********************************************************************
1469 * dup2() function for DOS handles.
1471 HFILE16 FILE_Dup2( HFILE16 hFile1, HFILE16 hFile2 )
1475 if (hFile1 < 5 && !dos_handles[hFile1]) FILE_InitProcessDosHandles();
1477 if ((hFile1 >= DOS_TABLE_SIZE) || (hFile2 >= DOS_TABLE_SIZE) || !dos_handles[hFile1])
1479 SetLastError( ERROR_INVALID_HANDLE );
1480 return HFILE_ERROR16;
1482 if (!DuplicateHandle( GetCurrentProcess(), dos_handles[hFile1],
1483 GetCurrentProcess(), &new_handle,
1484 0, FALSE, DUPLICATE_SAME_ACCESS ))
1485 return HFILE_ERROR16;
1486 if (dos_handles[hFile2]) CloseHandle( dos_handles[hFile2] );
1487 dos_handles[hFile2] = new_handle;
1492 /***********************************************************************
1493 * _lclose (KERNEL.81)
1495 HFILE16 WINAPI _lclose16( HFILE16 hFile )
1497 if ((hFile >= DOS_TABLE_SIZE) || !dos_handles[hFile])
1499 SetLastError( ERROR_INVALID_HANDLE );
1500 return HFILE_ERROR16;
1502 TRACE("%d (handle32=%d)\n", hFile, dos_handles[hFile] );
1503 CloseHandle( dos_handles[hFile] );
1504 dos_handles[hFile] = 0;
1509 /***********************************************************************
1510 * _lclose (KERNEL32.@)
1512 HFILE WINAPI _lclose( HFILE hFile )
1514 TRACE("handle %d\n", hFile );
1515 return CloseHandle( (HANDLE)hFile ) ? 0 : HFILE_ERROR;
1518 /***********************************************************************
1519 * GetOverlappedResult (KERNEL32.@)
1521 * Check the result of an Asynchronous data transfer from a file.
1527 * If successful (and relevant) lpTransferred will hold the number of
1528 * bytes transferred during the async operation.
1532 * Currently only works for WaitCommEvent, ReadFile, WriteFile
1533 * with communications ports.
1536 BOOL WINAPI GetOverlappedResult(
1537 HANDLE hFile, /* [in] handle of file to check on */
1538 LPOVERLAPPED lpOverlapped, /* [in/out] pointer to overlapped */
1539 LPDWORD lpTransferred, /* [in/out] number of bytes transferred */
1540 BOOL bWait /* [in] wait for the transfer to complete ? */
1544 TRACE("(%d %p %p %x)\n", hFile, lpOverlapped, lpTransferred, bWait);
1546 if(lpOverlapped==NULL)
1548 ERR("lpOverlapped was null\n");
1551 if(!lpOverlapped->hEvent)
1553 ERR("lpOverlapped->hEvent was null\n");
1558 TRACE("waiting on %p\n",lpOverlapped);
1559 r = WaitForSingleObjectEx(lpOverlapped->hEvent, bWait?INFINITE:0, TRUE);
1560 TRACE("wait on %p returned %ld\n",lpOverlapped,r);
1561 } while (r==STATUS_USER_APC);
1564 *lpTransferred = lpOverlapped->InternalHigh;
1566 SetLastError ( lpOverlapped->Internal == STATUS_PENDING ?
1567 ERROR_IO_INCOMPLETE : RtlNtStatusToDosError ( lpOverlapped->Internal ) );
1569 return (r==WAIT_OBJECT_0);
1572 /***********************************************************************
1573 * CancelIo (KERNEL32.@)
1575 BOOL WINAPI CancelIo(HANDLE handle)
1577 async_private *ovp,*t;
1579 TRACE("handle = %x\n",handle);
1581 for (ovp = NtCurrentTeb()->pending_list; ovp; ovp = t)
1584 if ( ovp->handle == handle )
1585 cancel_async ( ovp );
1587 WaitForMultipleObjectsEx(0,NULL,FALSE,1,TRUE);
1591 /***********************************************************************
1592 * FILE_AsyncReadService (INTERNAL)
1594 * This function is called while the client is waiting on the
1595 * server, so we can't make any server calls here.
1597 static void FILE_AsyncReadService(async_private *ovp)
1599 async_fileio *fileio = (async_fileio*) ovp;
1600 LPOVERLAPPED lpOverlapped = fileio->lpOverlapped;
1602 int already = lpOverlapped->InternalHigh;
1604 TRACE("%p %p\n", lpOverlapped, fileio->buffer );
1606 /* check to see if the data is ready (non-blocking) */
1608 if ( fileio->fd_type == FD_TYPE_SOCKET )
1609 result = read (ovp->fd, &fileio->buffer[already], fileio->count - already);
1612 result = pread (ovp->fd, &fileio->buffer[already], fileio->count - already,
1613 OVERLAPPED_OFFSET (lpOverlapped) + already);
1614 if ((result < 0) && (errno == ESPIPE))
1615 result = read (ovp->fd, &fileio->buffer[already], fileio->count - already);
1618 if ( (result<0) && ((errno == EAGAIN) || (errno == EINTR)))
1620 TRACE("Deferred read %d\n",errno);
1625 /* check to see if the transfer is complete */
1628 r = FILE_GetNtStatus ();
1632 lpOverlapped->InternalHigh += result;
1633 TRACE("read %d more bytes %ld/%d so far\n",result,lpOverlapped->InternalHigh,fileio->count);
1635 if(lpOverlapped->InternalHigh >= fileio->count || fileio->fd_type == FD_TYPE_SOCKET )
1641 lpOverlapped->Internal = r;
1644 /***********************************************************************
1645 * FILE_ReadFileEx (INTERNAL)
1647 static BOOL FILE_ReadFileEx(HANDLE hFile, LPVOID buffer, DWORD bytesToRead,
1648 LPOVERLAPPED overlapped,
1649 LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine,
1657 TRACE("file %d to buf %p num %ld %p func %p\n",
1658 hFile, buffer, bytesToRead, overlapped, lpCompletionRoutine);
1660 /* check that there is an overlapped struct */
1661 if (overlapped==NULL)
1663 SetLastError(ERROR_INVALID_PARAMETER);
1667 fd = FILE_GetUnixHandleType ( hFile, GENERIC_READ, &type, &flags);
1670 WARN ( "Couldn't get FD\n" );
1674 ovp = (async_fileio*) HeapAlloc(GetProcessHeap(), 0, sizeof (async_fileio));
1677 TRACE("HeapAlloc Failed\n");
1678 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1682 ovp->async.ops = ( lpCompletionRoutine ? &fileio_async_ops : &fileio_nocomp_async_ops );
1683 ovp->async.handle = hFile;
1685 ovp->async.type = ASYNC_TYPE_READ;
1686 ovp->async.func = FILE_AsyncReadService;
1687 ovp->async.event = hEvent;
1688 ovp->lpOverlapped = overlapped;
1689 ovp->count = bytesToRead;
1690 ovp->completion_func = lpCompletionRoutine;
1691 ovp->buffer = buffer;
1692 ovp->fd_type = type;
1694 return !register_new_async (&ovp->async);
1702 /***********************************************************************
1703 * ReadFileEx (KERNEL32.@)
1705 BOOL WINAPI ReadFileEx(HANDLE hFile, LPVOID buffer, DWORD bytesToRead,
1706 LPOVERLAPPED overlapped,
1707 LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine)
1709 overlapped->InternalHigh = 0;
1710 return FILE_ReadFileEx(hFile,buffer,bytesToRead,overlapped,lpCompletionRoutine, INVALID_HANDLE_VALUE);
1713 static BOOL FILE_TimeoutRead(HANDLE hFile, LPVOID buffer, DWORD bytesToRead, LPDWORD bytesRead)
1718 TRACE("%d %p %ld %p\n", hFile, buffer, bytesToRead, bytesRead );
1720 ZeroMemory(&ov, sizeof (OVERLAPPED));
1721 if(STATUS_SUCCESS==NtCreateEvent(&ov.hEvent, SYNCHRONIZE, NULL, 0, 0))
1723 if(FILE_ReadFileEx(hFile, buffer, bytesToRead, &ov, NULL, ov.hEvent))
1725 r = GetOverlappedResult(hFile, &ov, bytesRead, TRUE);
1728 CloseHandle(ov.hEvent);
1732 /***********************************************************************
1733 * ReadFile (KERNEL32.@)
1735 BOOL WINAPI ReadFile( HANDLE hFile, LPVOID buffer, DWORD bytesToRead,
1736 LPDWORD bytesRead, LPOVERLAPPED overlapped )
1738 int unix_handle, result, flags;
1741 TRACE("%d %p %ld %p %p\n", hFile, buffer, bytesToRead,
1742 bytesRead, overlapped );
1744 if (bytesRead) *bytesRead = 0; /* Do this before anything else */
1745 if (!bytesToRead) return TRUE;
1747 unix_handle = FILE_GetUnixHandleType( hFile, GENERIC_READ, &type, &flags );
1749 if (flags & FD_FLAG_OVERLAPPED)
1751 if (unix_handle == -1) return FALSE;
1752 if ( (overlapped==NULL) || NtResetEvent( overlapped->hEvent, NULL ) )
1754 TRACE("Overlapped not specified or invalid event flag\n");
1756 SetLastError(ERROR_INVALID_PARAMETER);
1761 overlapped->InternalHigh = 0;
1763 if(!FILE_ReadFileEx(hFile, buffer, bytesToRead, overlapped, NULL, overlapped->hEvent))
1766 if ( !GetOverlappedResult (hFile, overlapped, bytesRead, FALSE) )
1768 if ( GetLastError() == ERROR_IO_INCOMPLETE )
1769 SetLastError ( ERROR_IO_PENDING );
1775 if (flags & FD_FLAG_TIMEOUT)
1778 return FILE_TimeoutRead(hFile, buffer, bytesToRead, bytesRead);
1783 return SMB_ReadFile(hFile, buffer, bytesToRead, bytesRead, NULL);
1785 case FD_TYPE_CONSOLE:
1786 return FILE_ReadConsole(hFile, buffer, bytesToRead, bytesRead, NULL);
1788 case FD_TYPE_DEFAULT:
1789 /* normal unix files */
1790 if (unix_handle == -1) return FALSE;
1793 DWORD highOffset = overlapped->OffsetHigh;
1794 if ( (INVALID_SET_FILE_POINTER == SetFilePointer(hFile, overlapped->Offset,
1795 &highOffset, FILE_BEGIN)) &&
1796 (GetLastError() != NO_ERROR) )
1805 if (unix_handle == -1)
1811 off_t offset = OVERLAPPED_OFFSET(overlapped);
1812 if(lseek(unix_handle, offset, SEEK_SET) == -1)
1815 SetLastError(ERROR_INVALID_PARAMETER);
1820 /* code for synchronous reads */
1821 while ((result = read( unix_handle, buffer, bytesToRead )) == -1)
1823 if ((errno == EAGAIN) || (errno == EINTR)) continue;
1824 if ((errno == EFAULT) && !IsBadWritePtr( buffer, bytesToRead )) continue;
1828 close( unix_handle );
1829 if (result == -1) return FALSE;
1830 if (bytesRead) *bytesRead = result;
1835 /***********************************************************************
1836 * FILE_AsyncWriteService (INTERNAL)
1838 * This function is called while the client is waiting on the
1839 * server, so we can't make any server calls here.
1841 static void FILE_AsyncWriteService(struct async_private *ovp)
1843 async_fileio *fileio = (async_fileio *) ovp;
1844 LPOVERLAPPED lpOverlapped = fileio->lpOverlapped;
1846 int already = lpOverlapped->InternalHigh;
1848 TRACE("(%p %p)\n",lpOverlapped,fileio->buffer);
1850 /* write some data (non-blocking) */
1852 if ( fileio->fd_type == FD_TYPE_SOCKET )
1853 result = write(ovp->fd, &fileio->buffer[already], fileio->count - already);
1856 result = pwrite(ovp->fd, &fileio->buffer[already], fileio->count - already,
1857 OVERLAPPED_OFFSET (lpOverlapped) + already);
1858 if ((result < 0) && (errno == ESPIPE))
1859 result = write(ovp->fd, &fileio->buffer[already], fileio->count - already);
1862 if ( (result<0) && ((errno == EAGAIN) || (errno == EINTR)))
1868 /* check to see if the transfer is complete */
1871 r = FILE_GetNtStatus ();
1875 lpOverlapped->InternalHigh += result;
1877 TRACE("wrote %d more bytes %ld/%d so far\n",result,lpOverlapped->InternalHigh,fileio->count);
1879 if(lpOverlapped->InternalHigh < fileio->count)
1885 lpOverlapped->Internal = r;
1888 /***********************************************************************
1891 static BOOL FILE_WriteFileEx(HANDLE hFile, LPCVOID buffer, DWORD bytesToWrite,
1892 LPOVERLAPPED overlapped,
1893 LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine,
1901 TRACE("file %d to buf %p num %ld %p func %p handle %d\n",
1902 hFile, buffer, bytesToWrite, overlapped, lpCompletionRoutine, hEvent);
1904 if (overlapped == NULL)
1906 SetLastError(ERROR_INVALID_PARAMETER);
1910 fd = FILE_GetUnixHandleType ( hFile, GENERIC_WRITE, &type, &flags );
1913 TRACE( "Couldn't get FD\n" );
1917 ovp = (async_fileio*) HeapAlloc(GetProcessHeap(), 0, sizeof (async_fileio));
1920 TRACE("HeapAlloc Failed\n");
1921 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1925 ovp->async.ops = ( lpCompletionRoutine ? &fileio_async_ops : &fileio_nocomp_async_ops );
1926 ovp->async.handle = hFile;
1928 ovp->async.type = ASYNC_TYPE_WRITE;
1929 ovp->async.func = FILE_AsyncWriteService;
1930 ovp->lpOverlapped = overlapped;
1931 ovp->async.event = hEvent;
1932 ovp->buffer = (LPVOID) buffer;
1933 ovp->count = bytesToWrite;
1934 ovp->completion_func = lpCompletionRoutine;
1935 ovp->fd_type = type;
1937 return !register_new_async (&ovp->async);
1944 /***********************************************************************
1945 * WriteFileEx (KERNEL32.@)
1947 BOOL WINAPI WriteFileEx(HANDLE hFile, LPCVOID buffer, DWORD bytesToWrite,
1948 LPOVERLAPPED overlapped,
1949 LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine)
1951 overlapped->InternalHigh = 0;
1953 return FILE_WriteFileEx(hFile, buffer, bytesToWrite, overlapped, lpCompletionRoutine, INVALID_HANDLE_VALUE);
1956 /***********************************************************************
1957 * WriteFile (KERNEL32.@)
1959 BOOL WINAPI WriteFile( HANDLE hFile, LPCVOID buffer, DWORD bytesToWrite,
1960 LPDWORD bytesWritten, LPOVERLAPPED overlapped )
1962 int unix_handle, result, flags;
1965 TRACE("%d %p %ld %p %p\n", hFile, buffer, bytesToWrite,
1966 bytesWritten, overlapped );
1968 if (bytesWritten) *bytesWritten = 0; /* Do this before anything else */
1969 if (!bytesToWrite) return TRUE;
1971 unix_handle = FILE_GetUnixHandleType( hFile, GENERIC_WRITE, &type, &flags );
1973 if (flags & FD_FLAG_OVERLAPPED)
1975 if (unix_handle == -1) return FALSE;
1976 if ( (overlapped==NULL) || NtResetEvent( overlapped->hEvent, NULL ) )
1978 TRACE("Overlapped not specified or invalid event flag\n");
1980 SetLastError(ERROR_INVALID_PARAMETER);
1985 overlapped->InternalHigh = 0;
1987 if(!FILE_WriteFileEx(hFile, buffer, bytesToWrite, overlapped, NULL, overlapped->hEvent))
1990 if ( !GetOverlappedResult (hFile, overlapped, bytesWritten, FALSE) )
1992 if ( GetLastError() == ERROR_IO_INCOMPLETE )
1993 SetLastError ( ERROR_IO_PENDING );
2002 case FD_TYPE_CONSOLE:
2003 TRACE("%d %s %ld %p %p\n", hFile, debugstr_an(buffer, bytesToWrite), bytesToWrite,
2004 bytesWritten, overlapped );
2005 return FILE_WriteConsole(hFile, buffer, bytesToWrite, bytesWritten, NULL);
2007 case FD_TYPE_DEFAULT:
2008 if (unix_handle == -1) return FALSE;
2012 DWORD highOffset = overlapped->OffsetHigh;
2013 if ( (INVALID_SET_FILE_POINTER == SetFilePointer(hFile, overlapped->Offset,
2014 &highOffset, FILE_BEGIN)) &&
2015 (GetLastError() != NO_ERROR) )
2024 if (unix_handle == -1)
2029 SetLastError(ERROR_INVALID_PARAMETER);
2037 off_t offset = OVERLAPPED_OFFSET(overlapped);
2038 if(lseek(unix_handle, offset, SEEK_SET) == -1)
2041 SetLastError(ERROR_INVALID_PARAMETER);
2046 /* synchronous file write */
2047 while ((result = write( unix_handle, buffer, bytesToWrite )) == -1)
2049 if ((errno == EAGAIN) || (errno == EINTR)) continue;
2050 if ((errno == EFAULT) && !IsBadReadPtr( buffer, bytesToWrite )) continue;
2051 if (errno == ENOSPC)
2052 SetLastError( ERROR_DISK_FULL );
2057 close( unix_handle );
2058 if (result == -1) return FALSE;
2059 if (bytesWritten) *bytesWritten = result;
2064 /***********************************************************************
2065 * _hread (KERNEL.349)
2067 LONG WINAPI WIN16_hread( HFILE16 hFile, SEGPTR buffer, LONG count )
2071 TRACE("%d %08lx %ld\n",
2072 hFile, (DWORD)buffer, count );
2074 /* Some programs pass a count larger than the allocated buffer */
2075 maxlen = GetSelectorLimit16( SELECTOROF(buffer) ) - OFFSETOF(buffer) + 1;
2076 if (count > maxlen) count = maxlen;
2077 return _lread((HFILE)DosFileHandleToWin32Handle(hFile), MapSL(buffer), count );
2081 /***********************************************************************
2082 * _lread (KERNEL.82)
2084 UINT16 WINAPI WIN16_lread( HFILE16 hFile, SEGPTR buffer, UINT16 count )
2086 return (UINT16)WIN16_hread( hFile, buffer, (LONG)count );
2090 /***********************************************************************
2091 * _lread (KERNEL32.@)
2093 UINT WINAPI _lread( HFILE handle, LPVOID buffer, UINT count )
2096 if (!ReadFile( (HANDLE)handle, buffer, count, &result, NULL )) return -1;
2101 /***********************************************************************
2102 * _lread16 (KERNEL.82)
2104 UINT16 WINAPI _lread16( HFILE16 hFile, LPVOID buffer, UINT16 count )
2106 return (UINT16)_lread((HFILE)DosFileHandleToWin32Handle(hFile), buffer, (LONG)count );
2110 /***********************************************************************
2111 * _lcreat (KERNEL.83)
2113 HFILE16 WINAPI _lcreat16( LPCSTR path, INT16 attr )
2115 return Win32HandleToDosFileHandle( (HANDLE)_lcreat( path, attr ) );
2119 /***********************************************************************
2120 * _lcreat (KERNEL32.@)
2122 HFILE WINAPI _lcreat( LPCSTR path, INT attr )
2124 /* Mask off all flags not explicitly allowed by the doc */
2125 attr &= FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM;
2126 TRACE("%s %02x\n", path, attr );
2127 return (HFILE)CreateFileA( path, GENERIC_READ | GENERIC_WRITE,
2128 FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
2129 CREATE_ALWAYS, attr, 0 );
2133 /***********************************************************************
2134 * SetFilePointer (KERNEL32.@)
2136 DWORD WINAPI SetFilePointer( HANDLE hFile, LONG distance, LONG *highword,
2139 DWORD ret = INVALID_SET_FILE_POINTER;
2141 TRACE("handle %d offset %ld high %ld origin %ld\n",
2142 hFile, distance, highword?*highword:0, method );
2144 SERVER_START_REQ( set_file_pointer )
2146 req->handle = hFile;
2147 req->low = distance;
2148 req->high = highword ? *highword : (distance >= 0) ? 0 : -1;
2149 /* FIXME: assumes 1:1 mapping between Windows and Unix seek constants */
2150 req->whence = method;
2152 if (!wine_server_call_err( req ))
2154 ret = reply->new_low;
2155 if (highword) *highword = reply->new_high;
2163 /***********************************************************************
2164 * _llseek (KERNEL.84)
2167 * Seeking before the start of the file should be allowed for _llseek16,
2168 * but cause subsequent I/O operations to fail (cf. interrupt list)
2171 LONG WINAPI _llseek16( HFILE16 hFile, LONG lOffset, INT16 nOrigin )
2173 return SetFilePointer( DosFileHandleToWin32Handle(hFile), lOffset, NULL, nOrigin );
2177 /***********************************************************************
2178 * _llseek (KERNEL32.@)
2180 LONG WINAPI _llseek( HFILE hFile, LONG lOffset, INT nOrigin )
2182 return SetFilePointer( (HANDLE)hFile, lOffset, NULL, nOrigin );
2186 /***********************************************************************
2187 * _lopen (KERNEL.85)
2189 HFILE16 WINAPI _lopen16( LPCSTR path, INT16 mode )
2191 return Win32HandleToDosFileHandle( (HANDLE)_lopen( path, mode ) );
2195 /***********************************************************************
2196 * _lopen (KERNEL32.@)
2198 HFILE WINAPI _lopen( LPCSTR path, INT mode )
2200 DWORD access, sharing;
2202 TRACE("('%s',%04x)\n", path, mode );
2203 FILE_ConvertOFMode( mode, &access, &sharing );
2204 return (HFILE)CreateFileA( path, access, sharing, NULL, OPEN_EXISTING, 0, 0 );
2208 /***********************************************************************
2209 * _lwrite (KERNEL.86)
2211 UINT16 WINAPI _lwrite16( HFILE16 hFile, LPCSTR buffer, UINT16 count )
2213 return (UINT16)_hwrite( (HFILE)DosFileHandleToWin32Handle(hFile), buffer, (LONG)count );
2216 /***********************************************************************
2217 * _lwrite (KERNEL32.@)
2219 UINT WINAPI _lwrite( HFILE hFile, LPCSTR buffer, UINT count )
2221 return (UINT)_hwrite( hFile, buffer, (LONG)count );
2225 /***********************************************************************
2226 * _hread16 (KERNEL.349)
2228 LONG WINAPI _hread16( HFILE16 hFile, LPVOID buffer, LONG count)
2230 return _lread( (HFILE)DosFileHandleToWin32Handle(hFile), buffer, count );
2234 /***********************************************************************
2235 * _hread (KERNEL32.@)
2237 LONG WINAPI _hread( HFILE hFile, LPVOID buffer, LONG count)
2239 return _lread( hFile, buffer, count );
2243 /***********************************************************************
2244 * _hwrite (KERNEL.350)
2246 LONG WINAPI _hwrite16( HFILE16 hFile, LPCSTR buffer, LONG count )
2248 return _hwrite( (HFILE)DosFileHandleToWin32Handle(hFile), buffer, count );
2252 /***********************************************************************
2253 * _hwrite (KERNEL32.@)
2255 * experimentation yields that _lwrite:
2256 * o truncates the file at the current position with
2258 * o returns 0 on a 0 length write
2259 * o works with console handles
2262 LONG WINAPI _hwrite( HFILE handle, LPCSTR buffer, LONG count )
2266 TRACE("%d %p %ld\n", handle, buffer, count );
2270 /* Expand or truncate at current position */
2271 if (!SetEndOfFile( (HANDLE)handle )) return HFILE_ERROR;
2274 if (!WriteFile( (HANDLE)handle, buffer, count, &result, NULL ))
2280 /***********************************************************************
2281 * SetHandleCount (KERNEL.199)
2283 UINT16 WINAPI SetHandleCount16( UINT16 count )
2285 return SetHandleCount( count );
2289 /*************************************************************************
2290 * SetHandleCount (KERNEL32.@)
2292 UINT WINAPI SetHandleCount( UINT count )
2294 return min( 256, count );
2298 /***********************************************************************
2299 * FlushFileBuffers (KERNEL32.@)
2301 BOOL WINAPI FlushFileBuffers( HANDLE hFile )
2304 SERVER_START_REQ( flush_file )
2306 req->handle = hFile;
2307 ret = !wine_server_call_err( req );
2314 /**************************************************************************
2315 * SetEndOfFile (KERNEL32.@)
2317 BOOL WINAPI SetEndOfFile( HANDLE hFile )
2320 SERVER_START_REQ( truncate_file )
2322 req->handle = hFile;
2323 ret = !wine_server_call_err( req );
2330 /***********************************************************************
2331 * DeleteFile (KERNEL.146)
2333 BOOL16 WINAPI DeleteFile16( LPCSTR path )
2335 return DeleteFileA( path );
2339 /***********************************************************************
2340 * DeleteFileW (KERNEL32.@)
2342 BOOL WINAPI DeleteFileW( LPCWSTR path )
2344 DOS_FULL_NAME full_name;
2349 SetLastError(ERROR_INVALID_PARAMETER);
2352 TRACE("%s\n", debugstr_w(path) );
2356 ERR("Empty path passed\n");
2359 if (DOSFS_GetDevice( path ))
2361 WARN("cannot remove DOS device %s!\n", debugstr_w(path));
2362 SetLastError( ERROR_FILE_NOT_FOUND );
2366 if (!DOSFS_GetFullName( path, TRUE, &full_name )) return FALSE;
2368 /* check if we are allowed to delete the source */
2369 hFile = FILE_CreateFile( full_name.long_name, GENERIC_READ|GENERIC_WRITE, 0,
2370 NULL, OPEN_EXISTING, 0, 0, TRUE,
2371 GetDriveTypeW( full_name.short_name ) );
2372 if (!hFile) return FALSE;
2374 if (unlink( full_name.long_name ) == -1)
2385 /***********************************************************************
2386 * DeleteFileA (KERNEL32.@)
2388 BOOL WINAPI DeleteFileA( LPCSTR path )
2390 UNICODE_STRING pathW;
2395 SetLastError(ERROR_INVALID_PARAMETER);
2399 if (RtlCreateUnicodeStringFromAsciiz(&pathW, path))
2401 ret = DeleteFileW(pathW.Buffer);
2402 RtlFreeUnicodeString(&pathW);
2405 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
2410 /***********************************************************************
2411 * GetFileType (KERNEL32.@)
2413 DWORD WINAPI GetFileType( HANDLE hFile )
2415 DWORD ret = FILE_TYPE_UNKNOWN;
2416 SERVER_START_REQ( get_file_info )
2418 req->handle = hFile;
2419 if (!wine_server_call_err( req )) ret = reply->type;
2426 /* check if a file name is for an executable file (.exe or .com) */
2427 inline static BOOL is_executable( const char *name )
2429 int len = strlen(name);
2431 if (len < 4) return FALSE;
2432 return (!strcasecmp( name + len - 4, ".exe" ) ||
2433 !strcasecmp( name + len - 4, ".com" ));
2437 /***********************************************************************
2438 * FILE_AddBootRenameEntry
2440 * Adds an entry to the registry that is loaded when windows boots and
2441 * checks if there are some files to be removed or renamed/moved.
2442 * <fn1> has to be valid and <fn2> may be NULL. If both pointers are
2443 * non-NULL then the file is moved, otherwise it is deleted. The
2444 * entry of the registrykey is always appended with two zero
2445 * terminated strings. If <fn2> is NULL then the second entry is
2446 * simply a single 0-byte. Otherwise the second filename goes
2447 * there. The entries are prepended with \??\ before the path and the
2448 * second filename gets also a '!' as the first character if
2449 * MOVEFILE_REPLACE_EXISTING is set. After the final string another
2450 * 0-byte follows to indicate the end of the strings.
2452 * \??\D:\test\file1[0]
2453 * !\??\D:\test\file1_renamed[0]
2454 * \??\D:\Test|delete[0]
2455 * [0] <- file is to be deleted, second string empty
2456 * \??\D:\test\file2[0]
2457 * !\??\D:\test\file2_renamed[0]
2458 * [0] <- indicates end of strings
2461 * \??\D:\test\file1[0]
2462 * !\??\D:\test\file1_renamed[0]
2463 * \??\D:\Test|delete[0]
2464 * [0] <- file is to be deleted, second string empty
2465 * [0] <- indicates end of strings
2468 static BOOL FILE_AddBootRenameEntry( LPCWSTR fn1, LPCWSTR fn2, DWORD flags )
2470 static const WCHAR PreString[] = {'\\','?','?','\\',0};
2471 static const WCHAR ValueName[] = {'P','e','n','d','i','n','g',
2472 'F','i','l','e','R','e','n','a','m','e',
2473 'O','p','e','r','a','t','i','o','n','s',0};
2476 DWORD Type, len0, len1, len2;
2478 BYTE *Buffer = NULL;
2481 if(RegCreateKeyA(HKEY_LOCAL_MACHINE, "SYSTEM\\CurrentControlSet\\Control\\Session Manager",
2482 &Reboot) != ERROR_SUCCESS)
2484 WARN("Error creating key for reboot managment [%s]\n",
2485 "SYSTEM\\CurrentControlSet\\Control\\Session Manager");
2489 len0 = strlenW(PreString);
2490 len1 = strlenW(fn1) + len0 + 1;
2493 len2 = strlenW(fn2) + len0 + 1;
2494 if (flags & MOVEFILE_REPLACE_EXISTING) len2++; /* Plus 1 because of the leading '!' */
2496 else len2 = 1; /* minimum is the 0 characters for the empty second string */
2498 /* convert characters to bytes */
2499 len0 *= sizeof(WCHAR);
2500 len1 *= sizeof(WCHAR);
2501 len2 *= sizeof(WCHAR);
2503 /* First we check if the key exists and if so how many bytes it already contains. */
2504 if (RegQueryValueExW(Reboot, ValueName, NULL, &Type, NULL, &DataSize) == ERROR_SUCCESS)
2506 if (Type != REG_MULTI_SZ) goto Quit;
2507 if (!(Buffer = HeapAlloc( GetProcessHeap(), 0, DataSize + len1 + len2 + sizeof(WCHAR) ))) goto Quit;
2508 if (RegQueryValueExW(Reboot, ValueName, NULL, &Type, Buffer, &DataSize) != ERROR_SUCCESS)
2510 if (DataSize) DataSize -= sizeof(WCHAR); /* remove terminating null (will be added back later) */
2514 if (!(Buffer = HeapAlloc( GetProcessHeap(), 0, len1 + len2 + sizeof(WCHAR) ))) goto Quit;
2518 p = (WCHAR *)(Buffer + DataSize);
2519 strcpyW( p, PreString );
2524 p = (WCHAR *)(Buffer + DataSize);
2525 if (flags & MOVEFILE_REPLACE_EXISTING)
2527 strcpyW( p, PreString );
2533 p = (WCHAR *)(Buffer + DataSize);
2535 DataSize += sizeof(WCHAR);
2538 /* add final null */
2539 p = (WCHAR *)(Buffer + DataSize);
2541 DataSize += sizeof(WCHAR);
2542 rc = !RegSetValueExW( Reboot, ValueName, 0, REG_MULTI_SZ, Buffer, DataSize );
2545 if (Reboot) RegCloseKey(Reboot);
2546 if (Buffer) HeapFree( GetProcessHeap(), 0, Buffer );
2551 /**************************************************************************
2552 * MoveFileExW (KERNEL32.@)
2554 BOOL WINAPI MoveFileExW( LPCWSTR fn1, LPCWSTR fn2, DWORD flag )
2556 DOS_FULL_NAME full_name1, full_name2;
2559 TRACE("(%s,%s,%04lx)\n", debugstr_w(fn1), debugstr_w(fn2), flag);
2561 /* FIXME: <Gerhard W. Gruber>sparhawk@gmx.at
2562 In case of W9x and lesser this function should return 120 (ERROR_CALL_NOT_IMPLEMENTED)
2563 to be really compatible. Most programs wont have any problems though. In case
2564 you encounter one, this is what you should return here. I don't know what's up
2565 with NT 3.5. Is this function available there or not?
2566 Does anybody really care about 3.5? :)
2569 /* Filename1 has to be always set to a valid path. Filename2 may be NULL
2570 if the source file has to be deleted.
2573 SetLastError(ERROR_INVALID_PARAMETER);
2577 /* This function has to be run through in order to process the name properly.
2578 If the BOOTDELAY flag is set, the file doesn't need to exist though. At least
2579 that is the behaviour on NT 4.0. The operation accepts the filenames as
2580 they are given but it can't reply with a reasonable returncode. Success
2581 means in that case success for entering the values into the registry.
2583 if(!DOSFS_GetFullName( fn1, TRUE, &full_name1 ))
2585 if(!(flag & MOVEFILE_DELAY_UNTIL_REBOOT))
2589 if (fn2) /* !fn2 means delete fn1 */
2591 if (DOSFS_GetFullName( fn2, TRUE, &full_name2 ))
2593 if(!(flag & MOVEFILE_DELAY_UNTIL_REBOOT))
2595 /* target exists, check if we may overwrite */
2596 if (!(flag & MOVEFILE_REPLACE_EXISTING))
2598 /* FIXME: Use right error code */
2599 SetLastError( ERROR_ACCESS_DENIED );
2606 if (!DOSFS_GetFullName( fn2, FALSE, &full_name2 ))
2608 if(!(flag & MOVEFILE_DELAY_UNTIL_REBOOT))
2613 /* Source name and target path are valid */
2615 if (flag & MOVEFILE_DELAY_UNTIL_REBOOT)
2617 /* FIXME: (bon@elektron.ikp.physik.th-darmstadt.de 970706)
2618 Perhaps we should queue these command and execute it
2619 when exiting... What about using on_exit(2)
2621 FIXME("Please move existing file %s to file %s when Wine has finished\n",
2622 debugstr_w(fn1), debugstr_w(fn2));
2623 return FILE_AddBootRenameEntry( fn1, fn2, flag );
2626 /* check if we are allowed to rename the source */
2627 hFile = FILE_CreateFile( full_name1.long_name, 0, 0,
2628 NULL, OPEN_EXISTING, 0, 0, TRUE,
2629 GetDriveTypeW( full_name1.short_name ) );
2634 if (GetLastError() != ERROR_ACCESS_DENIED) return FALSE;
2635 attr = GetFileAttributesA( full_name1.long_name );
2636 if (attr == (DWORD)-1 || !(attr & FILE_ATTRIBUTE_DIRECTORY)) return FALSE;
2637 /* if it's a directory we can continue */
2639 else CloseHandle(hFile);
2641 /* check, if we are allowed to delete the destination,
2642 ** (but the file not being there is fine) */
2643 hFile = FILE_CreateFile( full_name2.long_name, GENERIC_READ|GENERIC_WRITE, 0,
2644 NULL, OPEN_EXISTING, 0, 0, TRUE,
2645 GetDriveTypeW( full_name2.short_name ) );
2646 if(!hFile && GetLastError() != ERROR_FILE_NOT_FOUND) return FALSE;
2649 if (full_name1.drive != full_name2.drive)
2651 /* use copy, if allowed */
2652 if (!(flag & MOVEFILE_COPY_ALLOWED))
2654 /* FIXME: Use right error code */
2655 SetLastError( ERROR_FILE_EXISTS );
2658 return CopyFileW( fn1, fn2, !(flag & MOVEFILE_REPLACE_EXISTING) );
2660 if (rename( full_name1.long_name, full_name2.long_name ) == -1)
2665 if (is_executable( full_name1.long_name ) != is_executable( full_name2.long_name ))
2668 if (stat( full_name2.long_name, &fstat ) != -1)
2670 if (is_executable( full_name2.long_name ))
2671 /* set executable bit where read bit is set */
2672 fstat.st_mode |= (fstat.st_mode & 0444) >> 2;
2674 fstat.st_mode &= ~0111;
2675 chmod( full_name2.long_name, fstat.st_mode );
2680 else /* fn2 == NULL means delete source */
2682 if (flag & MOVEFILE_DELAY_UNTIL_REBOOT)
2684 if (flag & MOVEFILE_COPY_ALLOWED) {
2685 WARN("Illegal flag\n");
2686 SetLastError( ERROR_GEN_FAILURE );
2689 /* FIXME: (bon@elektron.ikp.physik.th-darmstadt.de 970706)
2690 Perhaps we should queue these command and execute it
2691 when exiting... What about using on_exit(2)
2693 FIXME("Please delete file %s when Wine has finished\n", debugstr_w(fn1));
2694 return FILE_AddBootRenameEntry( fn1, NULL, flag );
2697 if (unlink( full_name1.long_name ) == -1)
2702 return TRUE; /* successfully deleted */
2706 /**************************************************************************
2707 * MoveFileExA (KERNEL32.@)
2709 BOOL WINAPI MoveFileExA( LPCSTR fn1, LPCSTR fn2, DWORD flag )
2711 UNICODE_STRING fn1W, fn2W;
2716 SetLastError(ERROR_INVALID_PARAMETER);
2720 RtlCreateUnicodeStringFromAsciiz(&fn1W, fn1);
2721 if (fn2) RtlCreateUnicodeStringFromAsciiz(&fn2W, fn2);
2722 else fn2W.Buffer = NULL;
2724 ret = MoveFileExW( fn1W.Buffer, fn2W.Buffer, flag );
2726 RtlFreeUnicodeString(&fn1W);
2727 RtlFreeUnicodeString(&fn2W);
2732 /**************************************************************************
2733 * MoveFileW (KERNEL32.@)
2735 * Move file or directory
2737 BOOL WINAPI MoveFileW( LPCWSTR fn1, LPCWSTR fn2 )
2739 DOS_FULL_NAME full_name1, full_name2;
2744 SetLastError(ERROR_INVALID_PARAMETER);
2748 TRACE("(%s,%s)\n", debugstr_w(fn1), debugstr_w(fn2) );
2750 if (!DOSFS_GetFullName( fn1, TRUE, &full_name1 )) return FALSE;
2751 if (DOSFS_GetFullName( fn2, TRUE, &full_name2 )) {
2752 /* The new name must not already exist */
2753 SetLastError(ERROR_ALREADY_EXISTS);
2756 if (!DOSFS_GetFullName( fn2, FALSE, &full_name2 )) return FALSE;
2758 if (full_name1.drive == full_name2.drive) /* move */
2759 return MoveFileExW( fn1, fn2, MOVEFILE_COPY_ALLOWED );
2762 if (stat( full_name1.long_name, &fstat ))
2764 WARN("Invalid source file %s\n",
2765 full_name1.long_name);
2769 if (S_ISDIR(fstat.st_mode)) {
2770 /* No Move for directories across file systems */
2771 /* FIXME: Use right error code */
2772 SetLastError( ERROR_GEN_FAILURE );
2775 return CopyFileW(fn1, fn2, TRUE); /*fail, if exist */
2779 /**************************************************************************
2780 * MoveFileA (KERNEL32.@)
2782 BOOL WINAPI MoveFileA( LPCSTR fn1, LPCSTR fn2 )
2784 UNICODE_STRING fn1W, fn2W;
2789 SetLastError(ERROR_INVALID_PARAMETER);
2793 RtlCreateUnicodeStringFromAsciiz(&fn1W, fn1);
2794 RtlCreateUnicodeStringFromAsciiz(&fn2W, fn2);
2796 ret = MoveFileW( fn1W.Buffer, fn2W.Buffer );
2798 RtlFreeUnicodeString(&fn1W);
2799 RtlFreeUnicodeString(&fn2W);
2804 /**************************************************************************
2805 * CopyFileW (KERNEL32.@)
2807 BOOL WINAPI CopyFileW( LPCWSTR source, LPCWSTR dest, BOOL fail_if_exists )
2810 BY_HANDLE_FILE_INFORMATION info;
2815 if (!source || !dest)
2817 SetLastError(ERROR_INVALID_PARAMETER);
2821 TRACE("%s -> %s\n", debugstr_w(source), debugstr_w(dest));
2823 if ((h1 = CreateFileW(source, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE,
2824 NULL, OPEN_EXISTING, 0, 0)) == INVALID_HANDLE_VALUE)
2826 WARN("Unable to open source %s\n", debugstr_w(source));
2830 if (!GetFileInformationByHandle( h1, &info ))
2832 WARN("GetFileInformationByHandle returned error for %s\n", debugstr_w(source));
2837 if ((h2 = CreateFileW( dest, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
2838 fail_if_exists ? CREATE_NEW : CREATE_ALWAYS,
2839 info.dwFileAttributes, h1 )) == INVALID_HANDLE_VALUE)
2841 WARN("Unable to open dest %s\n", debugstr_w(dest));
2846 while (ReadFile( h1, buffer, sizeof(buffer), &count, NULL ) && count)
2852 if (!WriteFile( h2, p, count, &res, NULL ) || !res) goto done;
2865 /**************************************************************************
2866 * CopyFileA (KERNEL32.@)
2868 BOOL WINAPI CopyFileA( LPCSTR source, LPCSTR dest, BOOL fail_if_exists)
2870 UNICODE_STRING sourceW, destW;
2873 if (!source || !dest)
2875 SetLastError(ERROR_INVALID_PARAMETER);
2879 RtlCreateUnicodeStringFromAsciiz(&sourceW, source);
2880 RtlCreateUnicodeStringFromAsciiz(&destW, dest);
2882 ret = CopyFileW(sourceW.Buffer, destW.Buffer, fail_if_exists);
2884 RtlFreeUnicodeString(&sourceW);
2885 RtlFreeUnicodeString(&destW);
2890 /**************************************************************************
2891 * CopyFileExW (KERNEL32.@)
2893 * This implementation ignores most of the extra parameters passed-in into
2894 * the "ex" version of the method and calls the CopyFile method.
2895 * It will have to be fixed eventually.
2897 BOOL WINAPI CopyFileExW(LPCWSTR sourceFilename, LPCWSTR destFilename,
2898 LPPROGRESS_ROUTINE progressRoutine, LPVOID appData,
2899 LPBOOL cancelFlagPointer, DWORD copyFlags)
2902 * Interpret the only flag that CopyFile can interpret.
2904 return CopyFileW(sourceFilename, destFilename, (copyFlags & COPY_FILE_FAIL_IF_EXISTS) != 0);
2907 /**************************************************************************
2908 * CopyFileExA (KERNEL32.@)
2910 BOOL WINAPI CopyFileExA(LPCSTR sourceFilename, LPCSTR destFilename,
2911 LPPROGRESS_ROUTINE progressRoutine, LPVOID appData,
2912 LPBOOL cancelFlagPointer, DWORD copyFlags)
2914 UNICODE_STRING sourceW, destW;
2917 if (!sourceFilename || !destFilename)
2919 SetLastError(ERROR_INVALID_PARAMETER);
2923 RtlCreateUnicodeStringFromAsciiz(&sourceW, sourceFilename);
2924 RtlCreateUnicodeStringFromAsciiz(&destW, destFilename);
2926 ret = CopyFileExW(sourceW.Buffer, destW.Buffer, progressRoutine, appData,
2927 cancelFlagPointer, copyFlags);
2929 RtlFreeUnicodeString(&sourceW);
2930 RtlFreeUnicodeString(&destW);
2935 /***********************************************************************
2936 * SetFileTime (KERNEL32.@)
2938 BOOL WINAPI SetFileTime( HANDLE hFile,
2939 const FILETIME *lpCreationTime,
2940 const FILETIME *lpLastAccessTime,
2941 const FILETIME *lpLastWriteTime )
2944 SERVER_START_REQ( set_file_time )
2946 req->handle = hFile;
2947 if (lpLastAccessTime)
2948 RtlTimeToSecondsSince1970( lpLastAccessTime, (DWORD *)&req->access_time );
2950 req->access_time = 0; /* FIXME */
2951 if (lpLastWriteTime)
2952 RtlTimeToSecondsSince1970( lpLastWriteTime, (DWORD *)&req->write_time );
2954 req->write_time = 0; /* FIXME */
2955 ret = !wine_server_call_err( req );
2962 /**************************************************************************
2963 * LockFile (KERNEL32.@)
2965 BOOL WINAPI LockFile( HANDLE hFile, DWORD dwFileOffsetLow, DWORD dwFileOffsetHigh,
2966 DWORD nNumberOfBytesToLockLow, DWORD nNumberOfBytesToLockHigh )
2970 FIXME("not implemented in server\n");
2972 SERVER_START_REQ( lock_file )
2974 req->handle = hFile;
2975 req->offset_low = dwFileOffsetLow;
2976 req->offset_high = dwFileOffsetHigh;
2977 req->count_low = nNumberOfBytesToLockLow;
2978 req->count_high = nNumberOfBytesToLockHigh;
2979 ret = !wine_server_call_err( req );
2985 /**************************************************************************
2986 * LockFileEx [KERNEL32.@]
2988 * Locks a byte range within an open file for shared or exclusive access.
2995 * Per Microsoft docs, the third parameter (reserved) must be set to 0.
2997 BOOL WINAPI LockFileEx( HANDLE hFile, DWORD flags, DWORD reserved,
2998 DWORD nNumberOfBytesToLockLow, DWORD nNumberOfBytesToLockHigh,
2999 LPOVERLAPPED pOverlapped )
3001 FIXME("hFile=%d,flags=%ld,reserved=%ld,lowbytes=%ld,highbytes=%ld,overlapped=%p: stub.\n",
3002 hFile, flags, reserved, nNumberOfBytesToLockLow, nNumberOfBytesToLockHigh,
3005 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
3008 ERR("reserved == %ld: Supposed to be 0??\n", reserved);
3009 SetLastError(ERROR_INVALID_PARAMETER);
3016 /**************************************************************************
3017 * UnlockFile (KERNEL32.@)
3019 BOOL WINAPI UnlockFile( HANDLE hFile, DWORD dwFileOffsetLow, DWORD dwFileOffsetHigh,
3020 DWORD nNumberOfBytesToUnlockLow, DWORD nNumberOfBytesToUnlockHigh )
3024 FIXME("not implemented in server\n");
3026 SERVER_START_REQ( unlock_file )
3028 req->handle = hFile;
3029 req->offset_low = dwFileOffsetLow;
3030 req->offset_high = dwFileOffsetHigh;
3031 req->count_low = nNumberOfBytesToUnlockLow;
3032 req->count_high = nNumberOfBytesToUnlockHigh;
3033 ret = !wine_server_call_err( req );
3040 /**************************************************************************
3041 * UnlockFileEx (KERNEL32.@)
3043 BOOL WINAPI UnlockFileEx(
3046 DWORD nNumberOfBytesToUnlockLow,
3047 DWORD nNumberOfBytesToUnlockHigh,
3048 LPOVERLAPPED lpOverlapped
3051 FIXME("hFile=%d,reserved=%ld,lowbytes=%ld,highbytes=%ld,overlapped=%p: stub.\n",
3052 hFile, dwReserved, nNumberOfBytesToUnlockLow, nNumberOfBytesToUnlockHigh,
3054 if (dwReserved == 0)
3055 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
3058 ERR("reserved == %ld: Supposed to be 0??\n", dwReserved);
3059 SetLastError(ERROR_INVALID_PARAMETER);
3068 struct DOS_FILE_LOCK {
3069 struct DOS_FILE_LOCK * next;
3073 FILE_OBJECT * dos_file;
3074 /* char * unix_name;*/
3077 typedef struct DOS_FILE_LOCK DOS_FILE_LOCK;
3079 static DOS_FILE_LOCK *locks = NULL;
3080 static void DOS_RemoveFileLocks(FILE_OBJECT *file);
3083 /* Locks need to be mirrored because unix file locking is based
3084 * on the pid. Inside of wine there can be multiple WINE processes
3085 * that share the same unix pid.
3086 * Read's and writes should check these locks also - not sure
3087 * how critical that is at this point (FIXME).
3090 static BOOL DOS_AddLock(FILE_OBJECT *file, struct flock *f)
3092 DOS_FILE_LOCK *curr;
3095 processId = GetCurrentProcessId();
3097 /* check if lock overlaps a current lock for the same file */
3099 for (curr = locks; curr; curr = curr->next) {
3100 if (strcmp(curr->unix_name, file->unix_name) == 0) {
3101 if ((f->l_start == curr->base) && (f->l_len == curr->len))
3102 return TRUE;/* region is identic */
3103 if ((f->l_start < (curr->base + curr->len)) &&
3104 ((f->l_start + f->l_len) > curr->base)) {
3105 /* region overlaps */
3112 curr = HeapAlloc( GetProcessHeap(), 0, sizeof(DOS_FILE_LOCK) );
3113 curr->processId = GetCurrentProcessId();
3114 curr->base = f->l_start;
3115 curr->len = f->l_len;
3116 /* curr->unix_name = HEAP_strdupA( GetProcessHeap(), 0, file->unix_name);*/
3118 curr->dos_file = file;
3123 static void DOS_RemoveFileLocks(FILE_OBJECT *file)
3126 DOS_FILE_LOCK **curr;
3129 processId = GetCurrentProcessId();
3132 if ((*curr)->dos_file == file) {
3134 *curr = (*curr)->next;
3135 /* HeapFree( GetProcessHeap(), 0, rem->unix_name );*/
3136 HeapFree( GetProcessHeap(), 0, rem );
3139 curr = &(*curr)->next;
3143 static BOOL DOS_RemoveLock(FILE_OBJECT *file, struct flock *f)
3146 DOS_FILE_LOCK **curr;
3149 processId = GetCurrentProcessId();
3150 for (curr = &locks; *curr; curr = &(*curr)->next) {
3151 if ((*curr)->processId == processId &&
3152 (*curr)->dos_file == file &&
3153 (*curr)->base == f->l_start &&
3154 (*curr)->len == f->l_len) {
3155 /* this is the same lock */
3157 *curr = (*curr)->next;
3158 /* HeapFree( GetProcessHeap(), 0, rem->unix_name );*/
3159 HeapFree( GetProcessHeap(), 0, rem );
3163 /* no matching lock found */
3168 /**************************************************************************
3169 * LockFile (KERNEL32.@)
3171 BOOL WINAPI LockFile(
3172 HANDLE hFile,DWORD dwFileOffsetLow,DWORD dwFileOffsetHigh,
3173 DWORD nNumberOfBytesToLockLow,DWORD nNumberOfBytesToLockHigh )
3178 TRACE("handle %d offsetlow=%ld offsethigh=%ld nbyteslow=%ld nbyteshigh=%ld\n",
3179 hFile, dwFileOffsetLow, dwFileOffsetHigh,
3180 nNumberOfBytesToLockLow, nNumberOfBytesToLockHigh);
3182 if (dwFileOffsetHigh || nNumberOfBytesToLockHigh) {
3183 FIXME("Unimplemented bytes > 32bits\n");
3187 f.l_start = dwFileOffsetLow;
3188 f.l_len = nNumberOfBytesToLockLow;
3189 f.l_whence = SEEK_SET;
3193 if (!(file = FILE_GetFile(hFile,0,NULL))) return FALSE;
3195 /* shadow locks internally */
3196 if (!DOS_AddLock(file, &f)) {
3197 SetLastError( ERROR_LOCK_VIOLATION );
3201 /* FIXME: Unix locking commented out for now, doesn't work with Excel */
3202 #ifdef USE_UNIX_LOCKS
3203 if (fcntl(file->unix_handle, F_SETLK, &f) == -1) {
3204 if (errno == EACCES || errno == EAGAIN) {
3205 SetLastError( ERROR_LOCK_VIOLATION );
3210 /* remove our internal copy of the lock */
3211 DOS_RemoveLock(file, &f);
3219 /**************************************************************************
3220 * UnlockFile (KERNEL32.@)
3222 BOOL WINAPI UnlockFile(
3223 HANDLE hFile,DWORD dwFileOffsetLow,DWORD dwFileOffsetHigh,
3224 DWORD nNumberOfBytesToUnlockLow,DWORD nNumberOfBytesToUnlockHigh )
3229 TRACE("handle %d offsetlow=%ld offsethigh=%ld nbyteslow=%ld nbyteshigh=%ld\n",
3230 hFile, dwFileOffsetLow, dwFileOffsetHigh,
3231 nNumberOfBytesToUnlockLow, nNumberOfBytesToUnlockHigh);
3233 if (dwFileOffsetHigh || nNumberOfBytesToUnlockHigh) {
3234 WARN("Unimplemented bytes > 32bits\n");
3238 f.l_start = dwFileOffsetLow;
3239 f.l_len = nNumberOfBytesToUnlockLow;
3240 f.l_whence = SEEK_SET;
3244 if (!(file = FILE_GetFile(hFile,0,NULL))) return FALSE;
3246 DOS_RemoveLock(file, &f); /* ok if fails - may be another wine */
3248 /* FIXME: Unix locking commented out for now, doesn't work with Excel */
3249 #ifdef USE_UNIX_LOCKS
3250 if (fcntl(file->unix_handle, F_SETLK, &f) == -1) {
3259 /**************************************************************************
3260 * GetFileAttributesExW (KERNEL32.@)
3262 BOOL WINAPI GetFileAttributesExW(
3263 LPCWSTR lpFileName, GET_FILEEX_INFO_LEVELS fInfoLevelId,
3264 LPVOID lpFileInformation)
3266 DOS_FULL_NAME full_name;
3267 BY_HANDLE_FILE_INFORMATION info;
3269 if (!lpFileName || !lpFileInformation)
3271 SetLastError(ERROR_INVALID_PARAMETER);
3275 if (fInfoLevelId == GetFileExInfoStandard) {
3276 LPWIN32_FILE_ATTRIBUTE_DATA lpFad =
3277 (LPWIN32_FILE_ATTRIBUTE_DATA) lpFileInformation;
3278 if (!DOSFS_GetFullName( lpFileName, TRUE, &full_name )) return FALSE;
3279 if (!FILE_Stat( full_name.long_name, &info )) return FALSE;
3281 lpFad->dwFileAttributes = info.dwFileAttributes;
3282 lpFad->ftCreationTime = info.ftCreationTime;
3283 lpFad->ftLastAccessTime = info.ftLastAccessTime;
3284 lpFad->ftLastWriteTime = info.ftLastWriteTime;
3285 lpFad->nFileSizeHigh = info.nFileSizeHigh;
3286 lpFad->nFileSizeLow = info.nFileSizeLow;
3289 FIXME("invalid info level %d!\n", fInfoLevelId);
3297 /**************************************************************************
3298 * GetFileAttributesExA (KERNEL32.@)
3300 BOOL WINAPI GetFileAttributesExA(
3301 LPCSTR filename, GET_FILEEX_INFO_LEVELS fInfoLevelId,
3302 LPVOID lpFileInformation)
3304 UNICODE_STRING filenameW;
3307 if (!filename || !lpFileInformation)
3309 SetLastError(ERROR_INVALID_PARAMETER);
3313 if (RtlCreateUnicodeStringFromAsciiz(&filenameW, filename))
3315 ret = GetFileAttributesExW(filenameW.Buffer, fInfoLevelId, lpFileInformation);
3316 RtlFreeUnicodeString(&filenameW);
3319 SetLastError(ERROR_NOT_ENOUGH_MEMORY);