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>
62 #include "wine/winbase16.h"
63 #include "wine/server.h"
73 #include "wine/unicode.h"
74 #include "wine/debug.h"
76 WINE_DEFAULT_DEBUG_CHANNEL(file);
78 #if defined(MAP_ANONYMOUS) && !defined(MAP_ANON)
79 #define MAP_ANON MAP_ANONYMOUS
82 /* Size of per-process table of DOS handles */
83 #define DOS_TABLE_SIZE 256
85 /* Macro to derive file offset from OVERLAPPED struct */
86 #define OVERLAPPED_OFFSET(overlapped) ((off_t) (overlapped)->Offset + ((off_t) (overlapped)->OffsetHigh << 32))
88 static HANDLE dos_handles[DOS_TABLE_SIZE];
92 extern HANDLE WINAPI FILE_SmbOpen(LPCSTR name);
94 /***********************************************************************
95 * Asynchronous file I/O *
97 static DWORD fileio_get_async_status (const async_private *ovp);
98 static DWORD fileio_get_async_count (const async_private *ovp);
99 static void fileio_set_async_status (async_private *ovp, const DWORD status);
100 static void CALLBACK fileio_call_completion_func (ULONG_PTR data);
101 static void fileio_async_cleanup (async_private *ovp);
103 static async_ops fileio_async_ops =
105 fileio_get_async_status, /* get_status */
106 fileio_set_async_status, /* set_status */
107 fileio_get_async_count, /* get_count */
108 fileio_call_completion_func, /* call_completion */
109 fileio_async_cleanup /* cleanup */
112 static async_ops fileio_nocomp_async_ops =
114 fileio_get_async_status, /* get_status */
115 fileio_set_async_status, /* set_status */
116 fileio_get_async_count, /* get_count */
117 NULL, /* call_completion */
118 fileio_async_cleanup /* cleanup */
121 typedef struct async_fileio
123 struct async_private async;
124 LPOVERLAPPED lpOverlapped;
125 LPOVERLAPPED_COMPLETION_ROUTINE completion_func;
128 enum fd_type fd_type;
131 static DWORD fileio_get_async_status (const struct async_private *ovp)
133 return ((async_fileio*) ovp)->lpOverlapped->Internal;
136 static void fileio_set_async_status (async_private *ovp, const DWORD status)
138 ((async_fileio*) ovp)->lpOverlapped->Internal = status;
141 static DWORD fileio_get_async_count (const struct async_private *ovp)
143 async_fileio *fileio = (async_fileio*) ovp;
145 if (fileio->count < fileio->lpOverlapped->InternalHigh)
147 return fileio->count - fileio->lpOverlapped->InternalHigh;
150 static void CALLBACK fileio_call_completion_func (ULONG_PTR data)
152 async_fileio *ovp = (async_fileio*) data;
153 TRACE ("data: %p\n", ovp);
155 ovp->completion_func( ovp->lpOverlapped->Internal,
156 ovp->lpOverlapped->InternalHigh,
159 fileio_async_cleanup ( &ovp->async );
162 static void fileio_async_cleanup ( struct async_private *ovp )
164 HeapFree ( GetProcessHeap(), 0, ovp );
167 /***********************************************************************
170 * Convert OF_* mode into flags for CreateFile.
172 static void FILE_ConvertOFMode( INT mode, DWORD *access, DWORD *sharing )
176 case OF_READ: *access = GENERIC_READ; break;
177 case OF_WRITE: *access = GENERIC_WRITE; break;
178 case OF_READWRITE: *access = GENERIC_READ | GENERIC_WRITE; break;
179 default: *access = 0; break;
183 case OF_SHARE_EXCLUSIVE: *sharing = 0; break;
184 case OF_SHARE_DENY_WRITE: *sharing = FILE_SHARE_READ; break;
185 case OF_SHARE_DENY_READ: *sharing = FILE_SHARE_WRITE; break;
186 case OF_SHARE_DENY_NONE:
187 case OF_SHARE_COMPAT:
188 default: *sharing = FILE_SHARE_READ | FILE_SHARE_WRITE; break;
193 /***********************************************************************
196 * locale-independent case conversion for file I/O
198 int FILE_strcasecmp( const char *str1, const char *str2 )
201 for ( ; ; str1++, str2++)
202 if ((ret = FILE_toupper(*str1) - FILE_toupper(*str2)) || !*str1) break;
207 /***********************************************************************
210 * locale-independent case conversion for file I/O
212 int FILE_strncasecmp( const char *str1, const char *str2, int len )
215 for ( ; len > 0; len--, str1++, str2++)
216 if ((ret = FILE_toupper(*str1) - FILE_toupper(*str2)) || !*str1) break;
221 /***********************************************************************
222 * FILE_GetNtStatus(void)
224 * Retrieve the Nt Status code from errno.
225 * Try to be consistent with FILE_SetDosError().
227 DWORD FILE_GetNtStatus(void)
231 TRACE ( "errno = %d\n", errno );
234 case EAGAIN: nt = STATUS_SHARING_VIOLATION; break;
235 case EBADF: nt = STATUS_INVALID_HANDLE; break;
236 case ENOSPC: nt = STATUS_DISK_FULL; break;
239 case EACCES: nt = STATUS_ACCESS_DENIED; break;
240 case ENOENT: nt = STATUS_SHARING_VIOLATION; break;
241 case EISDIR: nt = STATUS_FILE_IS_A_DIRECTORY; break;
243 case ENFILE: nt = STATUS_NO_MORE_FILES; break;
245 case ENOTEMPTY: nt = STATUS_DIRECTORY_NOT_EMPTY; break;
246 case EPIPE: nt = STATUS_PIPE_BROKEN; break;
247 case ENOEXEC: /* ?? */
248 case ESPIPE: /* ?? */
249 case EEXIST: /* ?? */
251 FIXME ( "Converting errno %d to STATUS_UNSUCCESSFUL\n", err );
252 nt = STATUS_UNSUCCESSFUL;
257 /***********************************************************************
260 * Set the DOS error code from errno.
262 void FILE_SetDosError(void)
264 int save_errno = errno; /* errno gets overwritten by printf */
266 TRACE("errno = %d %s\n", errno, strerror(errno));
270 SetLastError( ERROR_SHARING_VIOLATION );
273 SetLastError( ERROR_INVALID_HANDLE );
276 SetLastError( ERROR_HANDLE_DISK_FULL );
281 SetLastError( ERROR_ACCESS_DENIED );
284 SetLastError( ERROR_LOCK_VIOLATION );
287 SetLastError( ERROR_FILE_NOT_FOUND );
290 SetLastError( ERROR_CANNOT_MAKE );
294 SetLastError( ERROR_NO_MORE_FILES );
297 SetLastError( ERROR_FILE_EXISTS );
301 SetLastError( ERROR_SEEK );
304 SetLastError( ERROR_DIR_NOT_EMPTY );
307 SetLastError( ERROR_BAD_FORMAT );
310 WARN("unknown file error: %s\n", strerror(save_errno) );
311 SetLastError( ERROR_GEN_FAILURE );
318 /***********************************************************************
319 * FILE_GetUnixHandleType
321 * Retrieve the Unix handle corresponding to a file handle.
322 * Returns -1 on failure.
324 static int FILE_GetUnixHandleType( HANDLE handle, DWORD access, enum fd_type *type, int *flags_ptr )
326 int ret, flags, fd = -1;
328 ret = wine_server_handle_to_fd( handle, access, &fd, type, &flags );
329 if (flags_ptr) *flags_ptr = flags;
330 if (ret) SetLastError( RtlNtStatusToDosError(ret) );
331 else if (((access & GENERIC_READ) && (flags & FD_FLAG_RECV_SHUTDOWN)) ||
332 ((access & GENERIC_WRITE) && (flags & FD_FLAG_SEND_SHUTDOWN)))
335 SetLastError ( ERROR_PIPE_NOT_CONNECTED );
341 /***********************************************************************
344 * Retrieve the Unix handle corresponding to a file handle.
345 * Returns -1 on failure.
347 int FILE_GetUnixHandle( HANDLE handle, DWORD access )
349 return FILE_GetUnixHandleType( handle, access, NULL, NULL );
352 /*************************************************************************
355 * Open a handle to the current process console.
356 * Returns 0 on failure.
358 static HANDLE FILE_OpenConsole( BOOL output, DWORD access, DWORD sharing, LPSECURITY_ATTRIBUTES sa )
362 SERVER_START_REQ( open_console )
365 req->access = access;
366 req->share = sharing;
367 req->inherit = (sa && (sa->nLength>=sizeof(*sa)) && sa->bInheritHandle);
369 wine_server_call_err( req );
376 /* FIXME: those routines defined as pointers are needed, because this file is
377 * currently compiled into NTDLL whereas it belongs to kernel32.
378 * this shall go away once all the DLL separation process is done
380 typedef BOOL (WINAPI* pRW)(HANDLE, const void*, DWORD, DWORD*, void*);
382 static BOOL FILE_ReadConsole(HANDLE hCon, void* buf, DWORD nb, DWORD* nr, void* p)
384 static HANDLE hKernel /* = 0 */;
385 static pRW pReadConsole /* = 0 */;
387 if ((!hKernel && !(hKernel = LoadLibraryA("kernel32"))) ||
389 !(pReadConsole = GetProcAddress(hKernel, "ReadConsoleA"))))
394 return (pReadConsole)(hCon, buf, nb, nr, p);
397 static BOOL FILE_WriteConsole(HANDLE hCon, const void* buf, DWORD nb, DWORD* nr, void* p)
399 static HANDLE hKernel /* = 0 */;
400 static pRW pWriteConsole /* = 0 */;
402 if ((!hKernel && !(hKernel = LoadLibraryA("kernel32"))) ||
404 !(pWriteConsole = GetProcAddress(hKernel, "WriteConsoleA"))))
409 return (pWriteConsole)(hCon, buf, nb, nr, p);
413 /***********************************************************************
416 * Implementation of CreateFile. Takes a Unix path name.
417 * Returns 0 on failure.
419 HANDLE FILE_CreateFile( LPCSTR filename, DWORD access, DWORD sharing,
420 LPSECURITY_ATTRIBUTES sa, DWORD creation,
421 DWORD attributes, HANDLE template, BOOL fail_read_only,
429 SERVER_START_REQ( create_file )
431 req->access = access;
432 req->inherit = (sa && (sa->nLength>=sizeof(*sa)) && sa->bInheritHandle);
433 req->sharing = sharing;
434 req->create = creation;
435 req->attrs = attributes;
436 req->drive_type = drive_type;
437 wine_server_add_data( req, filename, strlen(filename) );
439 err = wine_server_call( req );
444 /* If write access failed, retry without GENERIC_WRITE */
446 if (!ret && !fail_read_only && (access & GENERIC_WRITE))
448 if ((err == STATUS_MEDIA_WRITE_PROTECTED) || (err == STATUS_ACCESS_DENIED))
450 TRACE("Write access failed for file '%s', trying without "
451 "write access\n", filename);
452 access &= ~GENERIC_WRITE;
459 /* In the case file creation was rejected due to CREATE_NEW flag
460 * was specified and file with that name already exists, correct
461 * last error is ERROR_FILE_EXISTS and not ERROR_ALREADY_EXISTS.
462 * Note: RtlNtStatusToDosError is not the subject to blame here.
464 if (err == STATUS_OBJECT_NAME_COLLISION)
465 SetLastError( ERROR_FILE_EXISTS );
467 SetLastError( RtlNtStatusToDosError(err) );
470 if (!ret) WARN("Unable to create file '%s' (GLE %ld)\n", filename, GetLastError());
476 /***********************************************************************
479 * Same as FILE_CreateFile but for a device
480 * Returns 0 on failure.
482 HANDLE FILE_CreateDevice( int client_id, DWORD access, LPSECURITY_ATTRIBUTES sa )
485 SERVER_START_REQ( create_device )
487 req->access = access;
488 req->inherit = (sa && (sa->nLength>=sizeof(*sa)) && sa->bInheritHandle);
491 wine_server_call_err( req );
498 static HANDLE FILE_OpenPipe(LPCWSTR name, DWORD access)
503 if (name && (len = strlenW(name)) > MAX_PATH)
505 SetLastError( ERROR_FILENAME_EXCED_RANGE );
508 SERVER_START_REQ( open_named_pipe )
510 req->access = access;
512 wine_server_add_data( req, name, len * sizeof(WCHAR) );
513 wine_server_call_err( req );
517 TRACE("Returned %d\n",ret);
521 /*************************************************************************
522 * CreateFileW [KERNEL32.@] Creates or opens a file or other object
524 * Creates or opens an object, and returns a handle that can be used to
525 * access that object.
529 * filename [in] pointer to filename to be accessed
530 * access [in] access mode requested
531 * sharing [in] share mode
532 * sa [in] pointer to security attributes
533 * creation [in] how to create the file
534 * attributes [in] attributes for newly created file
535 * template [in] handle to file with extended attributes to copy
538 * Success: Open handle to specified file
539 * Failure: INVALID_HANDLE_VALUE
542 * Should call SetLastError() on failure.
546 * Doesn't support character devices, template files, or a
547 * lot of the 'attributes' flags yet.
549 HANDLE WINAPI CreateFileW( LPCWSTR filename, DWORD access, DWORD sharing,
550 LPSECURITY_ATTRIBUTES sa, DWORD creation,
551 DWORD attributes, HANDLE template )
553 DOS_FULL_NAME full_name;
555 static const WCHAR bkslashes_with_question_markW[] = {'\\','\\','?','\\',0};
556 static const WCHAR bkslashes_with_dotW[] = {'\\','\\','.','\\',0};
557 static const WCHAR bkslashesW[] = {'\\','\\',0};
558 static const WCHAR coninW[] = {'C','O','N','I','N','$',0};
559 static const WCHAR conoutW[] = {'C','O','N','O','U','T','$',0};
563 SetLastError( ERROR_INVALID_PARAMETER );
564 return INVALID_HANDLE_VALUE;
566 TRACE("%s %s%s%s%s%s%s%s attributes 0x%lx\n", debugstr_w(filename),
567 ((access & GENERIC_READ)==GENERIC_READ)?"GENERIC_READ ":"",
568 ((access & GENERIC_WRITE)==GENERIC_WRITE)?"GENERIC_WRITE ":"",
569 (!access)?"QUERY_ACCESS ":"",
570 ((sharing & FILE_SHARE_READ)==FILE_SHARE_READ)?"FILE_SHARE_READ ":"",
571 ((sharing & FILE_SHARE_WRITE)==FILE_SHARE_WRITE)?"FILE_SHARE_WRITE ":"",
572 ((sharing & FILE_SHARE_DELETE)==FILE_SHARE_DELETE)?"FILE_SHARE_DELETE ":"",
573 (creation ==CREATE_NEW)?"CREATE_NEW":
574 (creation ==CREATE_ALWAYS)?"CREATE_ALWAYS ":
575 (creation ==OPEN_EXISTING)?"OPEN_EXISTING ":
576 (creation ==OPEN_ALWAYS)?"OPEN_ALWAYS ":
577 (creation ==TRUNCATE_EXISTING)?"TRUNCATE_EXISTING ":"", attributes);
579 /* If the name starts with '\\?\', ignore the first 4 chars. */
580 if (!strncmpW(filename, bkslashes_with_question_markW, 4))
582 static const WCHAR uncW[] = {'U','N','C','\\',0};
584 if (!strncmpiW(filename, uncW, 4))
586 FIXME("UNC name (%s) not supported.\n", debugstr_w(filename) );
587 SetLastError( ERROR_PATH_NOT_FOUND );
588 return INVALID_HANDLE_VALUE;
592 if (!strncmpW(filename, bkslashes_with_dotW, 4))
594 static const WCHAR pipeW[] = {'P','I','P','E','\\',0};
595 if(!strncmpiW(filename + 4, pipeW, 5))
597 TRACE("Opening a pipe: %s\n", debugstr_w(filename));
598 ret = FILE_OpenPipe(filename,access);
601 else if (isalphaW(filename[4]) && filename[5] == ':' && filename[6] == '\0')
603 ret = FILE_CreateDevice( (toupperW(filename[4]) - 'A') | 0x20000, access, sa );
606 else if (!DOSFS_GetDevice( filename ))
608 ret = DEVICE_Open( filename+4, access, sa );
612 filename+=4; /* fall into DOSFS_Device case below */
615 /* If the name still starts with '\\', it's a UNC name. */
616 if (!strncmpW(filename, bkslashesW, 2))
618 ret = SMB_CreateFileW(filename, access, sharing, sa, creation, attributes, template );
622 /* If the name contains a DOS wild card (* or ?), do no create a file */
623 if(strchrW(filename, '*') || strchrW(filename, '?'))
624 return INVALID_HANDLE_VALUE;
626 /* Open a console for CONIN$ or CONOUT$ */
627 if (!strcmpiW(filename, coninW))
629 ret = FILE_OpenConsole( FALSE, access, sharing, sa );
632 if (!strcmpiW(filename, conoutW))
634 ret = FILE_OpenConsole( TRUE, access, sharing, sa );
638 if (DOSFS_GetDevice( filename ))
640 TRACE("opening device %s\n", debugstr_w(filename) );
642 if (!(ret = DOSFS_OpenDevice( filename, access, attributes, sa )))
644 /* Do not silence this please. It is a critical error. -MM */
645 ERR("Couldn't open device %s!\n", debugstr_w(filename));
646 SetLastError( ERROR_FILE_NOT_FOUND );
651 /* check for filename, don't check for last entry if creating */
652 if (!DOSFS_GetFullName( filename,
653 (creation == OPEN_EXISTING) ||
654 (creation == TRUNCATE_EXISTING),
656 WARN("Unable to get full filename from %s (GLE %ld)\n",
657 debugstr_w(filename), GetLastError());
658 return INVALID_HANDLE_VALUE;
661 ret = FILE_CreateFile( full_name.long_name, access, sharing,
662 sa, creation, attributes, template,
663 DRIVE_GetFlags(full_name.drive) & DRIVE_FAIL_READ_ONLY,
664 GetDriveTypeW( full_name.short_name ) );
666 if (!ret) ret = INVALID_HANDLE_VALUE;
667 TRACE("returning %08x\n", ret);
673 /*************************************************************************
674 * CreateFileA (KERNEL32.@)
676 HANDLE WINAPI CreateFileA( LPCSTR filename, DWORD access, DWORD sharing,
677 LPSECURITY_ATTRIBUTES sa, DWORD creation,
678 DWORD attributes, HANDLE template)
680 UNICODE_STRING filenameW;
681 HANDLE ret = INVALID_HANDLE_VALUE;
685 SetLastError( ERROR_INVALID_PARAMETER );
686 return INVALID_HANDLE_VALUE;
689 if (RtlCreateUnicodeStringFromAsciiz(&filenameW, filename))
691 ret = CreateFileW(filenameW.Buffer, access, sharing, sa, creation,
692 attributes, template);
693 RtlFreeUnicodeString(&filenameW);
696 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
701 /***********************************************************************
704 * Fill a file information from a struct stat.
706 static void FILE_FillInfo( struct stat *st, BY_HANDLE_FILE_INFORMATION *info )
708 if (S_ISDIR(st->st_mode))
709 info->dwFileAttributes = FILE_ATTRIBUTE_DIRECTORY;
711 info->dwFileAttributes = FILE_ATTRIBUTE_ARCHIVE;
712 if (!(st->st_mode & S_IWUSR))
713 info->dwFileAttributes |= FILE_ATTRIBUTE_READONLY;
715 RtlSecondsSince1970ToTime( st->st_mtime, (LARGE_INTEGER *)&info->ftCreationTime );
716 RtlSecondsSince1970ToTime( st->st_mtime, (LARGE_INTEGER *)&info->ftLastWriteTime );
717 RtlSecondsSince1970ToTime( st->st_atime, (LARGE_INTEGER *)&info->ftLastAccessTime );
719 info->dwVolumeSerialNumber = 0; /* FIXME */
720 info->nFileSizeHigh = 0;
721 info->nFileSizeLow = 0;
722 if (!S_ISDIR(st->st_mode)) {
723 info->nFileSizeHigh = st->st_size >> 32;
724 info->nFileSizeLow = st->st_size & 0xffffffff;
726 info->nNumberOfLinks = st->st_nlink;
727 info->nFileIndexHigh = 0;
728 info->nFileIndexLow = st->st_ino;
732 /***********************************************************************
735 * Stat a Unix path name. Return TRUE if OK.
737 BOOL FILE_Stat( LPCSTR unixName, BY_HANDLE_FILE_INFORMATION *info, BOOL *is_symlink_ptr )
743 if (lstat( unixName, &st ) == -1)
748 is_symlink = S_ISLNK(st.st_mode);
751 /* do a "real" stat to find out
752 about the type of the symlink destination */
753 if (stat( unixName, &st ) == -1)
760 /* fill in the information we gathered so far */
761 FILE_FillInfo( &st, info );
763 /* and now see if this is a hidden file, based on the name */
764 p = strrchr( unixName, '/');
765 p = p ? p + 1 : unixName;
766 if (*p == '.' && *(p+1) && (*(p+1) != '.' || *(p+2)))
768 static const WCHAR wineW[] = {'w','i','n','e',0};
769 static const WCHAR ShowDotFilesW[] = {'S','h','o','w','D','o','t','F','i','l','e','s',0};
770 static int show_dot_files = -1;
771 if (show_dot_files == -1)
772 show_dot_files = PROFILE_GetWineIniBool(wineW, ShowDotFilesW, 0);
774 info->dwFileAttributes |= FILE_ATTRIBUTE_HIDDEN;
776 if (is_symlink_ptr) *is_symlink_ptr = is_symlink;
781 /***********************************************************************
782 * GetFileInformationByHandle (KERNEL32.@)
784 DWORD WINAPI GetFileInformationByHandle( HANDLE hFile,
785 BY_HANDLE_FILE_INFORMATION *info )
790 TRACE("%08x\n", hFile);
792 SERVER_START_REQ( get_file_info )
795 if ((ret = !wine_server_call_err( req )))
797 /* FIXME: which file types are supported ?
798 * Serial ports (FILE_TYPE_CHAR) are not,
799 * and MSDN also says that pipes are not supported.
800 * FILE_TYPE_REMOTE seems to be supported according to
801 * MSDN q234741.txt */
802 if ((reply->type == FILE_TYPE_DISK) || (reply->type == FILE_TYPE_REMOTE))
804 RtlSecondsSince1970ToTime( reply->write_time, (LARGE_INTEGER *)&info->ftCreationTime );
805 RtlSecondsSince1970ToTime( reply->write_time, (LARGE_INTEGER *)&info->ftLastWriteTime );
806 RtlSecondsSince1970ToTime( reply->access_time, (LARGE_INTEGER *)&info->ftLastAccessTime );
807 info->dwFileAttributes = reply->attr;
808 info->dwVolumeSerialNumber = reply->serial;
809 info->nFileSizeHigh = reply->size_high;
810 info->nFileSizeLow = reply->size_low;
811 info->nNumberOfLinks = reply->links;
812 info->nFileIndexHigh = reply->index_high;
813 info->nFileIndexLow = reply->index_low;
817 SetLastError(ERROR_NOT_SUPPORTED);
827 /**************************************************************************
828 * GetFileAttributes (KERNEL.420)
830 DWORD WINAPI GetFileAttributes16( LPCSTR name )
832 return GetFileAttributesA( name );
836 /**************************************************************************
837 * GetFileAttributesW (KERNEL32.@)
839 DWORD WINAPI GetFileAttributesW( LPCWSTR name )
841 DOS_FULL_NAME full_name;
842 BY_HANDLE_FILE_INFORMATION info;
846 SetLastError( ERROR_INVALID_PARAMETER );
849 if (!DOSFS_GetFullName( name, TRUE, &full_name) )
851 if (!FILE_Stat( full_name.long_name, &info, NULL )) return -1;
852 return info.dwFileAttributes;
856 /**************************************************************************
857 * GetFileAttributesA (KERNEL32.@)
859 DWORD WINAPI GetFileAttributesA( LPCSTR name )
861 UNICODE_STRING nameW;
862 DWORD ret = (DWORD)-1;
866 SetLastError( ERROR_INVALID_PARAMETER );
870 if (RtlCreateUnicodeStringFromAsciiz(&nameW, name))
872 ret = GetFileAttributesW(nameW.Buffer);
873 RtlFreeUnicodeString(&nameW);
876 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
881 /**************************************************************************
882 * SetFileAttributes (KERNEL.421)
884 BOOL16 WINAPI SetFileAttributes16( LPCSTR lpFileName, DWORD attributes )
886 return SetFileAttributesA( lpFileName, attributes );
890 /**************************************************************************
891 * SetFileAttributesW (KERNEL32.@)
893 BOOL WINAPI SetFileAttributesW(LPCWSTR lpFileName, DWORD attributes)
896 DOS_FULL_NAME full_name;
900 SetLastError( ERROR_INVALID_PARAMETER );
904 TRACE("(%s,%lx)\n", debugstr_w(lpFileName), attributes);
906 if (!DOSFS_GetFullName( lpFileName, TRUE, &full_name ))
909 if(stat(full_name.long_name,&buf)==-1)
914 if (attributes & FILE_ATTRIBUTE_READONLY)
916 if(S_ISDIR(buf.st_mode))
918 WARN("FILE_ATTRIBUTE_READONLY ignored for directory.\n");
920 buf.st_mode &= ~0222; /* octal!, clear write permission bits */
921 attributes &= ~FILE_ATTRIBUTE_READONLY;
925 /* add write permission */
926 buf.st_mode |= (0600 | ((buf.st_mode & 044) >> 1)) & (~FILE_umask);
928 if (attributes & FILE_ATTRIBUTE_DIRECTORY)
930 if (!S_ISDIR(buf.st_mode))
931 FIXME("SetFileAttributes expected the file %s to be a directory\n",
932 debugstr_w(lpFileName));
933 attributes &= ~FILE_ATTRIBUTE_DIRECTORY;
935 attributes &= ~(FILE_ATTRIBUTE_NORMAL|FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_HIDDEN|FILE_ATTRIBUTE_SYSTEM);
937 FIXME("(%s):%lx attribute(s) not implemented.\n", debugstr_w(lpFileName), attributes);
938 if (-1==chmod(full_name.long_name,buf.st_mode))
940 if (GetDriveTypeW(lpFileName) == DRIVE_CDROM)
942 SetLastError( ERROR_ACCESS_DENIED );
947 * FIXME: We don't return FALSE here because of differences between
948 * Linux and Windows privileges. Under Linux only the owner of
949 * the file is allowed to change file attributes. Under Windows,
950 * applications expect that if you can write to a file, you can also
951 * change its attributes (see GENERIC_WRITE). We could try to be
952 * clever here but that would break multi-user installations where
953 * users share read-only DLLs. This is because some installers like
954 * to change attributes of already installed DLLs.
956 FIXME("Couldn't set file attributes for existing file \"%s\".\n"
957 "Check permissions or set VFAT \"quiet\" mount flag\n", full_name.long_name);
963 /**************************************************************************
964 * SetFileAttributesA (KERNEL32.@)
966 BOOL WINAPI SetFileAttributesA(LPCSTR lpFileName, DWORD attributes)
968 UNICODE_STRING filenameW;
973 SetLastError( ERROR_INVALID_PARAMETER );
977 if (RtlCreateUnicodeStringFromAsciiz(&filenameW, lpFileName))
979 ret = SetFileAttributesW(filenameW.Buffer, attributes);
980 RtlFreeUnicodeString(&filenameW);
983 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
988 /***********************************************************************
989 * GetFileSize (KERNEL32.@)
991 DWORD WINAPI GetFileSize( HANDLE hFile, LPDWORD filesizehigh )
993 BY_HANDLE_FILE_INFORMATION info;
994 if (!GetFileInformationByHandle( hFile, &info )) return -1;
995 if (filesizehigh) *filesizehigh = info.nFileSizeHigh;
996 return info.nFileSizeLow;
1000 /***********************************************************************
1001 * GetFileSizeEx (KERNEL32.@)
1003 BOOL WINAPI GetFileSizeEx( HANDLE hFile, PLARGE_INTEGER lpFileSize )
1005 BY_HANDLE_FILE_INFORMATION info;
1009 SetLastError( ERROR_INVALID_PARAMETER );
1013 if (!GetFileInformationByHandle( hFile, &info ))
1018 lpFileSize->s.LowPart = info.nFileSizeLow;
1019 lpFileSize->s.HighPart = info.nFileSizeHigh;
1025 /***********************************************************************
1026 * GetFileTime (KERNEL32.@)
1028 BOOL WINAPI GetFileTime( HANDLE hFile, FILETIME *lpCreationTime,
1029 FILETIME *lpLastAccessTime,
1030 FILETIME *lpLastWriteTime )
1032 BY_HANDLE_FILE_INFORMATION info;
1033 if (!GetFileInformationByHandle( hFile, &info )) return FALSE;
1034 if (lpCreationTime) *lpCreationTime = info.ftCreationTime;
1035 if (lpLastAccessTime) *lpLastAccessTime = info.ftLastAccessTime;
1036 if (lpLastWriteTime) *lpLastWriteTime = info.ftLastWriteTime;
1040 /***********************************************************************
1041 * CompareFileTime (KERNEL32.@)
1043 INT WINAPI CompareFileTime( LPFILETIME x, LPFILETIME y )
1045 if (!x || !y) return -1;
1047 if (x->dwHighDateTime > y->dwHighDateTime)
1049 if (x->dwHighDateTime < y->dwHighDateTime)
1051 if (x->dwLowDateTime > y->dwLowDateTime)
1053 if (x->dwLowDateTime < y->dwLowDateTime)
1058 /***********************************************************************
1059 * FILE_GetTempFileName : utility for GetTempFileName
1061 static UINT FILE_GetTempFileName( LPCWSTR path, LPCWSTR prefix, UINT unique,
1064 static UINT unique_temp;
1065 DOS_FULL_NAME full_name;
1071 if ( !path || !prefix || !buffer )
1073 SetLastError( ERROR_INVALID_PARAMETER );
1077 if (!unique_temp) unique_temp = time(NULL) & 0xffff;
1078 num = unique ? (unique & 0xffff) : (unique_temp++ & 0xffff);
1080 strcpyW( buffer, path );
1081 p = buffer + strlenW(buffer);
1083 /* add a \, if there isn't one and path is more than just the drive letter ... */
1084 if ( !((strlenW(buffer) == 2) && (buffer[1] == ':'))
1085 && ((p == buffer) || (p[-1] != '\\'))) *p++ = '\\';
1087 for (i = 3; (i > 0) && (*prefix); i--) *p++ = *prefix++;
1089 sprintf( buf, "%04x.tmp", num );
1090 MultiByteToWideChar(CP_ACP, 0, buf, -1, p, 20);
1092 /* Now try to create it */
1098 HANDLE handle = CreateFileW( buffer, GENERIC_WRITE, 0, NULL,
1099 CREATE_NEW, FILE_ATTRIBUTE_NORMAL, 0 );
1100 if (handle != INVALID_HANDLE_VALUE)
1101 { /* We created it */
1102 TRACE("created %s\n", debugstr_w(buffer) );
1103 CloseHandle( handle );
1106 if (GetLastError() != ERROR_FILE_EXISTS)
1107 break; /* No need to go on */
1109 sprintf( buf, "%04x.tmp", num );
1110 MultiByteToWideChar(CP_ACP, 0, buf, -1, p, 20);
1111 } while (num != (unique & 0xffff));
1114 /* Get the full path name */
1116 if (DOSFS_GetFullName( buffer, FALSE, &full_name ))
1119 /* Check if we have write access in the directory */
1120 if ((slash = strrchr( full_name.long_name, '/' ))) *slash = '\0';
1121 if (access( full_name.long_name, W_OK ) == -1)
1122 WARN("returns %s, which doesn't seem to be writeable.\n",
1123 debugstr_w(buffer) );
1125 TRACE("returning %s\n", debugstr_w(buffer) );
1126 return unique ? unique : num;
1130 /***********************************************************************
1131 * GetTempFileNameA (KERNEL32.@)
1133 UINT WINAPI GetTempFileNameA( LPCSTR path, LPCSTR prefix, UINT unique,
1136 UNICODE_STRING pathW, prefixW;
1137 WCHAR bufferW[MAX_PATH];
1140 if ( !path || !prefix || !buffer )
1142 SetLastError( ERROR_INVALID_PARAMETER );
1146 RtlCreateUnicodeStringFromAsciiz(&pathW, path);
1147 RtlCreateUnicodeStringFromAsciiz(&prefixW, prefix);
1149 ret = GetTempFileNameW(pathW.Buffer, prefixW.Buffer, unique, bufferW);
1151 WideCharToMultiByte(CP_ACP, 0, bufferW, -1, buffer, MAX_PATH, NULL, NULL);
1153 RtlFreeUnicodeString(&pathW);
1154 RtlFreeUnicodeString(&prefixW);
1158 /***********************************************************************
1159 * GetTempFileNameW (KERNEL32.@)
1161 UINT WINAPI GetTempFileNameW( LPCWSTR path, LPCWSTR prefix, UINT unique,
1164 return FILE_GetTempFileName( path, prefix, unique, buffer );
1168 /***********************************************************************
1169 * GetTempFileName (KERNEL.97)
1171 UINT16 WINAPI GetTempFileName16( BYTE drive, LPCSTR prefix, UINT16 unique,
1174 char temppath[MAX_PATH];
1175 char *prefix16 = NULL;
1178 if (!(drive & ~TF_FORCEDRIVE)) /* drive 0 means current default drive */
1179 drive |= DRIVE_GetCurrentDrive() + 'A';
1181 if ((drive & TF_FORCEDRIVE) &&
1182 !DRIVE_IsValid( toupper(drive & ~TF_FORCEDRIVE) - 'A' ))
1184 drive &= ~TF_FORCEDRIVE;
1185 WARN("invalid drive %d specified\n", drive );
1188 if (drive & TF_FORCEDRIVE)
1189 sprintf(temppath,"%c:", drive & ~TF_FORCEDRIVE );
1191 GetTempPathA( MAX_PATH, temppath );
1195 prefix16 = HeapAlloc(GetProcessHeap(), 0, strlen(prefix) + 2);
1197 strcpy(prefix16 + 1, prefix);
1200 ret = GetTempFileNameA( temppath, prefix16, unique, buffer );
1202 if (prefix16) HeapFree(GetProcessHeap(), 0, prefix16);
1206 /***********************************************************************
1209 * Implementation of OpenFile16() and OpenFile32().
1211 static HFILE FILE_DoOpenFile( LPCSTR name, OFSTRUCT *ofs, UINT mode,
1217 WORD filedatetime[2];
1218 DOS_FULL_NAME full_name;
1219 DWORD access, sharing;
1221 WCHAR buffer[MAX_PATH];
1224 if (!ofs) return HFILE_ERROR;
1226 TRACE("%s %s %s %s%s%s%s%s%s%s%s%s\n",name,
1227 ((mode & 0x3 )==OF_READ)?"OF_READ":
1228 ((mode & 0x3 )==OF_WRITE)?"OF_WRITE":
1229 ((mode & 0x3 )==OF_READWRITE)?"OF_READWRITE":"unknown",
1230 ((mode & 0x70 )==OF_SHARE_COMPAT)?"OF_SHARE_COMPAT":
1231 ((mode & 0x70 )==OF_SHARE_DENY_NONE)?"OF_SHARE_DENY_NONE":
1232 ((mode & 0x70 )==OF_SHARE_DENY_READ)?"OF_SHARE_DENY_READ":
1233 ((mode & 0x70 )==OF_SHARE_DENY_WRITE)?"OF_SHARE_DENY_WRITE":
1234 ((mode & 0x70 )==OF_SHARE_EXCLUSIVE)?"OF_SHARE_EXCLUSIVE":"unknown",
1235 ((mode & OF_PARSE )==OF_PARSE)?"OF_PARSE ":"",
1236 ((mode & OF_DELETE )==OF_DELETE)?"OF_DELETE ":"",
1237 ((mode & OF_VERIFY )==OF_VERIFY)?"OF_VERIFY ":"",
1238 ((mode & OF_SEARCH )==OF_SEARCH)?"OF_SEARCH ":"",
1239 ((mode & OF_CANCEL )==OF_CANCEL)?"OF_CANCEL ":"",
1240 ((mode & OF_CREATE )==OF_CREATE)?"OF_CREATE ":"",
1241 ((mode & OF_PROMPT )==OF_PROMPT)?"OF_PROMPT ":"",
1242 ((mode & OF_EXIST )==OF_EXIST)?"OF_EXIST ":"",
1243 ((mode & OF_REOPEN )==OF_REOPEN)?"OF_REOPEN ":""
1247 ofs->cBytes = sizeof(OFSTRUCT);
1249 if (mode & OF_REOPEN) name = ofs->szPathName;
1252 ERR("called with `name' set to NULL ! Please debug.\n");
1256 TRACE("%s %04x\n", name, mode );
1258 /* the watcom 10.6 IDE relies on a valid path returned in ofs->szPathName
1259 Are there any cases where getting the path here is wrong?
1260 Uwe Bonnes 1997 Apr 2 */
1261 if (!GetFullPathNameA( name, sizeof(ofs->szPathName),
1262 ofs->szPathName, NULL )) goto error;
1263 FILE_ConvertOFMode( mode, &access, &sharing );
1265 /* OF_PARSE simply fills the structure */
1267 if (mode & OF_PARSE)
1269 ofs->fFixedDisk = (GetDriveType16( ofs->szPathName[0]-'A' )
1270 != DRIVE_REMOVABLE);
1271 TRACE("(%s): OF_PARSE, res = '%s'\n",
1272 name, ofs->szPathName );
1276 /* OF_CREATE is completely different from all other options, so
1279 if (mode & OF_CREATE)
1281 if ((handle = CreateFileA( name, GENERIC_READ | GENERIC_WRITE,
1282 sharing, NULL, CREATE_ALWAYS,
1283 FILE_ATTRIBUTE_NORMAL, 0 ))== INVALID_HANDLE_VALUE)
1288 MultiByteToWideChar(CP_ACP, 0, name, -1, buffer, MAX_PATH);
1291 /* If OF_SEARCH is set, ignore the given path */
1293 if ((mode & OF_SEARCH) && !(mode & OF_REOPEN))
1295 /* First try the file name as is */
1296 if (DOSFS_GetFullName( nameW, TRUE, &full_name )) goto found;
1297 /* Now remove the path */
1298 if (nameW[0] && (nameW[1] == ':')) nameW += 2;
1299 if ((p = strrchrW( nameW, '\\' ))) nameW = p + 1;
1300 if ((p = strrchrW( nameW, '/' ))) nameW = p + 1;
1301 if (!nameW[0]) goto not_found;
1304 /* Now look for the file */
1306 if (!DIR_SearchPath( NULL, nameW, NULL, &full_name, win32 )) goto not_found;
1309 TRACE("found %s = %s\n",
1310 full_name.long_name, debugstr_w(full_name.short_name) );
1311 WideCharToMultiByte(CP_ACP, 0, full_name.short_name, -1,
1312 ofs->szPathName, sizeof(ofs->szPathName), NULL, NULL);
1314 if (mode & OF_SHARE_EXCLUSIVE)
1315 /* Some InstallShield version uses OF_SHARE_EXCLUSIVE
1316 on the file <tempdir>/_ins0432._mp to determine how
1317 far installation has proceeded.
1318 _ins0432._mp is an executable and while running the
1319 application expects the open with OF_SHARE_ to fail*/
1321 As our loader closes the files after loading the executable,
1322 we can't find the running executable with FILE_InUse.
1323 The loader should keep the file open, as Windows does that, too.
1326 char *last = strrchr(full_name.long_name,'/');
1328 last = full_name.long_name - 1;
1329 if (GetModuleHandle16(last+1))
1331 TRACE("Denying shared open for %s\n",full_name.long_name);
1336 if (mode & OF_DELETE)
1338 if (unlink( full_name.long_name ) == -1) goto not_found;
1339 TRACE("(%s): OF_DELETE return = OK\n", name);
1343 handle = FILE_CreateFile( full_name.long_name, access, sharing,
1344 NULL, OPEN_EXISTING, 0, 0,
1345 DRIVE_GetFlags(full_name.drive) & DRIVE_FAIL_READ_ONLY,
1346 GetDriveTypeW( full_name.short_name ) );
1347 if (!handle) goto not_found;
1349 GetFileTime( handle, NULL, NULL, &filetime );
1350 FileTimeToDosDateTime( &filetime, &filedatetime[0], &filedatetime[1] );
1351 if ((mode & OF_VERIFY) && (mode & OF_REOPEN))
1353 if (ofs->Reserved1 != filedatetime[0] || ofs->Reserved2 != filedatetime[1] )
1355 CloseHandle( handle );
1356 WARN("(%s): OF_VERIFY failed\n", name );
1357 /* FIXME: what error here? */
1358 SetLastError( ERROR_FILE_NOT_FOUND );
1362 ofs->Reserved1 = filedatetime[0];
1363 ofs->Reserved2 = filedatetime[1];
1365 success: /* We get here if the open was successful */
1366 TRACE("(%s): OK, return = %x\n", name, handle );
1369 hFileRet = (HFILE)handle;
1370 if (mode & OF_EXIST) /* Return the handle, but close it first */
1371 CloseHandle( handle );
1375 hFileRet = Win32HandleToDosFileHandle( handle );
1376 if (hFileRet == HFILE_ERROR16) goto error;
1377 if (mode & OF_EXIST) /* Return the handle, but close it first */
1378 _lclose16( hFileRet );
1382 not_found: /* We get here if the file does not exist */
1383 WARN("'%s' not found or sharing violation\n", name );
1384 SetLastError( ERROR_FILE_NOT_FOUND );
1387 error: /* We get here if there was an error opening the file */
1388 ofs->nErrCode = GetLastError();
1389 WARN("(%s): return = HFILE_ERROR error= %d\n",
1390 name,ofs->nErrCode );
1395 /***********************************************************************
1396 * OpenFile (KERNEL.74)
1397 * OpenFileEx (KERNEL.360)
1399 HFILE16 WINAPI OpenFile16( LPCSTR name, OFSTRUCT *ofs, UINT16 mode )
1401 return FILE_DoOpenFile( name, ofs, mode, FALSE );
1405 /***********************************************************************
1406 * OpenFile (KERNEL32.@)
1408 HFILE WINAPI OpenFile( LPCSTR name, OFSTRUCT *ofs, UINT mode )
1410 return FILE_DoOpenFile( name, ofs, mode, TRUE );
1414 /***********************************************************************
1415 * FILE_InitProcessDosHandles
1417 * Allocates the default DOS handles for a process. Called either by
1418 * Win32HandleToDosFileHandle below or by the DOSVM stuff.
1420 static void FILE_InitProcessDosHandles( void )
1422 HANDLE cp = GetCurrentProcess();
1423 DuplicateHandle(cp, GetStdHandle(STD_INPUT_HANDLE), cp, &dos_handles[0],
1424 0, TRUE, DUPLICATE_SAME_ACCESS);
1425 DuplicateHandle(cp, GetStdHandle(STD_OUTPUT_HANDLE), cp, &dos_handles[1],
1426 0, TRUE, DUPLICATE_SAME_ACCESS);
1427 DuplicateHandle(cp, GetStdHandle(STD_ERROR_HANDLE), cp, &dos_handles[2],
1428 0, TRUE, DUPLICATE_SAME_ACCESS);
1429 DuplicateHandle(cp, GetStdHandle(STD_ERROR_HANDLE), cp, &dos_handles[3],
1430 0, TRUE, DUPLICATE_SAME_ACCESS);
1431 DuplicateHandle(cp, GetStdHandle(STD_ERROR_HANDLE), cp, &dos_handles[4],
1432 0, TRUE, DUPLICATE_SAME_ACCESS);
1435 /***********************************************************************
1436 * Win32HandleToDosFileHandle (KERNEL32.21)
1438 * Allocate a DOS handle for a Win32 handle. The Win32 handle is no
1439 * longer valid after this function (even on failure).
1441 * Note: this is not exactly right, since on Win95 the Win32 handles
1442 * are on top of DOS handles and we do it the other way
1443 * around. Should be good enough though.
1445 HFILE WINAPI Win32HandleToDosFileHandle( HANDLE handle )
1449 if (!handle || (handle == INVALID_HANDLE_VALUE))
1452 for (i = 5; i < DOS_TABLE_SIZE; i++)
1453 if (!dos_handles[i])
1455 dos_handles[i] = handle;
1456 TRACE("Got %d for h32 %d\n", i, handle );
1459 CloseHandle( handle );
1460 SetLastError( ERROR_TOO_MANY_OPEN_FILES );
1465 /***********************************************************************
1466 * DosFileHandleToWin32Handle (KERNEL32.20)
1468 * Return the Win32 handle for a DOS handle.
1470 * Note: this is not exactly right, since on Win95 the Win32 handles
1471 * are on top of DOS handles and we do it the other way
1472 * around. Should be good enough though.
1474 HANDLE WINAPI DosFileHandleToWin32Handle( HFILE handle )
1476 HFILE16 hfile = (HFILE16)handle;
1477 if (hfile < 5 && !dos_handles[hfile]) FILE_InitProcessDosHandles();
1478 if ((hfile >= DOS_TABLE_SIZE) || !dos_handles[hfile])
1480 SetLastError( ERROR_INVALID_HANDLE );
1481 return INVALID_HANDLE_VALUE;
1483 return dos_handles[hfile];
1487 /***********************************************************************
1488 * DisposeLZ32Handle (KERNEL32.22)
1490 * Note: this is not entirely correct, we should only close the
1491 * 32-bit handle and not the 16-bit one, but we cannot do
1492 * this because of the way our DOS handles are implemented.
1493 * It shouldn't break anything though.
1495 void WINAPI DisposeLZ32Handle( HANDLE handle )
1499 if (!handle || (handle == INVALID_HANDLE_VALUE)) return;
1501 for (i = 5; i < DOS_TABLE_SIZE; i++)
1502 if (dos_handles[i] == handle)
1505 CloseHandle( handle );
1511 /***********************************************************************
1514 * dup2() function for DOS handles.
1516 HFILE16 FILE_Dup2( HFILE16 hFile1, HFILE16 hFile2 )
1520 if (hFile1 < 5 && !dos_handles[hFile1]) FILE_InitProcessDosHandles();
1522 if ((hFile1 >= DOS_TABLE_SIZE) || (hFile2 >= DOS_TABLE_SIZE) || !dos_handles[hFile1])
1524 SetLastError( ERROR_INVALID_HANDLE );
1525 return HFILE_ERROR16;
1527 if (!DuplicateHandle( GetCurrentProcess(), dos_handles[hFile1],
1528 GetCurrentProcess(), &new_handle,
1529 0, FALSE, DUPLICATE_SAME_ACCESS ))
1530 return HFILE_ERROR16;
1531 if (dos_handles[hFile2]) CloseHandle( dos_handles[hFile2] );
1532 dos_handles[hFile2] = new_handle;
1537 /***********************************************************************
1538 * _lclose (KERNEL.81)
1540 HFILE16 WINAPI _lclose16( HFILE16 hFile )
1542 if ((hFile >= DOS_TABLE_SIZE) || !dos_handles[hFile])
1544 SetLastError( ERROR_INVALID_HANDLE );
1545 return HFILE_ERROR16;
1547 TRACE("%d (handle32=%d)\n", hFile, dos_handles[hFile] );
1548 CloseHandle( dos_handles[hFile] );
1549 dos_handles[hFile] = 0;
1554 /***********************************************************************
1555 * _lclose (KERNEL32.@)
1557 HFILE WINAPI _lclose( HFILE hFile )
1559 TRACE("handle %d\n", hFile );
1560 return CloseHandle( (HANDLE)hFile ) ? 0 : HFILE_ERROR;
1563 /***********************************************************************
1564 * GetOverlappedResult (KERNEL32.@)
1566 * Check the result of an Asynchronous data transfer from a file.
1572 * If successful (and relevant) lpTransferred will hold the number of
1573 * bytes transferred during the async operation.
1577 * Currently only works for WaitCommEvent, ReadFile, WriteFile
1578 * with communications ports.
1581 BOOL WINAPI GetOverlappedResult(
1582 HANDLE hFile, /* [in] handle of file to check on */
1583 LPOVERLAPPED lpOverlapped, /* [in/out] pointer to overlapped */
1584 LPDWORD lpTransferred, /* [in/out] number of bytes transferred */
1585 BOOL bWait /* [in] wait for the transfer to complete ? */
1589 TRACE("(%d %p %p %x)\n", hFile, lpOverlapped, lpTransferred, bWait);
1591 if(lpOverlapped==NULL)
1593 ERR("lpOverlapped was null\n");
1596 if(!lpOverlapped->hEvent)
1598 ERR("lpOverlapped->hEvent was null\n");
1605 TRACE("waiting on %p\n",lpOverlapped);
1606 r = WaitForSingleObjectEx(lpOverlapped->hEvent, INFINITE, TRUE);
1607 TRACE("wait on %p returned %ld\n",lpOverlapped,r);
1608 } while (r==STATUS_USER_APC);
1610 else if ( lpOverlapped->Internal == STATUS_PENDING )
1612 /* Wait in order to give APCs a chance to run. */
1613 /* This is cheating, so we must set the event again in case of success -
1614 it may be a non-manual reset event. */
1616 TRACE("waiting on %p\n",lpOverlapped);
1617 r = WaitForSingleObjectEx(lpOverlapped->hEvent, 0, TRUE);
1618 TRACE("wait on %p returned %ld\n",lpOverlapped,r);
1619 } while (r==STATUS_USER_APC);
1620 if ( r == WAIT_OBJECT_0 )
1621 NtSetEvent ( lpOverlapped->hEvent, NULL );
1625 *lpTransferred = lpOverlapped->InternalHigh;
1627 switch ( lpOverlapped->Internal )
1629 case STATUS_SUCCESS:
1631 case STATUS_PENDING:
1632 SetLastError ( ERROR_IO_INCOMPLETE );
1633 if ( bWait ) ERR ("PENDING status after waiting!\n");
1636 SetLastError ( RtlNtStatusToDosError ( lpOverlapped->Internal ) );
1641 /***********************************************************************
1642 * CancelIo (KERNEL32.@)
1644 BOOL WINAPI CancelIo(HANDLE handle)
1646 async_private *ovp,*t;
1648 TRACE("handle = %x\n",handle);
1650 for (ovp = NtCurrentTeb()->pending_list; ovp; ovp = t)
1653 if ( ovp->handle == handle )
1654 cancel_async ( ovp );
1656 WaitForMultipleObjectsEx(0,NULL,FALSE,1,TRUE);
1660 /***********************************************************************
1661 * FILE_AsyncReadService (INTERNAL)
1663 * This function is called while the client is waiting on the
1664 * server, so we can't make any server calls here.
1666 static void FILE_AsyncReadService(async_private *ovp)
1668 async_fileio *fileio = (async_fileio*) ovp;
1669 LPOVERLAPPED lpOverlapped = fileio->lpOverlapped;
1671 int already = lpOverlapped->InternalHigh;
1673 TRACE("%p %p\n", lpOverlapped, fileio->buffer );
1675 /* check to see if the data is ready (non-blocking) */
1677 if ( fileio->fd_type == FD_TYPE_SOCKET )
1678 result = read (ovp->fd, &fileio->buffer[already], fileio->count - already);
1681 result = pread (ovp->fd, &fileio->buffer[already], fileio->count - already,
1682 OVERLAPPED_OFFSET (lpOverlapped) + already);
1683 if ((result < 0) && (errno == ESPIPE))
1684 result = read (ovp->fd, &fileio->buffer[already], fileio->count - already);
1687 if ( (result<0) && ((errno == EAGAIN) || (errno == EINTR)))
1689 TRACE("Deferred read %d\n",errno);
1694 /* check to see if the transfer is complete */
1697 r = FILE_GetNtStatus ();
1701 lpOverlapped->InternalHigh += result;
1702 TRACE("read %d more bytes %ld/%d so far\n",result,lpOverlapped->InternalHigh,fileio->count);
1704 if(lpOverlapped->InternalHigh >= fileio->count || fileio->fd_type == FD_TYPE_SOCKET )
1710 lpOverlapped->Internal = r;
1713 /***********************************************************************
1714 * FILE_ReadFileEx (INTERNAL)
1716 static BOOL FILE_ReadFileEx(HANDLE hFile, LPVOID buffer, DWORD bytesToRead,
1717 LPOVERLAPPED overlapped,
1718 LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine,
1726 TRACE("file %d to buf %p num %ld %p func %p\n",
1727 hFile, buffer, bytesToRead, overlapped, lpCompletionRoutine);
1729 /* check that there is an overlapped struct */
1730 if (overlapped==NULL)
1732 SetLastError(ERROR_INVALID_PARAMETER);
1736 fd = FILE_GetUnixHandleType ( hFile, GENERIC_READ, &type, &flags);
1739 WARN ( "Couldn't get FD\n" );
1743 ovp = (async_fileio*) HeapAlloc(GetProcessHeap(), 0, sizeof (async_fileio));
1746 TRACE("HeapAlloc Failed\n");
1747 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1751 ovp->async.ops = ( lpCompletionRoutine ? &fileio_async_ops : &fileio_nocomp_async_ops );
1752 ovp->async.handle = hFile;
1754 ovp->async.type = ASYNC_TYPE_READ;
1755 ovp->async.func = FILE_AsyncReadService;
1756 ovp->async.event = hEvent;
1757 ovp->lpOverlapped = overlapped;
1758 ovp->count = bytesToRead;
1759 ovp->completion_func = lpCompletionRoutine;
1760 ovp->buffer = buffer;
1761 ovp->fd_type = type;
1763 return !register_new_async (&ovp->async);
1771 /***********************************************************************
1772 * ReadFileEx (KERNEL32.@)
1774 BOOL WINAPI ReadFileEx(HANDLE hFile, LPVOID buffer, DWORD bytesToRead,
1775 LPOVERLAPPED overlapped,
1776 LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine)
1778 overlapped->InternalHigh = 0;
1779 return FILE_ReadFileEx(hFile,buffer,bytesToRead,overlapped,lpCompletionRoutine, INVALID_HANDLE_VALUE);
1782 static BOOL FILE_TimeoutRead(HANDLE hFile, LPVOID buffer, DWORD bytesToRead, LPDWORD bytesRead)
1787 TRACE("%d %p %ld %p\n", hFile, buffer, bytesToRead, bytesRead );
1789 ZeroMemory(&ov, sizeof (OVERLAPPED));
1790 if(STATUS_SUCCESS==NtCreateEvent(&ov.hEvent, SYNCHRONIZE, NULL, 0, 0))
1792 if(FILE_ReadFileEx(hFile, buffer, bytesToRead, &ov, NULL, ov.hEvent))
1794 r = GetOverlappedResult(hFile, &ov, bytesRead, TRUE);
1797 CloseHandle(ov.hEvent);
1801 /***********************************************************************
1802 * ReadFile (KERNEL32.@)
1804 BOOL WINAPI ReadFile( HANDLE hFile, LPVOID buffer, DWORD bytesToRead,
1805 LPDWORD bytesRead, LPOVERLAPPED overlapped )
1807 int unix_handle, result, flags;
1810 TRACE("%d %p %ld %p %p\n", hFile, buffer, bytesToRead,
1811 bytesRead, overlapped );
1813 if (bytesRead) *bytesRead = 0; /* Do this before anything else */
1814 if (!bytesToRead) return TRUE;
1816 unix_handle = FILE_GetUnixHandleType( hFile, GENERIC_READ, &type, &flags );
1818 if (flags & FD_FLAG_OVERLAPPED)
1820 if (unix_handle == -1) return FALSE;
1821 if ( (overlapped==NULL) || NtResetEvent( overlapped->hEvent, NULL ) )
1823 TRACE("Overlapped not specified or invalid event flag\n");
1825 SetLastError(ERROR_INVALID_PARAMETER);
1830 overlapped->InternalHigh = 0;
1832 if(!FILE_ReadFileEx(hFile, buffer, bytesToRead, overlapped, NULL, overlapped->hEvent))
1835 if ( !GetOverlappedResult (hFile, overlapped, bytesRead, FALSE) )
1837 if ( GetLastError() == ERROR_IO_INCOMPLETE )
1838 SetLastError ( ERROR_IO_PENDING );
1844 if (flags & FD_FLAG_TIMEOUT)
1847 return FILE_TimeoutRead(hFile, buffer, bytesToRead, bytesRead);
1852 return SMB_ReadFile(hFile, buffer, bytesToRead, bytesRead, NULL);
1854 case FD_TYPE_CONSOLE:
1855 return FILE_ReadConsole(hFile, buffer, bytesToRead, bytesRead, NULL);
1857 case FD_TYPE_DEFAULT:
1858 /* normal unix files */
1859 if (unix_handle == -1) return FALSE;
1862 DWORD highOffset = overlapped->OffsetHigh;
1863 if ( (INVALID_SET_FILE_POINTER == SetFilePointer(hFile, overlapped->Offset,
1864 &highOffset, FILE_BEGIN)) &&
1865 (GetLastError() != NO_ERROR) )
1874 if (unix_handle == -1)
1880 off_t offset = OVERLAPPED_OFFSET(overlapped);
1881 if(lseek(unix_handle, offset, SEEK_SET) == -1)
1884 SetLastError(ERROR_INVALID_PARAMETER);
1889 /* code for synchronous reads */
1890 while ((result = read( unix_handle, buffer, bytesToRead )) == -1)
1892 if ((errno == EAGAIN) || (errno == EINTR)) continue;
1893 if ((errno == EFAULT) && !IsBadWritePtr( buffer, bytesToRead )) continue;
1897 close( unix_handle );
1898 if (result == -1) return FALSE;
1899 if (bytesRead) *bytesRead = result;
1904 /***********************************************************************
1905 * FILE_AsyncWriteService (INTERNAL)
1907 * This function is called while the client is waiting on the
1908 * server, so we can't make any server calls here.
1910 static void FILE_AsyncWriteService(struct async_private *ovp)
1912 async_fileio *fileio = (async_fileio *) ovp;
1913 LPOVERLAPPED lpOverlapped = fileio->lpOverlapped;
1915 int already = lpOverlapped->InternalHigh;
1917 TRACE("(%p %p)\n",lpOverlapped,fileio->buffer);
1919 /* write some data (non-blocking) */
1921 if ( fileio->fd_type == FD_TYPE_SOCKET )
1922 result = write(ovp->fd, &fileio->buffer[already], fileio->count - already);
1925 result = pwrite(ovp->fd, &fileio->buffer[already], fileio->count - already,
1926 OVERLAPPED_OFFSET (lpOverlapped) + already);
1927 if ((result < 0) && (errno == ESPIPE))
1928 result = write(ovp->fd, &fileio->buffer[already], fileio->count - already);
1931 if ( (result<0) && ((errno == EAGAIN) || (errno == EINTR)))
1937 /* check to see if the transfer is complete */
1940 r = FILE_GetNtStatus ();
1944 lpOverlapped->InternalHigh += result;
1946 TRACE("wrote %d more bytes %ld/%d so far\n",result,lpOverlapped->InternalHigh,fileio->count);
1948 if(lpOverlapped->InternalHigh < fileio->count)
1954 lpOverlapped->Internal = r;
1957 /***********************************************************************
1960 static BOOL FILE_WriteFileEx(HANDLE hFile, LPCVOID buffer, DWORD bytesToWrite,
1961 LPOVERLAPPED overlapped,
1962 LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine,
1970 TRACE("file %d to buf %p num %ld %p func %p handle %d\n",
1971 hFile, buffer, bytesToWrite, overlapped, lpCompletionRoutine, hEvent);
1973 if (overlapped == NULL)
1975 SetLastError(ERROR_INVALID_PARAMETER);
1979 fd = FILE_GetUnixHandleType ( hFile, GENERIC_WRITE, &type, &flags );
1982 TRACE( "Couldn't get FD\n" );
1986 ovp = (async_fileio*) HeapAlloc(GetProcessHeap(), 0, sizeof (async_fileio));
1989 TRACE("HeapAlloc Failed\n");
1990 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1994 ovp->async.ops = ( lpCompletionRoutine ? &fileio_async_ops : &fileio_nocomp_async_ops );
1995 ovp->async.handle = hFile;
1997 ovp->async.type = ASYNC_TYPE_WRITE;
1998 ovp->async.func = FILE_AsyncWriteService;
1999 ovp->lpOverlapped = overlapped;
2000 ovp->async.event = hEvent;
2001 ovp->buffer = (LPVOID) buffer;
2002 ovp->count = bytesToWrite;
2003 ovp->completion_func = lpCompletionRoutine;
2004 ovp->fd_type = type;
2006 return !register_new_async (&ovp->async);
2013 /***********************************************************************
2014 * WriteFileEx (KERNEL32.@)
2016 BOOL WINAPI WriteFileEx(HANDLE hFile, LPCVOID buffer, DWORD bytesToWrite,
2017 LPOVERLAPPED overlapped,
2018 LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine)
2020 overlapped->InternalHigh = 0;
2022 return FILE_WriteFileEx(hFile, buffer, bytesToWrite, overlapped, lpCompletionRoutine, INVALID_HANDLE_VALUE);
2025 /***********************************************************************
2026 * WriteFile (KERNEL32.@)
2028 BOOL WINAPI WriteFile( HANDLE hFile, LPCVOID buffer, DWORD bytesToWrite,
2029 LPDWORD bytesWritten, LPOVERLAPPED overlapped )
2031 int unix_handle, result, flags;
2034 TRACE("%d %p %ld %p %p\n", hFile, buffer, bytesToWrite,
2035 bytesWritten, overlapped );
2037 if (bytesWritten) *bytesWritten = 0; /* Do this before anything else */
2038 if (!bytesToWrite) return TRUE;
2040 unix_handle = FILE_GetUnixHandleType( hFile, GENERIC_WRITE, &type, &flags );
2042 if (flags & FD_FLAG_OVERLAPPED)
2044 if (unix_handle == -1) return FALSE;
2045 if ( (overlapped==NULL) || NtResetEvent( overlapped->hEvent, NULL ) )
2047 TRACE("Overlapped not specified or invalid event flag\n");
2049 SetLastError(ERROR_INVALID_PARAMETER);
2054 overlapped->InternalHigh = 0;
2056 if(!FILE_WriteFileEx(hFile, buffer, bytesToWrite, overlapped, NULL, overlapped->hEvent))
2059 if ( !GetOverlappedResult (hFile, overlapped, bytesWritten, FALSE) )
2061 if ( GetLastError() == ERROR_IO_INCOMPLETE )
2062 SetLastError ( ERROR_IO_PENDING );
2071 case FD_TYPE_CONSOLE:
2072 TRACE("%d %s %ld %p %p\n", hFile, debugstr_an(buffer, bytesToWrite), bytesToWrite,
2073 bytesWritten, overlapped );
2074 return FILE_WriteConsole(hFile, buffer, bytesToWrite, bytesWritten, NULL);
2076 case FD_TYPE_DEFAULT:
2077 if (unix_handle == -1) return FALSE;
2081 DWORD highOffset = overlapped->OffsetHigh;
2082 if ( (INVALID_SET_FILE_POINTER == SetFilePointer(hFile, overlapped->Offset,
2083 &highOffset, FILE_BEGIN)) &&
2084 (GetLastError() != NO_ERROR) )
2093 if (unix_handle == -1)
2098 SetLastError(ERROR_INVALID_PARAMETER);
2106 off_t offset = OVERLAPPED_OFFSET(overlapped);
2107 if(lseek(unix_handle, offset, SEEK_SET) == -1)
2110 SetLastError(ERROR_INVALID_PARAMETER);
2115 /* synchronous file write */
2116 while ((result = write( unix_handle, buffer, bytesToWrite )) == -1)
2118 if ((errno == EAGAIN) || (errno == EINTR)) continue;
2119 if ((errno == EFAULT) && !IsBadReadPtr( buffer, bytesToWrite )) continue;
2120 if (errno == ENOSPC)
2121 SetLastError( ERROR_DISK_FULL );
2126 close( unix_handle );
2127 if (result == -1) return FALSE;
2128 if (bytesWritten) *bytesWritten = result;
2133 /***********************************************************************
2134 * _hread (KERNEL.349)
2136 LONG WINAPI WIN16_hread( HFILE16 hFile, SEGPTR buffer, LONG count )
2140 TRACE("%d %08lx %ld\n",
2141 hFile, (DWORD)buffer, count );
2143 /* Some programs pass a count larger than the allocated buffer */
2144 maxlen = GetSelectorLimit16( SELECTOROF(buffer) ) - OFFSETOF(buffer) + 1;
2145 if (count > maxlen) count = maxlen;
2146 return _lread((HFILE)DosFileHandleToWin32Handle(hFile), MapSL(buffer), count );
2150 /***********************************************************************
2151 * _lread (KERNEL.82)
2153 UINT16 WINAPI WIN16_lread( HFILE16 hFile, SEGPTR buffer, UINT16 count )
2155 return (UINT16)WIN16_hread( hFile, buffer, (LONG)count );
2159 /***********************************************************************
2160 * _lread (KERNEL32.@)
2162 UINT WINAPI _lread( HFILE handle, LPVOID buffer, UINT count )
2165 if (!ReadFile( (HANDLE)handle, buffer, count, &result, NULL )) return -1;
2170 /***********************************************************************
2171 * _lread16 (KERNEL.82)
2173 UINT16 WINAPI _lread16( HFILE16 hFile, LPVOID buffer, UINT16 count )
2175 return (UINT16)_lread((HFILE)DosFileHandleToWin32Handle(hFile), buffer, (LONG)count );
2179 /***********************************************************************
2180 * _lcreat (KERNEL.83)
2182 HFILE16 WINAPI _lcreat16( LPCSTR path, INT16 attr )
2184 return Win32HandleToDosFileHandle( (HANDLE)_lcreat( path, attr ) );
2188 /***********************************************************************
2189 * _lcreat (KERNEL32.@)
2191 HFILE WINAPI _lcreat( LPCSTR path, INT attr )
2193 /* Mask off all flags not explicitly allowed by the doc */
2194 attr &= FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM;
2195 TRACE("%s %02x\n", path, attr );
2196 return (HFILE)CreateFileA( path, GENERIC_READ | GENERIC_WRITE,
2197 FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
2198 CREATE_ALWAYS, attr, 0 );
2202 /***********************************************************************
2203 * SetFilePointer (KERNEL32.@)
2205 DWORD WINAPI SetFilePointer( HANDLE hFile, LONG distance, LONG *highword,
2208 DWORD ret = INVALID_SET_FILE_POINTER;
2210 TRACE("handle %d offset %ld high %ld origin %ld\n",
2211 hFile, distance, highword?*highword:0, method );
2213 SERVER_START_REQ( set_file_pointer )
2215 req->handle = hFile;
2216 req->low = distance;
2217 req->high = highword ? *highword : (distance >= 0) ? 0 : -1;
2218 /* FIXME: assumes 1:1 mapping between Windows and Unix seek constants */
2219 req->whence = method;
2221 if (!wine_server_call_err( req ))
2223 ret = reply->new_low;
2224 if (highword) *highword = reply->new_high;
2232 /***********************************************************************
2233 * _llseek (KERNEL.84)
2236 * Seeking before the start of the file should be allowed for _llseek16,
2237 * but cause subsequent I/O operations to fail (cf. interrupt list)
2240 LONG WINAPI _llseek16( HFILE16 hFile, LONG lOffset, INT16 nOrigin )
2242 return SetFilePointer( DosFileHandleToWin32Handle(hFile), lOffset, NULL, nOrigin );
2246 /***********************************************************************
2247 * _llseek (KERNEL32.@)
2249 LONG WINAPI _llseek( HFILE hFile, LONG lOffset, INT nOrigin )
2251 return SetFilePointer( (HANDLE)hFile, lOffset, NULL, nOrigin );
2255 /***********************************************************************
2256 * _lopen (KERNEL.85)
2258 HFILE16 WINAPI _lopen16( LPCSTR path, INT16 mode )
2260 return Win32HandleToDosFileHandle( (HANDLE)_lopen( path, mode ) );
2264 /***********************************************************************
2265 * _lopen (KERNEL32.@)
2267 HFILE WINAPI _lopen( LPCSTR path, INT mode )
2269 DWORD access, sharing;
2271 TRACE("('%s',%04x)\n", path, mode );
2272 FILE_ConvertOFMode( mode, &access, &sharing );
2273 return (HFILE)CreateFileA( path, access, sharing, NULL, OPEN_EXISTING, 0, 0 );
2277 /***********************************************************************
2278 * _lwrite (KERNEL.86)
2280 UINT16 WINAPI _lwrite16( HFILE16 hFile, LPCSTR buffer, UINT16 count )
2282 return (UINT16)_hwrite( (HFILE)DosFileHandleToWin32Handle(hFile), buffer, (LONG)count );
2285 /***********************************************************************
2286 * _lwrite (KERNEL32.@)
2288 UINT WINAPI _lwrite( HFILE hFile, LPCSTR buffer, UINT count )
2290 return (UINT)_hwrite( hFile, buffer, (LONG)count );
2294 /***********************************************************************
2295 * _hread16 (KERNEL.349)
2297 LONG WINAPI _hread16( HFILE16 hFile, LPVOID buffer, LONG count)
2299 return _lread( (HFILE)DosFileHandleToWin32Handle(hFile), buffer, count );
2303 /***********************************************************************
2304 * _hread (KERNEL32.@)
2306 LONG WINAPI _hread( HFILE hFile, LPVOID buffer, LONG count)
2308 return _lread( hFile, buffer, count );
2312 /***********************************************************************
2313 * _hwrite (KERNEL.350)
2315 LONG WINAPI _hwrite16( HFILE16 hFile, LPCSTR buffer, LONG count )
2317 return _hwrite( (HFILE)DosFileHandleToWin32Handle(hFile), buffer, count );
2321 /***********************************************************************
2322 * _hwrite (KERNEL32.@)
2324 * experimentation yields that _lwrite:
2325 * o truncates the file at the current position with
2327 * o returns 0 on a 0 length write
2328 * o works with console handles
2331 LONG WINAPI _hwrite( HFILE handle, LPCSTR buffer, LONG count )
2335 TRACE("%d %p %ld\n", handle, buffer, count );
2339 /* Expand or truncate at current position */
2340 if (!SetEndOfFile( (HANDLE)handle )) return HFILE_ERROR;
2343 if (!WriteFile( (HANDLE)handle, buffer, count, &result, NULL ))
2349 /***********************************************************************
2350 * SetHandleCount (KERNEL.199)
2352 UINT16 WINAPI SetHandleCount16( UINT16 count )
2354 return SetHandleCount( count );
2358 /*************************************************************************
2359 * SetHandleCount (KERNEL32.@)
2361 UINT WINAPI SetHandleCount( UINT count )
2363 return min( 256, count );
2367 /***********************************************************************
2368 * FlushFileBuffers (KERNEL32.@)
2370 BOOL WINAPI FlushFileBuffers( HANDLE hFile )
2373 SERVER_START_REQ( flush_file )
2375 req->handle = hFile;
2376 ret = !wine_server_call_err( req );
2383 /**************************************************************************
2384 * SetEndOfFile (KERNEL32.@)
2386 BOOL WINAPI SetEndOfFile( HANDLE hFile )
2389 SERVER_START_REQ( truncate_file )
2391 req->handle = hFile;
2392 ret = !wine_server_call_err( req );
2399 /***********************************************************************
2400 * DeleteFile (KERNEL.146)
2402 BOOL16 WINAPI DeleteFile16( LPCSTR path )
2404 return DeleteFileA( path );
2408 /***********************************************************************
2409 * DeleteFileW (KERNEL32.@)
2411 BOOL WINAPI DeleteFileW( LPCWSTR path )
2413 DOS_FULL_NAME full_name;
2418 SetLastError(ERROR_INVALID_PARAMETER);
2421 TRACE("%s\n", debugstr_w(path) );
2425 WARN("Empty path passed\n");
2426 SetLastError( ERROR_FILE_NOT_FOUND );
2429 if (DOSFS_GetDevice( path ))
2431 WARN("cannot remove DOS device %s!\n", debugstr_w(path));
2432 SetLastError( ERROR_FILE_NOT_FOUND );
2436 if (!DOSFS_GetFullName( path, TRUE, &full_name )) return FALSE;
2438 /* check if we are allowed to delete the source */
2439 hFile = FILE_CreateFile( full_name.long_name, GENERIC_READ|GENERIC_WRITE, 0,
2440 NULL, OPEN_EXISTING, 0, 0, TRUE,
2441 GetDriveTypeW( full_name.short_name ) );
2442 if (!hFile) return FALSE;
2444 if (unlink( full_name.long_name ) == -1)
2455 /***********************************************************************
2456 * DeleteFileA (KERNEL32.@)
2458 BOOL WINAPI DeleteFileA( LPCSTR path )
2460 UNICODE_STRING pathW;
2465 SetLastError(ERROR_INVALID_PARAMETER);
2469 if (RtlCreateUnicodeStringFromAsciiz(&pathW, path))
2471 ret = DeleteFileW(pathW.Buffer);
2472 RtlFreeUnicodeString(&pathW);
2475 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
2480 /***********************************************************************
2481 * GetFileType (KERNEL32.@)
2483 DWORD WINAPI GetFileType( HANDLE hFile )
2485 DWORD ret = FILE_TYPE_UNKNOWN;
2486 SERVER_START_REQ( get_file_info )
2488 req->handle = hFile;
2489 if (!wine_server_call_err( req )) ret = reply->type;
2496 /* check if a file name is for an executable file (.exe or .com) */
2497 inline static BOOL is_executable( const char *name )
2499 int len = strlen(name);
2501 if (len < 4) return FALSE;
2502 return (!strcasecmp( name + len - 4, ".exe" ) ||
2503 !strcasecmp( name + len - 4, ".com" ));
2507 /***********************************************************************
2508 * FILE_AddBootRenameEntry
2510 * Adds an entry to the registry that is loaded when windows boots and
2511 * checks if there are some files to be removed or renamed/moved.
2512 * <fn1> has to be valid and <fn2> may be NULL. If both pointers are
2513 * non-NULL then the file is moved, otherwise it is deleted. The
2514 * entry of the registrykey is always appended with two zero
2515 * terminated strings. If <fn2> is NULL then the second entry is
2516 * simply a single 0-byte. Otherwise the second filename goes
2517 * there. The entries are prepended with \??\ before the path and the
2518 * second filename gets also a '!' as the first character if
2519 * MOVEFILE_REPLACE_EXISTING is set. After the final string another
2520 * 0-byte follows to indicate the end of the strings.
2522 * \??\D:\test\file1[0]
2523 * !\??\D:\test\file1_renamed[0]
2524 * \??\D:\Test|delete[0]
2525 * [0] <- file is to be deleted, second string empty
2526 * \??\D:\test\file2[0]
2527 * !\??\D:\test\file2_renamed[0]
2528 * [0] <- indicates end of strings
2531 * \??\D:\test\file1[0]
2532 * !\??\D:\test\file1_renamed[0]
2533 * \??\D:\Test|delete[0]
2534 * [0] <- file is to be deleted, second string empty
2535 * [0] <- indicates end of strings
2538 static BOOL FILE_AddBootRenameEntry( LPCWSTR fn1, LPCWSTR fn2, DWORD flags )
2540 static const WCHAR PreString[] = {'\\','?','?','\\',0};
2541 static const WCHAR ValueName[] = {'P','e','n','d','i','n','g',
2542 'F','i','l','e','R','e','n','a','m','e',
2543 'O','p','e','r','a','t','i','o','n','s',0};
2544 static const WCHAR SessionW[] = {'M','a','c','h','i','n','e','\\',
2545 'S','y','s','t','e','m','\\',
2546 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
2547 'C','o','n','t','r','o','l','\\',
2548 'S','e','s','s','i','o','n',' ','M','a','n','a','g','e','r',0};
2549 static const int info_size = FIELD_OFFSET( KEY_VALUE_PARTIAL_INFORMATION, Data );
2551 OBJECT_ATTRIBUTES attr;
2552 UNICODE_STRING nameW;
2553 KEY_VALUE_PARTIAL_INFORMATION *info;
2556 DWORD len0, len1, len2;
2558 BYTE *Buffer = NULL;
2561 attr.Length = sizeof(attr);
2562 attr.RootDirectory = 0;
2563 attr.ObjectName = &nameW;
2564 attr.Attributes = 0;
2565 attr.SecurityDescriptor = NULL;
2566 attr.SecurityQualityOfService = NULL;
2567 RtlInitUnicodeString( &nameW, SessionW );
2569 if (NtCreateKey( &Reboot, KEY_ALL_ACCESS, &attr, 0, NULL, 0, NULL ) != STATUS_SUCCESS)
2571 WARN("Error creating key for reboot managment [%s]\n",
2572 "SYSTEM\\CurrentControlSet\\Control\\Session Manager");
2576 len0 = strlenW(PreString);
2577 len1 = strlenW(fn1) + len0 + 1;
2580 len2 = strlenW(fn2) + len0 + 1;
2581 if (flags & MOVEFILE_REPLACE_EXISTING) len2++; /* Plus 1 because of the leading '!' */
2583 else len2 = 1; /* minimum is the 0 characters for the empty second string */
2585 /* convert characters to bytes */
2586 len0 *= sizeof(WCHAR);
2587 len1 *= sizeof(WCHAR);
2588 len2 *= sizeof(WCHAR);
2590 RtlInitUnicodeString( &nameW, ValueName );
2592 /* First we check if the key exists and if so how many bytes it already contains. */
2593 if (NtQueryValueKey( Reboot, &nameW, KeyValuePartialInformation,
2594 NULL, 0, &DataSize ) == STATUS_BUFFER_OVERFLOW)
2596 if (!(Buffer = HeapAlloc( GetProcessHeap(), 0, DataSize + len1 + len2 + sizeof(WCHAR) )))
2598 if (NtQueryValueKey( Reboot, &nameW, KeyValuePartialInformation,
2599 Buffer, DataSize, &DataSize )) goto Quit;
2600 info = (KEY_VALUE_PARTIAL_INFORMATION *)Buffer;
2601 if (info->Type != REG_MULTI_SZ) goto Quit;
2602 if (DataSize > sizeof(info)) DataSize -= sizeof(WCHAR); /* remove terminating null (will be added back later) */
2606 DataSize = info_size;
2607 if (!(Buffer = HeapAlloc( GetProcessHeap(), 0, DataSize + len1 + len2 + sizeof(WCHAR) )))
2611 p = (WCHAR *)(Buffer + DataSize);
2612 strcpyW( p, PreString );
2617 p = (WCHAR *)(Buffer + DataSize);
2618 if (flags & MOVEFILE_REPLACE_EXISTING)
2620 strcpyW( p, PreString );
2626 p = (WCHAR *)(Buffer + DataSize);
2628 DataSize += sizeof(WCHAR);
2631 /* add final null */
2632 p = (WCHAR *)(Buffer + DataSize);
2634 DataSize += sizeof(WCHAR);
2636 rc = !NtSetValueKey(Reboot, &nameW, 0, REG_MULTI_SZ, Buffer + info_size, DataSize - info_size);
2639 if (Reboot) NtClose(Reboot);
2640 if (Buffer) HeapFree( GetProcessHeap(), 0, Buffer );
2645 /**************************************************************************
2646 * MoveFileExW (KERNEL32.@)
2648 BOOL WINAPI MoveFileExW( LPCWSTR fn1, LPCWSTR fn2, DWORD flag )
2650 DOS_FULL_NAME full_name1, full_name2;
2652 DWORD attr = INVALID_FILE_ATTRIBUTES;
2654 TRACE("(%s,%s,%04lx)\n", debugstr_w(fn1), debugstr_w(fn2), flag);
2656 /* FIXME: <Gerhard W. Gruber>sparhawk@gmx.at
2657 In case of W9x and lesser this function should return 120 (ERROR_CALL_NOT_IMPLEMENTED)
2658 to be really compatible. Most programs wont have any problems though. In case
2659 you encounter one, this is what you should return here. I don't know what's up
2660 with NT 3.5. Is this function available there or not?
2661 Does anybody really care about 3.5? :)
2664 /* Filename1 has to be always set to a valid path. Filename2 may be NULL
2665 if the source file has to be deleted.
2668 SetLastError(ERROR_INVALID_PARAMETER);
2672 /* This function has to be run through in order to process the name properly.
2673 If the BOOTDELAY flag is set, the file doesn't need to exist though. At least
2674 that is the behaviour on NT 4.0. The operation accepts the filenames as
2675 they are given but it can't reply with a reasonable returncode. Success
2676 means in that case success for entering the values into the registry.
2678 if(!DOSFS_GetFullName( fn1, TRUE, &full_name1 ))
2680 if(!(flag & MOVEFILE_DELAY_UNTIL_REBOOT))
2684 if (fn2) /* !fn2 means delete fn1 */
2686 if (DOSFS_GetFullName( fn2, TRUE, &full_name2 ))
2688 if(!(flag & MOVEFILE_DELAY_UNTIL_REBOOT))
2690 /* target exists, check if we may overwrite */
2691 if (!(flag & MOVEFILE_REPLACE_EXISTING))
2693 SetLastError( ERROR_FILE_EXISTS );
2700 if (!DOSFS_GetFullName( fn2, FALSE, &full_name2 ))
2702 if(!(flag & MOVEFILE_DELAY_UNTIL_REBOOT))
2707 /* Source name and target path are valid */
2709 if (flag & MOVEFILE_DELAY_UNTIL_REBOOT)
2711 /* FIXME: (bon@elektron.ikp.physik.th-darmstadt.de 970706)
2712 Perhaps we should queue these command and execute it
2713 when exiting... What about using on_exit(2)
2715 FIXME("Please move existing file %s to file %s when Wine has finished\n",
2716 debugstr_w(fn1), debugstr_w(fn2));
2717 return FILE_AddBootRenameEntry( fn1, fn2, flag );
2720 attr = GetFileAttributesW( fn1 );
2721 if ( attr == INVALID_FILE_ATTRIBUTES ) return FALSE;
2723 /* check if we are allowed to rename the source */
2724 hFile = FILE_CreateFile( full_name1.long_name, 0, 0,
2725 NULL, OPEN_EXISTING, 0, 0, TRUE,
2726 GetDriveTypeW( full_name1.short_name ) );
2729 if (GetLastError() != ERROR_ACCESS_DENIED) return FALSE;
2730 if ( !(attr & FILE_ATTRIBUTE_DIRECTORY) ) return FALSE;
2731 /* if it's a directory we can continue */
2733 else CloseHandle(hFile);
2735 /* check, if we are allowed to delete the destination,
2736 ** (but the file not being there is fine) */
2737 hFile = FILE_CreateFile( full_name2.long_name, GENERIC_READ|GENERIC_WRITE, 0,
2738 NULL, OPEN_EXISTING, 0, 0, TRUE,
2739 GetDriveTypeW( full_name2.short_name ) );
2740 if(!hFile && GetLastError() != ERROR_FILE_NOT_FOUND) return FALSE;
2743 if (full_name1.drive != full_name2.drive)
2745 if (!(flag & MOVEFILE_COPY_ALLOWED))
2747 SetLastError( ERROR_NOT_SAME_DEVICE );
2750 else if ( attr & FILE_ATTRIBUTE_DIRECTORY )
2752 /* Strange, but that's what Windows returns */
2753 SetLastError ( ERROR_ACCESS_DENIED );
2757 if (rename( full_name1.long_name, full_name2.long_name ) == -1)
2758 /* Try copy/delete unless it's a directory. */
2759 /* FIXME: This does not handle the (unlikely) case that the two locations
2760 are on the same Wine drive, but on different Unix file systems. */
2762 if ( attr & FILE_ATTRIBUTE_DIRECTORY )
2769 if ( ! CopyFileW( fn1, fn2, !(flag & MOVEFILE_REPLACE_EXISTING) ))
2771 if ( ! DeleteFileW ( fn1 ) )
2775 if (is_executable( full_name1.long_name ) != is_executable( full_name2.long_name ))
2778 if (stat( full_name2.long_name, &fstat ) != -1)
2780 if (is_executable( full_name2.long_name ))
2781 /* set executable bit where read bit is set */
2782 fstat.st_mode |= (fstat.st_mode & 0444) >> 2;
2784 fstat.st_mode &= ~0111;
2785 chmod( full_name2.long_name, fstat.st_mode );
2790 else /* fn2 == NULL means delete source */
2792 if (flag & MOVEFILE_DELAY_UNTIL_REBOOT)
2794 if (flag & MOVEFILE_COPY_ALLOWED) {
2795 WARN("Illegal flag\n");
2796 SetLastError( ERROR_GEN_FAILURE );
2799 /* FIXME: (bon@elektron.ikp.physik.th-darmstadt.de 970706)
2800 Perhaps we should queue these command and execute it
2801 when exiting... What about using on_exit(2)
2803 FIXME("Please delete file %s when Wine has finished\n", debugstr_w(fn1));
2804 return FILE_AddBootRenameEntry( fn1, NULL, flag );
2807 if (unlink( full_name1.long_name ) == -1)
2812 return TRUE; /* successfully deleted */
2816 /**************************************************************************
2817 * MoveFileExA (KERNEL32.@)
2819 BOOL WINAPI MoveFileExA( LPCSTR fn1, LPCSTR fn2, DWORD flag )
2821 UNICODE_STRING fn1W, fn2W;
2826 SetLastError(ERROR_INVALID_PARAMETER);
2830 RtlCreateUnicodeStringFromAsciiz(&fn1W, fn1);
2831 if (fn2) RtlCreateUnicodeStringFromAsciiz(&fn2W, fn2);
2832 else fn2W.Buffer = NULL;
2834 ret = MoveFileExW( fn1W.Buffer, fn2W.Buffer, flag );
2836 RtlFreeUnicodeString(&fn1W);
2837 RtlFreeUnicodeString(&fn2W);
2842 /**************************************************************************
2843 * MoveFileW (KERNEL32.@)
2845 * Move file or directory
2847 BOOL WINAPI MoveFileW( LPCWSTR fn1, LPCWSTR fn2 )
2849 DOS_FULL_NAME full_name1, full_name2;
2854 SetLastError(ERROR_INVALID_PARAMETER);
2858 TRACE("(%s,%s)\n", debugstr_w(fn1), debugstr_w(fn2) );
2860 if (!DOSFS_GetFullName( fn1, TRUE, &full_name1 )) return FALSE;
2861 if (DOSFS_GetFullName( fn2, TRUE, &full_name2 )) {
2862 /* The new name must not already exist */
2863 SetLastError(ERROR_ALREADY_EXISTS);
2866 if (!DOSFS_GetFullName( fn2, FALSE, &full_name2 )) return FALSE;
2868 if (full_name1.drive == full_name2.drive) /* move */
2869 return MoveFileExW( fn1, fn2, MOVEFILE_COPY_ALLOWED );
2872 if (stat( full_name1.long_name, &fstat ))
2874 WARN("Invalid source file %s\n",
2875 full_name1.long_name);
2879 if (S_ISDIR(fstat.st_mode)) {
2880 /* No Move for directories across file systems */
2881 /* FIXME: Use right error code */
2882 SetLastError( ERROR_GEN_FAILURE );
2885 return CopyFileW(fn1, fn2, TRUE); /*fail, if exist */
2889 /**************************************************************************
2890 * MoveFileA (KERNEL32.@)
2892 BOOL WINAPI MoveFileA( LPCSTR fn1, LPCSTR fn2 )
2894 UNICODE_STRING fn1W, fn2W;
2899 SetLastError(ERROR_INVALID_PARAMETER);
2903 RtlCreateUnicodeStringFromAsciiz(&fn1W, fn1);
2904 RtlCreateUnicodeStringFromAsciiz(&fn2W, fn2);
2906 ret = MoveFileW( fn1W.Buffer, fn2W.Buffer );
2908 RtlFreeUnicodeString(&fn1W);
2909 RtlFreeUnicodeString(&fn2W);
2914 /**************************************************************************
2915 * CopyFileW (KERNEL32.@)
2917 BOOL WINAPI CopyFileW( LPCWSTR source, LPCWSTR dest, BOOL fail_if_exists )
2920 BY_HANDLE_FILE_INFORMATION info;
2925 if (!source || !dest)
2927 SetLastError(ERROR_INVALID_PARAMETER);
2931 TRACE("%s -> %s\n", debugstr_w(source), debugstr_w(dest));
2933 if ((h1 = CreateFileW(source, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE,
2934 NULL, OPEN_EXISTING, 0, 0)) == INVALID_HANDLE_VALUE)
2936 WARN("Unable to open source %s\n", debugstr_w(source));
2940 if (!GetFileInformationByHandle( h1, &info ))
2942 WARN("GetFileInformationByHandle returned error for %s\n", debugstr_w(source));
2947 if ((h2 = CreateFileW( dest, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
2948 fail_if_exists ? CREATE_NEW : CREATE_ALWAYS,
2949 info.dwFileAttributes, h1 )) == INVALID_HANDLE_VALUE)
2951 WARN("Unable to open dest %s\n", debugstr_w(dest));
2956 while (ReadFile( h1, buffer, sizeof(buffer), &count, NULL ) && count)
2962 if (!WriteFile( h2, p, count, &res, NULL ) || !res) goto done;
2975 /**************************************************************************
2976 * CopyFileA (KERNEL32.@)
2978 BOOL WINAPI CopyFileA( LPCSTR source, LPCSTR dest, BOOL fail_if_exists)
2980 UNICODE_STRING sourceW, destW;
2983 if (!source || !dest)
2985 SetLastError(ERROR_INVALID_PARAMETER);
2989 RtlCreateUnicodeStringFromAsciiz(&sourceW, source);
2990 RtlCreateUnicodeStringFromAsciiz(&destW, dest);
2992 ret = CopyFileW(sourceW.Buffer, destW.Buffer, fail_if_exists);
2994 RtlFreeUnicodeString(&sourceW);
2995 RtlFreeUnicodeString(&destW);
3000 /**************************************************************************
3001 * CopyFileExW (KERNEL32.@)
3003 * This implementation ignores most of the extra parameters passed-in into
3004 * the "ex" version of the method and calls the CopyFile method.
3005 * It will have to be fixed eventually.
3007 BOOL WINAPI CopyFileExW(LPCWSTR sourceFilename, LPCWSTR destFilename,
3008 LPPROGRESS_ROUTINE progressRoutine, LPVOID appData,
3009 LPBOOL cancelFlagPointer, DWORD copyFlags)
3012 * Interpret the only flag that CopyFile can interpret.
3014 return CopyFileW(sourceFilename, destFilename, (copyFlags & COPY_FILE_FAIL_IF_EXISTS) != 0);
3017 /**************************************************************************
3018 * CopyFileExA (KERNEL32.@)
3020 BOOL WINAPI CopyFileExA(LPCSTR sourceFilename, LPCSTR destFilename,
3021 LPPROGRESS_ROUTINE progressRoutine, LPVOID appData,
3022 LPBOOL cancelFlagPointer, DWORD copyFlags)
3024 UNICODE_STRING sourceW, destW;
3027 if (!sourceFilename || !destFilename)
3029 SetLastError(ERROR_INVALID_PARAMETER);
3033 RtlCreateUnicodeStringFromAsciiz(&sourceW, sourceFilename);
3034 RtlCreateUnicodeStringFromAsciiz(&destW, destFilename);
3036 ret = CopyFileExW(sourceW.Buffer, destW.Buffer, progressRoutine, appData,
3037 cancelFlagPointer, copyFlags);
3039 RtlFreeUnicodeString(&sourceW);
3040 RtlFreeUnicodeString(&destW);
3045 /***********************************************************************
3046 * SetFileTime (KERNEL32.@)
3048 BOOL WINAPI SetFileTime( HANDLE hFile,
3049 const FILETIME *lpCreationTime,
3050 const FILETIME *lpLastAccessTime,
3051 const FILETIME *lpLastWriteTime )
3054 SERVER_START_REQ( set_file_time )
3056 req->handle = hFile;
3057 if (lpLastAccessTime)
3058 RtlTimeToSecondsSince1970( (PLARGE_INTEGER) lpLastAccessTime, (DWORD *)&req->access_time );
3060 req->access_time = 0; /* FIXME */
3061 if (lpLastWriteTime)
3062 RtlTimeToSecondsSince1970( (PLARGE_INTEGER) lpLastWriteTime, (DWORD *)&req->write_time );
3064 req->write_time = 0; /* FIXME */
3065 ret = !wine_server_call_err( req );
3072 /**************************************************************************
3073 * LockFile (KERNEL32.@)
3075 BOOL WINAPI LockFile( HANDLE hFile, DWORD dwFileOffsetLow, DWORD dwFileOffsetHigh,
3076 DWORD nNumberOfBytesToLockLow, DWORD nNumberOfBytesToLockHigh )
3080 FIXME("not implemented in server\n");
3082 SERVER_START_REQ( lock_file )
3084 req->handle = hFile;
3085 req->offset_low = dwFileOffsetLow;
3086 req->offset_high = dwFileOffsetHigh;
3087 req->count_low = nNumberOfBytesToLockLow;
3088 req->count_high = nNumberOfBytesToLockHigh;
3089 ret = !wine_server_call_err( req );
3095 /**************************************************************************
3096 * LockFileEx [KERNEL32.@]
3098 * Locks a byte range within an open file for shared or exclusive access.
3105 * Per Microsoft docs, the third parameter (reserved) must be set to 0.
3107 BOOL WINAPI LockFileEx( HANDLE hFile, DWORD flags, DWORD reserved,
3108 DWORD nNumberOfBytesToLockLow, DWORD nNumberOfBytesToLockHigh,
3109 LPOVERLAPPED pOverlapped )
3111 FIXME("hFile=%d,flags=%ld,reserved=%ld,lowbytes=%ld,highbytes=%ld,overlapped=%p: stub.\n",
3112 hFile, flags, reserved, nNumberOfBytesToLockLow, nNumberOfBytesToLockHigh,
3115 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
3118 ERR("reserved == %ld: Supposed to be 0??\n", reserved);
3119 SetLastError(ERROR_INVALID_PARAMETER);
3126 /**************************************************************************
3127 * UnlockFile (KERNEL32.@)
3129 BOOL WINAPI UnlockFile( HANDLE hFile, DWORD dwFileOffsetLow, DWORD dwFileOffsetHigh,
3130 DWORD nNumberOfBytesToUnlockLow, DWORD nNumberOfBytesToUnlockHigh )
3134 FIXME("not implemented in server\n");
3136 SERVER_START_REQ( unlock_file )
3138 req->handle = hFile;
3139 req->offset_low = dwFileOffsetLow;
3140 req->offset_high = dwFileOffsetHigh;
3141 req->count_low = nNumberOfBytesToUnlockLow;
3142 req->count_high = nNumberOfBytesToUnlockHigh;
3143 ret = !wine_server_call_err( req );
3150 /**************************************************************************
3151 * UnlockFileEx (KERNEL32.@)
3153 BOOL WINAPI UnlockFileEx(
3156 DWORD nNumberOfBytesToUnlockLow,
3157 DWORD nNumberOfBytesToUnlockHigh,
3158 LPOVERLAPPED lpOverlapped
3161 FIXME("hFile=%d,reserved=%ld,lowbytes=%ld,highbytes=%ld,overlapped=%p: stub.\n",
3162 hFile, dwReserved, nNumberOfBytesToUnlockLow, nNumberOfBytesToUnlockHigh,
3164 if (dwReserved == 0)
3165 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
3168 ERR("reserved == %ld: Supposed to be 0??\n", dwReserved);
3169 SetLastError(ERROR_INVALID_PARAMETER);
3178 struct DOS_FILE_LOCK {
3179 struct DOS_FILE_LOCK * next;
3183 FILE_OBJECT * dos_file;
3184 /* char * unix_name;*/
3187 typedef struct DOS_FILE_LOCK DOS_FILE_LOCK;
3189 static DOS_FILE_LOCK *locks = NULL;
3190 static void DOS_RemoveFileLocks(FILE_OBJECT *file);
3193 /* Locks need to be mirrored because unix file locking is based
3194 * on the pid. Inside of wine there can be multiple WINE processes
3195 * that share the same unix pid.
3196 * Read's and writes should check these locks also - not sure
3197 * how critical that is at this point (FIXME).
3200 static BOOL DOS_AddLock(FILE_OBJECT *file, struct flock *f)
3202 DOS_FILE_LOCK *curr;
3205 processId = GetCurrentProcessId();
3207 /* check if lock overlaps a current lock for the same file */
3209 for (curr = locks; curr; curr = curr->next) {
3210 if (strcmp(curr->unix_name, file->unix_name) == 0) {
3211 if ((f->l_start == curr->base) && (f->l_len == curr->len))
3212 return TRUE;/* region is identic */
3213 if ((f->l_start < (curr->base + curr->len)) &&
3214 ((f->l_start + f->l_len) > curr->base)) {
3215 /* region overlaps */
3222 curr = HeapAlloc( GetProcessHeap(), 0, sizeof(DOS_FILE_LOCK) );
3223 curr->processId = GetCurrentProcessId();
3224 curr->base = f->l_start;
3225 curr->len = f->l_len;
3226 /* curr->unix_name = HEAP_strdupA( GetProcessHeap(), 0, file->unix_name);*/
3228 curr->dos_file = file;
3233 static void DOS_RemoveFileLocks(FILE_OBJECT *file)
3236 DOS_FILE_LOCK **curr;
3239 processId = GetCurrentProcessId();
3242 if ((*curr)->dos_file == file) {
3244 *curr = (*curr)->next;
3245 /* HeapFree( GetProcessHeap(), 0, rem->unix_name );*/
3246 HeapFree( GetProcessHeap(), 0, rem );
3249 curr = &(*curr)->next;
3253 static BOOL DOS_RemoveLock(FILE_OBJECT *file, struct flock *f)
3256 DOS_FILE_LOCK **curr;
3259 processId = GetCurrentProcessId();
3260 for (curr = &locks; *curr; curr = &(*curr)->next) {
3261 if ((*curr)->processId == processId &&
3262 (*curr)->dos_file == file &&
3263 (*curr)->base == f->l_start &&
3264 (*curr)->len == f->l_len) {
3265 /* this is the same lock */
3267 *curr = (*curr)->next;
3268 /* HeapFree( GetProcessHeap(), 0, rem->unix_name );*/
3269 HeapFree( GetProcessHeap(), 0, rem );
3273 /* no matching lock found */
3278 /**************************************************************************
3279 * LockFile (KERNEL32.@)
3281 BOOL WINAPI LockFile(
3282 HANDLE hFile,DWORD dwFileOffsetLow,DWORD dwFileOffsetHigh,
3283 DWORD nNumberOfBytesToLockLow,DWORD nNumberOfBytesToLockHigh )
3288 TRACE("handle %d offsetlow=%ld offsethigh=%ld nbyteslow=%ld nbyteshigh=%ld\n",
3289 hFile, dwFileOffsetLow, dwFileOffsetHigh,
3290 nNumberOfBytesToLockLow, nNumberOfBytesToLockHigh);
3292 if (dwFileOffsetHigh || nNumberOfBytesToLockHigh) {
3293 FIXME("Unimplemented bytes > 32bits\n");
3297 f.l_start = dwFileOffsetLow;
3298 f.l_len = nNumberOfBytesToLockLow;
3299 f.l_whence = SEEK_SET;
3303 if (!(file = FILE_GetFile(hFile,0,NULL))) return FALSE;
3305 /* shadow locks internally */
3306 if (!DOS_AddLock(file, &f)) {
3307 SetLastError( ERROR_LOCK_VIOLATION );
3311 /* FIXME: Unix locking commented out for now, doesn't work with Excel */
3312 #ifdef USE_UNIX_LOCKS
3313 if (fcntl(file->unix_handle, F_SETLK, &f) == -1) {
3314 if (errno == EACCES || errno == EAGAIN) {
3315 SetLastError( ERROR_LOCK_VIOLATION );
3320 /* remove our internal copy of the lock */
3321 DOS_RemoveLock(file, &f);
3329 /**************************************************************************
3330 * UnlockFile (KERNEL32.@)
3332 BOOL WINAPI UnlockFile(
3333 HANDLE hFile,DWORD dwFileOffsetLow,DWORD dwFileOffsetHigh,
3334 DWORD nNumberOfBytesToUnlockLow,DWORD nNumberOfBytesToUnlockHigh )
3339 TRACE("handle %d offsetlow=%ld offsethigh=%ld nbyteslow=%ld nbyteshigh=%ld\n",
3340 hFile, dwFileOffsetLow, dwFileOffsetHigh,
3341 nNumberOfBytesToUnlockLow, nNumberOfBytesToUnlockHigh);
3343 if (dwFileOffsetHigh || nNumberOfBytesToUnlockHigh) {
3344 WARN("Unimplemented bytes > 32bits\n");
3348 f.l_start = dwFileOffsetLow;
3349 f.l_len = nNumberOfBytesToUnlockLow;
3350 f.l_whence = SEEK_SET;
3354 if (!(file = FILE_GetFile(hFile,0,NULL))) return FALSE;
3356 DOS_RemoveLock(file, &f); /* ok if fails - may be another wine */
3358 /* FIXME: Unix locking commented out for now, doesn't work with Excel */
3359 #ifdef USE_UNIX_LOCKS
3360 if (fcntl(file->unix_handle, F_SETLK, &f) == -1) {
3369 /**************************************************************************
3370 * GetFileAttributesExW (KERNEL32.@)
3372 BOOL WINAPI GetFileAttributesExW(
3373 LPCWSTR lpFileName, GET_FILEEX_INFO_LEVELS fInfoLevelId,
3374 LPVOID lpFileInformation)
3376 DOS_FULL_NAME full_name;
3377 BY_HANDLE_FILE_INFORMATION info;
3379 if (!lpFileName || !lpFileInformation)
3381 SetLastError(ERROR_INVALID_PARAMETER);
3385 if (fInfoLevelId == GetFileExInfoStandard) {
3386 LPWIN32_FILE_ATTRIBUTE_DATA lpFad =
3387 (LPWIN32_FILE_ATTRIBUTE_DATA) lpFileInformation;
3388 if (!DOSFS_GetFullName( lpFileName, TRUE, &full_name )) return FALSE;
3389 if (!FILE_Stat( full_name.long_name, &info, NULL )) return FALSE;
3391 lpFad->dwFileAttributes = info.dwFileAttributes;
3392 lpFad->ftCreationTime = info.ftCreationTime;
3393 lpFad->ftLastAccessTime = info.ftLastAccessTime;
3394 lpFad->ftLastWriteTime = info.ftLastWriteTime;
3395 lpFad->nFileSizeHigh = info.nFileSizeHigh;
3396 lpFad->nFileSizeLow = info.nFileSizeLow;
3399 FIXME("invalid info level %d!\n", fInfoLevelId);
3407 /**************************************************************************
3408 * GetFileAttributesExA (KERNEL32.@)
3410 BOOL WINAPI GetFileAttributesExA(
3411 LPCSTR filename, GET_FILEEX_INFO_LEVELS fInfoLevelId,
3412 LPVOID lpFileInformation)
3414 UNICODE_STRING filenameW;
3417 if (!filename || !lpFileInformation)
3419 SetLastError(ERROR_INVALID_PARAMETER);
3423 if (RtlCreateUnicodeStringFromAsciiz(&filenameW, filename))
3425 ret = GetFileAttributesExW(filenameW.Buffer, fInfoLevelId, lpFileInformation);
3426 RtlFreeUnicodeString(&filenameW);
3429 SetLastError(ERROR_NOT_ENOUGH_MEMORY);