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 )
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 );
762 if (is_symlink) info->dwFileAttributes |= FILE_ATTRIBUTE_SYMLINK;
764 /* and now see if this is a hidden file, based on the name */
765 p = strrchr( unixName, '/');
766 p = p ? p + 1 : unixName;
767 if (*p == '.' && *(p+1) && (*(p+1) != '.' || *(p+2)))
769 static const WCHAR wineW[] = {'w','i','n','e',0};
770 static const WCHAR ShowDotFilesW[] = {'S','h','o','w','D','o','t','F','i','l','e','s',0};
771 static int show_dot_files = -1;
772 if (show_dot_files == -1)
773 show_dot_files = PROFILE_GetWineIniBool(wineW, ShowDotFilesW, 0);
775 info->dwFileAttributes |= FILE_ATTRIBUTE_HIDDEN;
782 /***********************************************************************
783 * GetFileInformationByHandle (KERNEL32.@)
785 DWORD WINAPI GetFileInformationByHandle( HANDLE hFile,
786 BY_HANDLE_FILE_INFORMATION *info )
791 TRACE("%08x\n", hFile);
793 SERVER_START_REQ( get_file_info )
796 if ((ret = !wine_server_call_err( req )))
798 /* FIXME: which file types are supported ?
799 * Serial ports (FILE_TYPE_CHAR) are not,
800 * and MSDN also says that pipes are not supported.
801 * FILE_TYPE_REMOTE seems to be supported according to
802 * MSDN q234741.txt */
803 if ((reply->type == FILE_TYPE_DISK) || (reply->type == FILE_TYPE_REMOTE))
805 RtlSecondsSince1970ToTime( reply->write_time, (LARGE_INTEGER *)&info->ftCreationTime );
806 RtlSecondsSince1970ToTime( reply->write_time, (LARGE_INTEGER *)&info->ftLastWriteTime );
807 RtlSecondsSince1970ToTime( reply->access_time, (LARGE_INTEGER *)&info->ftLastAccessTime );
808 info->dwFileAttributes = reply->attr;
809 info->dwVolumeSerialNumber = reply->serial;
810 info->nFileSizeHigh = reply->size_high;
811 info->nFileSizeLow = reply->size_low;
812 info->nNumberOfLinks = reply->links;
813 info->nFileIndexHigh = reply->index_high;
814 info->nFileIndexLow = reply->index_low;
818 SetLastError(ERROR_NOT_SUPPORTED);
828 /**************************************************************************
829 * GetFileAttributes (KERNEL.420)
831 DWORD WINAPI GetFileAttributes16( LPCSTR name )
833 return GetFileAttributesA( name );
837 /**************************************************************************
838 * GetFileAttributesW (KERNEL32.@)
840 DWORD WINAPI GetFileAttributesW( LPCWSTR name )
842 DOS_FULL_NAME full_name;
843 BY_HANDLE_FILE_INFORMATION info;
847 SetLastError( ERROR_INVALID_PARAMETER );
850 if (!DOSFS_GetFullName( name, TRUE, &full_name) )
852 if (!FILE_Stat( full_name.long_name, &info )) return -1;
853 return info.dwFileAttributes;
857 /**************************************************************************
858 * GetFileAttributesA (KERNEL32.@)
860 DWORD WINAPI GetFileAttributesA( LPCSTR name )
862 UNICODE_STRING nameW;
863 DWORD ret = (DWORD)-1;
867 SetLastError( ERROR_INVALID_PARAMETER );
871 if (RtlCreateUnicodeStringFromAsciiz(&nameW, name))
873 ret = GetFileAttributesW(nameW.Buffer);
874 RtlFreeUnicodeString(&nameW);
877 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
882 /**************************************************************************
883 * SetFileAttributes (KERNEL.421)
885 BOOL16 WINAPI SetFileAttributes16( LPCSTR lpFileName, DWORD attributes )
887 return SetFileAttributesA( lpFileName, attributes );
891 /**************************************************************************
892 * SetFileAttributesW (KERNEL32.@)
894 BOOL WINAPI SetFileAttributesW(LPCWSTR lpFileName, DWORD attributes)
897 DOS_FULL_NAME full_name;
901 SetLastError( ERROR_INVALID_PARAMETER );
905 TRACE("(%s,%lx)\n", debugstr_w(lpFileName), attributes);
907 if (!DOSFS_GetFullName( lpFileName, TRUE, &full_name ))
910 if(stat(full_name.long_name,&buf)==-1)
915 if (attributes & FILE_ATTRIBUTE_READONLY)
917 if(S_ISDIR(buf.st_mode))
919 WARN("FILE_ATTRIBUTE_READONLY ignored for directory.\n");
921 buf.st_mode &= ~0222; /* octal!, clear write permission bits */
922 attributes &= ~FILE_ATTRIBUTE_READONLY;
926 /* add write permission */
927 buf.st_mode |= (0600 | ((buf.st_mode & 044) >> 1)) & (~FILE_umask);
929 if (attributes & FILE_ATTRIBUTE_DIRECTORY)
931 if (!S_ISDIR(buf.st_mode))
932 FIXME("SetFileAttributes expected the file %s to be a directory\n",
933 debugstr_w(lpFileName));
934 attributes &= ~FILE_ATTRIBUTE_DIRECTORY;
936 attributes &= ~(FILE_ATTRIBUTE_NORMAL|FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_HIDDEN|FILE_ATTRIBUTE_SYSTEM);
938 FIXME("(%s):%lx attribute(s) not implemented.\n", debugstr_w(lpFileName), attributes);
939 if (-1==chmod(full_name.long_name,buf.st_mode))
941 if (GetDriveTypeW(lpFileName) == DRIVE_CDROM)
943 SetLastError( ERROR_ACCESS_DENIED );
948 * FIXME: We don't return FALSE here because of differences between
949 * Linux and Windows privileges. Under Linux only the owner of
950 * the file is allowed to change file attributes. Under Windows,
951 * applications expect that if you can write to a file, you can also
952 * change its attributes (see GENERIC_WRITE). We could try to be
953 * clever here but that would break multi-user installations where
954 * users share read-only DLLs. This is because some installers like
955 * to change attributes of already installed DLLs.
957 FIXME("Couldn't set file attributes for existing file \"%s\".\n"
958 "Check permissions or set VFAT \"quiet\" mount flag\n", full_name.long_name);
964 /**************************************************************************
965 * SetFileAttributesA (KERNEL32.@)
967 BOOL WINAPI SetFileAttributesA(LPCSTR lpFileName, DWORD attributes)
969 UNICODE_STRING filenameW;
974 SetLastError( ERROR_INVALID_PARAMETER );
978 if (RtlCreateUnicodeStringFromAsciiz(&filenameW, lpFileName))
980 ret = SetFileAttributesW(filenameW.Buffer, attributes);
981 RtlFreeUnicodeString(&filenameW);
984 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
989 /***********************************************************************
990 * GetFileSize (KERNEL32.@)
992 DWORD WINAPI GetFileSize( HANDLE hFile, LPDWORD filesizehigh )
994 BY_HANDLE_FILE_INFORMATION info;
995 if (!GetFileInformationByHandle( hFile, &info )) return -1;
996 if (filesizehigh) *filesizehigh = info.nFileSizeHigh;
997 return info.nFileSizeLow;
1001 /***********************************************************************
1002 * GetFileTime (KERNEL32.@)
1004 BOOL WINAPI GetFileTime( HANDLE hFile, FILETIME *lpCreationTime,
1005 FILETIME *lpLastAccessTime,
1006 FILETIME *lpLastWriteTime )
1008 BY_HANDLE_FILE_INFORMATION info;
1009 if (!GetFileInformationByHandle( hFile, &info )) return FALSE;
1010 if (lpCreationTime) *lpCreationTime = info.ftCreationTime;
1011 if (lpLastAccessTime) *lpLastAccessTime = info.ftLastAccessTime;
1012 if (lpLastWriteTime) *lpLastWriteTime = info.ftLastWriteTime;
1016 /***********************************************************************
1017 * CompareFileTime (KERNEL32.@)
1019 INT WINAPI CompareFileTime( LPFILETIME x, LPFILETIME y )
1021 if (!x || !y) return -1;
1023 if (x->dwHighDateTime > y->dwHighDateTime)
1025 if (x->dwHighDateTime < y->dwHighDateTime)
1027 if (x->dwLowDateTime > y->dwLowDateTime)
1029 if (x->dwLowDateTime < y->dwLowDateTime)
1034 /***********************************************************************
1035 * FILE_GetTempFileName : utility for GetTempFileName
1037 static UINT FILE_GetTempFileName( LPCWSTR path, LPCWSTR prefix, UINT unique,
1040 static UINT unique_temp;
1041 DOS_FULL_NAME full_name;
1047 if ( !path || !prefix || !buffer )
1049 SetLastError( ERROR_INVALID_PARAMETER );
1053 if (!unique_temp) unique_temp = time(NULL) & 0xffff;
1054 num = unique ? (unique & 0xffff) : (unique_temp++ & 0xffff);
1056 strcpyW( buffer, path );
1057 p = buffer + strlenW(buffer);
1059 /* add a \, if there isn't one and path is more than just the drive letter ... */
1060 if ( !((strlenW(buffer) == 2) && (buffer[1] == ':'))
1061 && ((p == buffer) || (p[-1] != '\\'))) *p++ = '\\';
1063 for (i = 3; (i > 0) && (*prefix); i--) *p++ = *prefix++;
1065 sprintf( buf, "%04x.tmp", num );
1066 MultiByteToWideChar(CP_ACP, 0, buf, -1, p, 20);
1068 /* Now try to create it */
1074 HANDLE handle = CreateFileW( buffer, GENERIC_WRITE, 0, NULL,
1075 CREATE_NEW, FILE_ATTRIBUTE_NORMAL, 0 );
1076 if (handle != INVALID_HANDLE_VALUE)
1077 { /* We created it */
1078 TRACE("created %s\n", debugstr_w(buffer) );
1079 CloseHandle( handle );
1082 if (GetLastError() != ERROR_FILE_EXISTS)
1083 break; /* No need to go on */
1085 sprintf( buf, "%04x.tmp", num );
1086 MultiByteToWideChar(CP_ACP, 0, buf, -1, p, 20);
1087 } while (num != (unique & 0xffff));
1090 /* Get the full path name */
1092 if (DOSFS_GetFullName( buffer, FALSE, &full_name ))
1095 /* Check if we have write access in the directory */
1096 if ((slash = strrchr( full_name.long_name, '/' ))) *slash = '\0';
1097 if (access( full_name.long_name, W_OK ) == -1)
1098 WARN("returns %s, which doesn't seem to be writeable.\n",
1099 debugstr_w(buffer) );
1101 TRACE("returning %s\n", debugstr_w(buffer) );
1102 return unique ? unique : num;
1106 /***********************************************************************
1107 * GetTempFileNameA (KERNEL32.@)
1109 UINT WINAPI GetTempFileNameA( LPCSTR path, LPCSTR prefix, UINT unique,
1112 UNICODE_STRING pathW, prefixW;
1113 WCHAR bufferW[MAX_PATH];
1116 if ( !path || !prefix || !buffer )
1118 SetLastError( ERROR_INVALID_PARAMETER );
1122 RtlCreateUnicodeStringFromAsciiz(&pathW, path);
1123 RtlCreateUnicodeStringFromAsciiz(&prefixW, prefix);
1125 ret = GetTempFileNameW(pathW.Buffer, prefixW.Buffer, unique, bufferW);
1127 WideCharToMultiByte(CP_ACP, 0, bufferW, -1, buffer, MAX_PATH, NULL, NULL);
1129 RtlFreeUnicodeString(&pathW);
1130 RtlFreeUnicodeString(&prefixW);
1134 /***********************************************************************
1135 * GetTempFileNameW (KERNEL32.@)
1137 UINT WINAPI GetTempFileNameW( LPCWSTR path, LPCWSTR prefix, UINT unique,
1140 return FILE_GetTempFileName( path, prefix, unique, buffer );
1144 /***********************************************************************
1145 * GetTempFileName (KERNEL.97)
1147 UINT16 WINAPI GetTempFileName16( BYTE drive, LPCSTR prefix, UINT16 unique,
1150 char temppath[MAX_PATH];
1151 char *prefix16 = NULL;
1154 if (!(drive & ~TF_FORCEDRIVE)) /* drive 0 means current default drive */
1155 drive |= DRIVE_GetCurrentDrive() + 'A';
1157 if ((drive & TF_FORCEDRIVE) &&
1158 !DRIVE_IsValid( toupper(drive & ~TF_FORCEDRIVE) - 'A' ))
1160 drive &= ~TF_FORCEDRIVE;
1161 WARN("invalid drive %d specified\n", drive );
1164 if (drive & TF_FORCEDRIVE)
1165 sprintf(temppath,"%c:", drive & ~TF_FORCEDRIVE );
1167 GetTempPathA( MAX_PATH, temppath );
1171 prefix16 = HeapAlloc(GetProcessHeap(), 0, strlen(prefix) + 2);
1173 strcpy(prefix16 + 1, prefix);
1176 ret = GetTempFileNameA( temppath, prefix16, unique, buffer );
1178 if (prefix16) HeapFree(GetProcessHeap(), 0, prefix16);
1182 /***********************************************************************
1185 * Implementation of OpenFile16() and OpenFile32().
1187 static HFILE FILE_DoOpenFile( LPCSTR name, OFSTRUCT *ofs, UINT mode,
1193 WORD filedatetime[2];
1194 DOS_FULL_NAME full_name;
1195 DWORD access, sharing;
1197 WCHAR buffer[MAX_PATH];
1200 if (!ofs) return HFILE_ERROR;
1202 TRACE("%s %s %s %s%s%s%s%s%s%s%s%s\n",name,
1203 ((mode & 0x3 )==OF_READ)?"OF_READ":
1204 ((mode & 0x3 )==OF_WRITE)?"OF_WRITE":
1205 ((mode & 0x3 )==OF_READWRITE)?"OF_READWRITE":"unknown",
1206 ((mode & 0x70 )==OF_SHARE_COMPAT)?"OF_SHARE_COMPAT":
1207 ((mode & 0x70 )==OF_SHARE_DENY_NONE)?"OF_SHARE_DENY_NONE":
1208 ((mode & 0x70 )==OF_SHARE_DENY_READ)?"OF_SHARE_DENY_READ":
1209 ((mode & 0x70 )==OF_SHARE_DENY_WRITE)?"OF_SHARE_DENY_WRITE":
1210 ((mode & 0x70 )==OF_SHARE_EXCLUSIVE)?"OF_SHARE_EXCLUSIVE":"unknown",
1211 ((mode & OF_PARSE )==OF_PARSE)?"OF_PARSE ":"",
1212 ((mode & OF_DELETE )==OF_DELETE)?"OF_DELETE ":"",
1213 ((mode & OF_VERIFY )==OF_VERIFY)?"OF_VERIFY ":"",
1214 ((mode & OF_SEARCH )==OF_SEARCH)?"OF_SEARCH ":"",
1215 ((mode & OF_CANCEL )==OF_CANCEL)?"OF_CANCEL ":"",
1216 ((mode & OF_CREATE )==OF_CREATE)?"OF_CREATE ":"",
1217 ((mode & OF_PROMPT )==OF_PROMPT)?"OF_PROMPT ":"",
1218 ((mode & OF_EXIST )==OF_EXIST)?"OF_EXIST ":"",
1219 ((mode & OF_REOPEN )==OF_REOPEN)?"OF_REOPEN ":""
1223 ofs->cBytes = sizeof(OFSTRUCT);
1225 if (mode & OF_REOPEN) name = ofs->szPathName;
1228 ERR("called with `name' set to NULL ! Please debug.\n");
1232 TRACE("%s %04x\n", name, mode );
1234 /* the watcom 10.6 IDE relies on a valid path returned in ofs->szPathName
1235 Are there any cases where getting the path here is wrong?
1236 Uwe Bonnes 1997 Apr 2 */
1237 if (!GetFullPathNameA( name, sizeof(ofs->szPathName),
1238 ofs->szPathName, NULL )) goto error;
1239 FILE_ConvertOFMode( mode, &access, &sharing );
1241 /* OF_PARSE simply fills the structure */
1243 if (mode & OF_PARSE)
1245 ofs->fFixedDisk = (GetDriveType16( ofs->szPathName[0]-'A' )
1246 != DRIVE_REMOVABLE);
1247 TRACE("(%s): OF_PARSE, res = '%s'\n",
1248 name, ofs->szPathName );
1252 /* OF_CREATE is completely different from all other options, so
1255 if (mode & OF_CREATE)
1257 if ((handle = CreateFileA( name, GENERIC_READ | GENERIC_WRITE,
1258 sharing, NULL, CREATE_ALWAYS,
1259 FILE_ATTRIBUTE_NORMAL, 0 ))== INVALID_HANDLE_VALUE)
1264 MultiByteToWideChar(CP_ACP, 0, name, -1, buffer, MAX_PATH);
1267 /* If OF_SEARCH is set, ignore the given path */
1269 if ((mode & OF_SEARCH) && !(mode & OF_REOPEN))
1271 /* First try the file name as is */
1272 if (DOSFS_GetFullName( nameW, TRUE, &full_name )) goto found;
1273 /* Now remove the path */
1274 if (nameW[0] && (nameW[1] == ':')) nameW += 2;
1275 if ((p = strrchrW( nameW, '\\' ))) nameW = p + 1;
1276 if ((p = strrchrW( nameW, '/' ))) nameW = p + 1;
1277 if (!nameW[0]) goto not_found;
1280 /* Now look for the file */
1282 if (!DIR_SearchPath( NULL, nameW, NULL, &full_name, win32 )) goto not_found;
1285 TRACE("found %s = %s\n",
1286 full_name.long_name, debugstr_w(full_name.short_name) );
1287 WideCharToMultiByte(CP_ACP, 0, full_name.short_name, -1,
1288 ofs->szPathName, sizeof(ofs->szPathName), NULL, NULL);
1290 if (mode & OF_SHARE_EXCLUSIVE)
1291 /* Some InstallShield version uses OF_SHARE_EXCLUSIVE
1292 on the file <tempdir>/_ins0432._mp to determine how
1293 far installation has proceeded.
1294 _ins0432._mp is an executable and while running the
1295 application expects the open with OF_SHARE_ to fail*/
1297 As our loader closes the files after loading the executable,
1298 we can't find the running executable with FILE_InUse.
1299 The loader should keep the file open, as Windows does that, too.
1302 char *last = strrchr(full_name.long_name,'/');
1304 last = full_name.long_name - 1;
1305 if (GetModuleHandle16(last+1))
1307 TRACE("Denying shared open for %s\n",full_name.long_name);
1312 if (mode & OF_DELETE)
1314 if (unlink( full_name.long_name ) == -1) goto not_found;
1315 TRACE("(%s): OF_DELETE return = OK\n", name);
1319 handle = FILE_CreateFile( full_name.long_name, access, sharing,
1320 NULL, OPEN_EXISTING, 0, 0,
1321 DRIVE_GetFlags(full_name.drive) & DRIVE_FAIL_READ_ONLY,
1322 GetDriveTypeW( full_name.short_name ) );
1323 if (!handle) goto not_found;
1325 GetFileTime( handle, NULL, NULL, &filetime );
1326 FileTimeToDosDateTime( &filetime, &filedatetime[0], &filedatetime[1] );
1327 if ((mode & OF_VERIFY) && (mode & OF_REOPEN))
1329 if (ofs->Reserved1 != filedatetime[0] || ofs->Reserved2 != filedatetime[1] )
1331 CloseHandle( handle );
1332 WARN("(%s): OF_VERIFY failed\n", name );
1333 /* FIXME: what error here? */
1334 SetLastError( ERROR_FILE_NOT_FOUND );
1338 ofs->Reserved1 = filedatetime[0];
1339 ofs->Reserved2 = filedatetime[1];
1341 success: /* We get here if the open was successful */
1342 TRACE("(%s): OK, return = %x\n", name, handle );
1345 hFileRet = (HFILE)handle;
1346 if (mode & OF_EXIST) /* Return the handle, but close it first */
1347 CloseHandle( handle );
1351 hFileRet = Win32HandleToDosFileHandle( handle );
1352 if (hFileRet == HFILE_ERROR16) goto error;
1353 if (mode & OF_EXIST) /* Return the handle, but close it first */
1354 _lclose16( hFileRet );
1358 not_found: /* We get here if the file does not exist */
1359 WARN("'%s' not found or sharing violation\n", name );
1360 SetLastError( ERROR_FILE_NOT_FOUND );
1363 error: /* We get here if there was an error opening the file */
1364 ofs->nErrCode = GetLastError();
1365 WARN("(%s): return = HFILE_ERROR error= %d\n",
1366 name,ofs->nErrCode );
1371 /***********************************************************************
1372 * OpenFile (KERNEL.74)
1373 * OpenFileEx (KERNEL.360)
1375 HFILE16 WINAPI OpenFile16( LPCSTR name, OFSTRUCT *ofs, UINT16 mode )
1377 return FILE_DoOpenFile( name, ofs, mode, FALSE );
1381 /***********************************************************************
1382 * OpenFile (KERNEL32.@)
1384 HFILE WINAPI OpenFile( LPCSTR name, OFSTRUCT *ofs, UINT mode )
1386 return FILE_DoOpenFile( name, ofs, mode, TRUE );
1390 /***********************************************************************
1391 * FILE_InitProcessDosHandles
1393 * Allocates the default DOS handles for a process. Called either by
1394 * Win32HandleToDosFileHandle below or by the DOSVM stuff.
1396 static void FILE_InitProcessDosHandles( void )
1398 HANDLE cp = GetCurrentProcess();
1399 DuplicateHandle(cp, GetStdHandle(STD_INPUT_HANDLE), cp, &dos_handles[0],
1400 0, TRUE, DUPLICATE_SAME_ACCESS);
1401 DuplicateHandle(cp, GetStdHandle(STD_OUTPUT_HANDLE), cp, &dos_handles[1],
1402 0, TRUE, DUPLICATE_SAME_ACCESS);
1403 DuplicateHandle(cp, GetStdHandle(STD_ERROR_HANDLE), cp, &dos_handles[2],
1404 0, TRUE, DUPLICATE_SAME_ACCESS);
1405 DuplicateHandle(cp, GetStdHandle(STD_ERROR_HANDLE), cp, &dos_handles[3],
1406 0, TRUE, DUPLICATE_SAME_ACCESS);
1407 DuplicateHandle(cp, GetStdHandle(STD_ERROR_HANDLE), cp, &dos_handles[4],
1408 0, TRUE, DUPLICATE_SAME_ACCESS);
1411 /***********************************************************************
1412 * Win32HandleToDosFileHandle (KERNEL32.21)
1414 * Allocate a DOS handle for a Win32 handle. The Win32 handle is no
1415 * longer valid after this function (even on failure).
1417 * Note: this is not exactly right, since on Win95 the Win32 handles
1418 * are on top of DOS handles and we do it the other way
1419 * around. Should be good enough though.
1421 HFILE WINAPI Win32HandleToDosFileHandle( HANDLE handle )
1425 if (!handle || (handle == INVALID_HANDLE_VALUE))
1428 for (i = 5; i < DOS_TABLE_SIZE; i++)
1429 if (!dos_handles[i])
1431 dos_handles[i] = handle;
1432 TRACE("Got %d for h32 %d\n", i, handle );
1435 CloseHandle( handle );
1436 SetLastError( ERROR_TOO_MANY_OPEN_FILES );
1441 /***********************************************************************
1442 * DosFileHandleToWin32Handle (KERNEL32.20)
1444 * Return the Win32 handle for a DOS handle.
1446 * Note: this is not exactly right, since on Win95 the Win32 handles
1447 * are on top of DOS handles and we do it the other way
1448 * around. Should be good enough though.
1450 HANDLE WINAPI DosFileHandleToWin32Handle( HFILE handle )
1452 HFILE16 hfile = (HFILE16)handle;
1453 if (hfile < 5 && !dos_handles[hfile]) FILE_InitProcessDosHandles();
1454 if ((hfile >= DOS_TABLE_SIZE) || !dos_handles[hfile])
1456 SetLastError( ERROR_INVALID_HANDLE );
1457 return INVALID_HANDLE_VALUE;
1459 return dos_handles[hfile];
1463 /***********************************************************************
1464 * DisposeLZ32Handle (KERNEL32.22)
1466 * Note: this is not entirely correct, we should only close the
1467 * 32-bit handle and not the 16-bit one, but we cannot do
1468 * this because of the way our DOS handles are implemented.
1469 * It shouldn't break anything though.
1471 void WINAPI DisposeLZ32Handle( HANDLE handle )
1475 if (!handle || (handle == INVALID_HANDLE_VALUE)) return;
1477 for (i = 5; i < DOS_TABLE_SIZE; i++)
1478 if (dos_handles[i] == handle)
1481 CloseHandle( handle );
1487 /***********************************************************************
1490 * dup2() function for DOS handles.
1492 HFILE16 FILE_Dup2( HFILE16 hFile1, HFILE16 hFile2 )
1496 if (hFile1 < 5 && !dos_handles[hFile1]) FILE_InitProcessDosHandles();
1498 if ((hFile1 >= DOS_TABLE_SIZE) || (hFile2 >= DOS_TABLE_SIZE) || !dos_handles[hFile1])
1500 SetLastError( ERROR_INVALID_HANDLE );
1501 return HFILE_ERROR16;
1503 if (!DuplicateHandle( GetCurrentProcess(), dos_handles[hFile1],
1504 GetCurrentProcess(), &new_handle,
1505 0, FALSE, DUPLICATE_SAME_ACCESS ))
1506 return HFILE_ERROR16;
1507 if (dos_handles[hFile2]) CloseHandle( dos_handles[hFile2] );
1508 dos_handles[hFile2] = new_handle;
1513 /***********************************************************************
1514 * _lclose (KERNEL.81)
1516 HFILE16 WINAPI _lclose16( HFILE16 hFile )
1518 if ((hFile >= DOS_TABLE_SIZE) || !dos_handles[hFile])
1520 SetLastError( ERROR_INVALID_HANDLE );
1521 return HFILE_ERROR16;
1523 TRACE("%d (handle32=%d)\n", hFile, dos_handles[hFile] );
1524 CloseHandle( dos_handles[hFile] );
1525 dos_handles[hFile] = 0;
1530 /***********************************************************************
1531 * _lclose (KERNEL32.@)
1533 HFILE WINAPI _lclose( HFILE hFile )
1535 TRACE("handle %d\n", hFile );
1536 return CloseHandle( (HANDLE)hFile ) ? 0 : HFILE_ERROR;
1539 /***********************************************************************
1540 * GetOverlappedResult (KERNEL32.@)
1542 * Check the result of an Asynchronous data transfer from a file.
1548 * If successful (and relevant) lpTransferred will hold the number of
1549 * bytes transferred during the async operation.
1553 * Currently only works for WaitCommEvent, ReadFile, WriteFile
1554 * with communications ports.
1557 BOOL WINAPI GetOverlappedResult(
1558 HANDLE hFile, /* [in] handle of file to check on */
1559 LPOVERLAPPED lpOverlapped, /* [in/out] pointer to overlapped */
1560 LPDWORD lpTransferred, /* [in/out] number of bytes transferred */
1561 BOOL bWait /* [in] wait for the transfer to complete ? */
1565 TRACE("(%d %p %p %x)\n", hFile, lpOverlapped, lpTransferred, bWait);
1567 if(lpOverlapped==NULL)
1569 ERR("lpOverlapped was null\n");
1572 if(!lpOverlapped->hEvent)
1574 ERR("lpOverlapped->hEvent was null\n");
1581 TRACE("waiting on %p\n",lpOverlapped);
1582 r = WaitForSingleObjectEx(lpOverlapped->hEvent, INFINITE, TRUE);
1583 TRACE("wait on %p returned %ld\n",lpOverlapped,r);
1584 } while (r==STATUS_USER_APC);
1586 else if ( lpOverlapped->Internal == STATUS_PENDING )
1588 /* Wait in order to give APCs a chance to run. */
1589 /* This is cheating, so we must set the event again in case of success -
1590 it may be a non-manual reset event. */
1592 TRACE("waiting on %p\n",lpOverlapped);
1593 r = WaitForSingleObjectEx(lpOverlapped->hEvent, 0, TRUE);
1594 TRACE("wait on %p returned %ld\n",lpOverlapped,r);
1595 } while (r==STATUS_USER_APC);
1596 if ( r == WAIT_OBJECT_0 )
1597 NtSetEvent ( lpOverlapped->hEvent, NULL );
1601 *lpTransferred = lpOverlapped->InternalHigh;
1603 switch ( lpOverlapped->Internal )
1605 case STATUS_SUCCESS:
1607 case STATUS_PENDING:
1608 SetLastError ( ERROR_IO_INCOMPLETE );
1609 if ( bWait ) ERR ("PENDING status after waiting!\n");
1612 SetLastError ( RtlNtStatusToDosError ( lpOverlapped->Internal ) );
1617 /***********************************************************************
1618 * CancelIo (KERNEL32.@)
1620 BOOL WINAPI CancelIo(HANDLE handle)
1622 async_private *ovp,*t;
1624 TRACE("handle = %x\n",handle);
1626 for (ovp = NtCurrentTeb()->pending_list; ovp; ovp = t)
1629 if ( ovp->handle == handle )
1630 cancel_async ( ovp );
1632 WaitForMultipleObjectsEx(0,NULL,FALSE,1,TRUE);
1636 /***********************************************************************
1637 * FILE_AsyncReadService (INTERNAL)
1639 * This function is called while the client is waiting on the
1640 * server, so we can't make any server calls here.
1642 static void FILE_AsyncReadService(async_private *ovp)
1644 async_fileio *fileio = (async_fileio*) ovp;
1645 LPOVERLAPPED lpOverlapped = fileio->lpOverlapped;
1647 int already = lpOverlapped->InternalHigh;
1649 TRACE("%p %p\n", lpOverlapped, fileio->buffer );
1651 /* check to see if the data is ready (non-blocking) */
1653 if ( fileio->fd_type == FD_TYPE_SOCKET )
1654 result = read (ovp->fd, &fileio->buffer[already], fileio->count - already);
1657 result = pread (ovp->fd, &fileio->buffer[already], fileio->count - already,
1658 OVERLAPPED_OFFSET (lpOverlapped) + already);
1659 if ((result < 0) && (errno == ESPIPE))
1660 result = read (ovp->fd, &fileio->buffer[already], fileio->count - already);
1663 if ( (result<0) && ((errno == EAGAIN) || (errno == EINTR)))
1665 TRACE("Deferred read %d\n",errno);
1670 /* check to see if the transfer is complete */
1673 r = FILE_GetNtStatus ();
1677 lpOverlapped->InternalHigh += result;
1678 TRACE("read %d more bytes %ld/%d so far\n",result,lpOverlapped->InternalHigh,fileio->count);
1680 if(lpOverlapped->InternalHigh >= fileio->count || fileio->fd_type == FD_TYPE_SOCKET )
1686 lpOverlapped->Internal = r;
1689 /***********************************************************************
1690 * FILE_ReadFileEx (INTERNAL)
1692 static BOOL FILE_ReadFileEx(HANDLE hFile, LPVOID buffer, DWORD bytesToRead,
1693 LPOVERLAPPED overlapped,
1694 LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine,
1702 TRACE("file %d to buf %p num %ld %p func %p\n",
1703 hFile, buffer, bytesToRead, overlapped, lpCompletionRoutine);
1705 /* check that there is an overlapped struct */
1706 if (overlapped==NULL)
1708 SetLastError(ERROR_INVALID_PARAMETER);
1712 fd = FILE_GetUnixHandleType ( hFile, GENERIC_READ, &type, &flags);
1715 WARN ( "Couldn't get FD\n" );
1719 ovp = (async_fileio*) HeapAlloc(GetProcessHeap(), 0, sizeof (async_fileio));
1722 TRACE("HeapAlloc Failed\n");
1723 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1727 ovp->async.ops = ( lpCompletionRoutine ? &fileio_async_ops : &fileio_nocomp_async_ops );
1728 ovp->async.handle = hFile;
1730 ovp->async.type = ASYNC_TYPE_READ;
1731 ovp->async.func = FILE_AsyncReadService;
1732 ovp->async.event = hEvent;
1733 ovp->lpOverlapped = overlapped;
1734 ovp->count = bytesToRead;
1735 ovp->completion_func = lpCompletionRoutine;
1736 ovp->buffer = buffer;
1737 ovp->fd_type = type;
1739 return !register_new_async (&ovp->async);
1747 /***********************************************************************
1748 * ReadFileEx (KERNEL32.@)
1750 BOOL WINAPI ReadFileEx(HANDLE hFile, LPVOID buffer, DWORD bytesToRead,
1751 LPOVERLAPPED overlapped,
1752 LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine)
1754 overlapped->InternalHigh = 0;
1755 return FILE_ReadFileEx(hFile,buffer,bytesToRead,overlapped,lpCompletionRoutine, INVALID_HANDLE_VALUE);
1758 static BOOL FILE_TimeoutRead(HANDLE hFile, LPVOID buffer, DWORD bytesToRead, LPDWORD bytesRead)
1763 TRACE("%d %p %ld %p\n", hFile, buffer, bytesToRead, bytesRead );
1765 ZeroMemory(&ov, sizeof (OVERLAPPED));
1766 if(STATUS_SUCCESS==NtCreateEvent(&ov.hEvent, SYNCHRONIZE, NULL, 0, 0))
1768 if(FILE_ReadFileEx(hFile, buffer, bytesToRead, &ov, NULL, ov.hEvent))
1770 r = GetOverlappedResult(hFile, &ov, bytesRead, TRUE);
1773 CloseHandle(ov.hEvent);
1777 /***********************************************************************
1778 * ReadFile (KERNEL32.@)
1780 BOOL WINAPI ReadFile( HANDLE hFile, LPVOID buffer, DWORD bytesToRead,
1781 LPDWORD bytesRead, LPOVERLAPPED overlapped )
1783 int unix_handle, result, flags;
1786 TRACE("%d %p %ld %p %p\n", hFile, buffer, bytesToRead,
1787 bytesRead, overlapped );
1789 if (bytesRead) *bytesRead = 0; /* Do this before anything else */
1790 if (!bytesToRead) return TRUE;
1792 unix_handle = FILE_GetUnixHandleType( hFile, GENERIC_READ, &type, &flags );
1794 if (flags & FD_FLAG_OVERLAPPED)
1796 if (unix_handle == -1) return FALSE;
1797 if ( (overlapped==NULL) || NtResetEvent( overlapped->hEvent, NULL ) )
1799 TRACE("Overlapped not specified or invalid event flag\n");
1801 SetLastError(ERROR_INVALID_PARAMETER);
1806 overlapped->InternalHigh = 0;
1808 if(!FILE_ReadFileEx(hFile, buffer, bytesToRead, overlapped, NULL, overlapped->hEvent))
1811 if ( !GetOverlappedResult (hFile, overlapped, bytesRead, FALSE) )
1813 if ( GetLastError() == ERROR_IO_INCOMPLETE )
1814 SetLastError ( ERROR_IO_PENDING );
1820 if (flags & FD_FLAG_TIMEOUT)
1823 return FILE_TimeoutRead(hFile, buffer, bytesToRead, bytesRead);
1828 return SMB_ReadFile(hFile, buffer, bytesToRead, bytesRead, NULL);
1830 case FD_TYPE_CONSOLE:
1831 return FILE_ReadConsole(hFile, buffer, bytesToRead, bytesRead, NULL);
1833 case FD_TYPE_DEFAULT:
1834 /* normal unix files */
1835 if (unix_handle == -1) return FALSE;
1838 DWORD highOffset = overlapped->OffsetHigh;
1839 if ( (INVALID_SET_FILE_POINTER == SetFilePointer(hFile, overlapped->Offset,
1840 &highOffset, FILE_BEGIN)) &&
1841 (GetLastError() != NO_ERROR) )
1850 if (unix_handle == -1)
1856 off_t offset = OVERLAPPED_OFFSET(overlapped);
1857 if(lseek(unix_handle, offset, SEEK_SET) == -1)
1860 SetLastError(ERROR_INVALID_PARAMETER);
1865 /* code for synchronous reads */
1866 while ((result = read( unix_handle, buffer, bytesToRead )) == -1)
1868 if ((errno == EAGAIN) || (errno == EINTR)) continue;
1869 if ((errno == EFAULT) && !IsBadWritePtr( buffer, bytesToRead )) continue;
1873 close( unix_handle );
1874 if (result == -1) return FALSE;
1875 if (bytesRead) *bytesRead = result;
1880 /***********************************************************************
1881 * FILE_AsyncWriteService (INTERNAL)
1883 * This function is called while the client is waiting on the
1884 * server, so we can't make any server calls here.
1886 static void FILE_AsyncWriteService(struct async_private *ovp)
1888 async_fileio *fileio = (async_fileio *) ovp;
1889 LPOVERLAPPED lpOverlapped = fileio->lpOverlapped;
1891 int already = lpOverlapped->InternalHigh;
1893 TRACE("(%p %p)\n",lpOverlapped,fileio->buffer);
1895 /* write some data (non-blocking) */
1897 if ( fileio->fd_type == FD_TYPE_SOCKET )
1898 result = write(ovp->fd, &fileio->buffer[already], fileio->count - already);
1901 result = pwrite(ovp->fd, &fileio->buffer[already], fileio->count - already,
1902 OVERLAPPED_OFFSET (lpOverlapped) + already);
1903 if ((result < 0) && (errno == ESPIPE))
1904 result = write(ovp->fd, &fileio->buffer[already], fileio->count - already);
1907 if ( (result<0) && ((errno == EAGAIN) || (errno == EINTR)))
1913 /* check to see if the transfer is complete */
1916 r = FILE_GetNtStatus ();
1920 lpOverlapped->InternalHigh += result;
1922 TRACE("wrote %d more bytes %ld/%d so far\n",result,lpOverlapped->InternalHigh,fileio->count);
1924 if(lpOverlapped->InternalHigh < fileio->count)
1930 lpOverlapped->Internal = r;
1933 /***********************************************************************
1936 static BOOL FILE_WriteFileEx(HANDLE hFile, LPCVOID buffer, DWORD bytesToWrite,
1937 LPOVERLAPPED overlapped,
1938 LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine,
1946 TRACE("file %d to buf %p num %ld %p func %p handle %d\n",
1947 hFile, buffer, bytesToWrite, overlapped, lpCompletionRoutine, hEvent);
1949 if (overlapped == NULL)
1951 SetLastError(ERROR_INVALID_PARAMETER);
1955 fd = FILE_GetUnixHandleType ( hFile, GENERIC_WRITE, &type, &flags );
1958 TRACE( "Couldn't get FD\n" );
1962 ovp = (async_fileio*) HeapAlloc(GetProcessHeap(), 0, sizeof (async_fileio));
1965 TRACE("HeapAlloc Failed\n");
1966 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1970 ovp->async.ops = ( lpCompletionRoutine ? &fileio_async_ops : &fileio_nocomp_async_ops );
1971 ovp->async.handle = hFile;
1973 ovp->async.type = ASYNC_TYPE_WRITE;
1974 ovp->async.func = FILE_AsyncWriteService;
1975 ovp->lpOverlapped = overlapped;
1976 ovp->async.event = hEvent;
1977 ovp->buffer = (LPVOID) buffer;
1978 ovp->count = bytesToWrite;
1979 ovp->completion_func = lpCompletionRoutine;
1980 ovp->fd_type = type;
1982 return !register_new_async (&ovp->async);
1989 /***********************************************************************
1990 * WriteFileEx (KERNEL32.@)
1992 BOOL WINAPI WriteFileEx(HANDLE hFile, LPCVOID buffer, DWORD bytesToWrite,
1993 LPOVERLAPPED overlapped,
1994 LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine)
1996 overlapped->InternalHigh = 0;
1998 return FILE_WriteFileEx(hFile, buffer, bytesToWrite, overlapped, lpCompletionRoutine, INVALID_HANDLE_VALUE);
2001 /***********************************************************************
2002 * WriteFile (KERNEL32.@)
2004 BOOL WINAPI WriteFile( HANDLE hFile, LPCVOID buffer, DWORD bytesToWrite,
2005 LPDWORD bytesWritten, LPOVERLAPPED overlapped )
2007 int unix_handle, result, flags;
2010 TRACE("%d %p %ld %p %p\n", hFile, buffer, bytesToWrite,
2011 bytesWritten, overlapped );
2013 if (bytesWritten) *bytesWritten = 0; /* Do this before anything else */
2014 if (!bytesToWrite) return TRUE;
2016 unix_handle = FILE_GetUnixHandleType( hFile, GENERIC_WRITE, &type, &flags );
2018 if (flags & FD_FLAG_OVERLAPPED)
2020 if (unix_handle == -1) return FALSE;
2021 if ( (overlapped==NULL) || NtResetEvent( overlapped->hEvent, NULL ) )
2023 TRACE("Overlapped not specified or invalid event flag\n");
2025 SetLastError(ERROR_INVALID_PARAMETER);
2030 overlapped->InternalHigh = 0;
2032 if(!FILE_WriteFileEx(hFile, buffer, bytesToWrite, overlapped, NULL, overlapped->hEvent))
2035 if ( !GetOverlappedResult (hFile, overlapped, bytesWritten, FALSE) )
2037 if ( GetLastError() == ERROR_IO_INCOMPLETE )
2038 SetLastError ( ERROR_IO_PENDING );
2047 case FD_TYPE_CONSOLE:
2048 TRACE("%d %s %ld %p %p\n", hFile, debugstr_an(buffer, bytesToWrite), bytesToWrite,
2049 bytesWritten, overlapped );
2050 return FILE_WriteConsole(hFile, buffer, bytesToWrite, bytesWritten, NULL);
2052 case FD_TYPE_DEFAULT:
2053 if (unix_handle == -1) return FALSE;
2057 DWORD highOffset = overlapped->OffsetHigh;
2058 if ( (INVALID_SET_FILE_POINTER == SetFilePointer(hFile, overlapped->Offset,
2059 &highOffset, FILE_BEGIN)) &&
2060 (GetLastError() != NO_ERROR) )
2069 if (unix_handle == -1)
2074 SetLastError(ERROR_INVALID_PARAMETER);
2082 off_t offset = OVERLAPPED_OFFSET(overlapped);
2083 if(lseek(unix_handle, offset, SEEK_SET) == -1)
2086 SetLastError(ERROR_INVALID_PARAMETER);
2091 /* synchronous file write */
2092 while ((result = write( unix_handle, buffer, bytesToWrite )) == -1)
2094 if ((errno == EAGAIN) || (errno == EINTR)) continue;
2095 if ((errno == EFAULT) && !IsBadReadPtr( buffer, bytesToWrite )) continue;
2096 if (errno == ENOSPC)
2097 SetLastError( ERROR_DISK_FULL );
2102 close( unix_handle );
2103 if (result == -1) return FALSE;
2104 if (bytesWritten) *bytesWritten = result;
2109 /***********************************************************************
2110 * _hread (KERNEL.349)
2112 LONG WINAPI WIN16_hread( HFILE16 hFile, SEGPTR buffer, LONG count )
2116 TRACE("%d %08lx %ld\n",
2117 hFile, (DWORD)buffer, count );
2119 /* Some programs pass a count larger than the allocated buffer */
2120 maxlen = GetSelectorLimit16( SELECTOROF(buffer) ) - OFFSETOF(buffer) + 1;
2121 if (count > maxlen) count = maxlen;
2122 return _lread((HFILE)DosFileHandleToWin32Handle(hFile), MapSL(buffer), count );
2126 /***********************************************************************
2127 * _lread (KERNEL.82)
2129 UINT16 WINAPI WIN16_lread( HFILE16 hFile, SEGPTR buffer, UINT16 count )
2131 return (UINT16)WIN16_hread( hFile, buffer, (LONG)count );
2135 /***********************************************************************
2136 * _lread (KERNEL32.@)
2138 UINT WINAPI _lread( HFILE handle, LPVOID buffer, UINT count )
2141 if (!ReadFile( (HANDLE)handle, buffer, count, &result, NULL )) return -1;
2146 /***********************************************************************
2147 * _lread16 (KERNEL.82)
2149 UINT16 WINAPI _lread16( HFILE16 hFile, LPVOID buffer, UINT16 count )
2151 return (UINT16)_lread((HFILE)DosFileHandleToWin32Handle(hFile), buffer, (LONG)count );
2155 /***********************************************************************
2156 * _lcreat (KERNEL.83)
2158 HFILE16 WINAPI _lcreat16( LPCSTR path, INT16 attr )
2160 return Win32HandleToDosFileHandle( (HANDLE)_lcreat( path, attr ) );
2164 /***********************************************************************
2165 * _lcreat (KERNEL32.@)
2167 HFILE WINAPI _lcreat( LPCSTR path, INT attr )
2169 /* Mask off all flags not explicitly allowed by the doc */
2170 attr &= FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM;
2171 TRACE("%s %02x\n", path, attr );
2172 return (HFILE)CreateFileA( path, GENERIC_READ | GENERIC_WRITE,
2173 FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
2174 CREATE_ALWAYS, attr, 0 );
2178 /***********************************************************************
2179 * SetFilePointer (KERNEL32.@)
2181 DWORD WINAPI SetFilePointer( HANDLE hFile, LONG distance, LONG *highword,
2184 DWORD ret = INVALID_SET_FILE_POINTER;
2186 TRACE("handle %d offset %ld high %ld origin %ld\n",
2187 hFile, distance, highword?*highword:0, method );
2189 SERVER_START_REQ( set_file_pointer )
2191 req->handle = hFile;
2192 req->low = distance;
2193 req->high = highword ? *highword : (distance >= 0) ? 0 : -1;
2194 /* FIXME: assumes 1:1 mapping between Windows and Unix seek constants */
2195 req->whence = method;
2197 if (!wine_server_call_err( req ))
2199 ret = reply->new_low;
2200 if (highword) *highword = reply->new_high;
2208 /***********************************************************************
2209 * _llseek (KERNEL.84)
2212 * Seeking before the start of the file should be allowed for _llseek16,
2213 * but cause subsequent I/O operations to fail (cf. interrupt list)
2216 LONG WINAPI _llseek16( HFILE16 hFile, LONG lOffset, INT16 nOrigin )
2218 return SetFilePointer( DosFileHandleToWin32Handle(hFile), lOffset, NULL, nOrigin );
2222 /***********************************************************************
2223 * _llseek (KERNEL32.@)
2225 LONG WINAPI _llseek( HFILE hFile, LONG lOffset, INT nOrigin )
2227 return SetFilePointer( (HANDLE)hFile, lOffset, NULL, nOrigin );
2231 /***********************************************************************
2232 * _lopen (KERNEL.85)
2234 HFILE16 WINAPI _lopen16( LPCSTR path, INT16 mode )
2236 return Win32HandleToDosFileHandle( (HANDLE)_lopen( path, mode ) );
2240 /***********************************************************************
2241 * _lopen (KERNEL32.@)
2243 HFILE WINAPI _lopen( LPCSTR path, INT mode )
2245 DWORD access, sharing;
2247 TRACE("('%s',%04x)\n", path, mode );
2248 FILE_ConvertOFMode( mode, &access, &sharing );
2249 return (HFILE)CreateFileA( path, access, sharing, NULL, OPEN_EXISTING, 0, 0 );
2253 /***********************************************************************
2254 * _lwrite (KERNEL.86)
2256 UINT16 WINAPI _lwrite16( HFILE16 hFile, LPCSTR buffer, UINT16 count )
2258 return (UINT16)_hwrite( (HFILE)DosFileHandleToWin32Handle(hFile), buffer, (LONG)count );
2261 /***********************************************************************
2262 * _lwrite (KERNEL32.@)
2264 UINT WINAPI _lwrite( HFILE hFile, LPCSTR buffer, UINT count )
2266 return (UINT)_hwrite( hFile, buffer, (LONG)count );
2270 /***********************************************************************
2271 * _hread16 (KERNEL.349)
2273 LONG WINAPI _hread16( HFILE16 hFile, LPVOID buffer, LONG count)
2275 return _lread( (HFILE)DosFileHandleToWin32Handle(hFile), buffer, count );
2279 /***********************************************************************
2280 * _hread (KERNEL32.@)
2282 LONG WINAPI _hread( HFILE hFile, LPVOID buffer, LONG count)
2284 return _lread( hFile, buffer, count );
2288 /***********************************************************************
2289 * _hwrite (KERNEL.350)
2291 LONG WINAPI _hwrite16( HFILE16 hFile, LPCSTR buffer, LONG count )
2293 return _hwrite( (HFILE)DosFileHandleToWin32Handle(hFile), buffer, count );
2297 /***********************************************************************
2298 * _hwrite (KERNEL32.@)
2300 * experimentation yields that _lwrite:
2301 * o truncates the file at the current position with
2303 * o returns 0 on a 0 length write
2304 * o works with console handles
2307 LONG WINAPI _hwrite( HFILE handle, LPCSTR buffer, LONG count )
2311 TRACE("%d %p %ld\n", handle, buffer, count );
2315 /* Expand or truncate at current position */
2316 if (!SetEndOfFile( (HANDLE)handle )) return HFILE_ERROR;
2319 if (!WriteFile( (HANDLE)handle, buffer, count, &result, NULL ))
2325 /***********************************************************************
2326 * SetHandleCount (KERNEL.199)
2328 UINT16 WINAPI SetHandleCount16( UINT16 count )
2330 return SetHandleCount( count );
2334 /*************************************************************************
2335 * SetHandleCount (KERNEL32.@)
2337 UINT WINAPI SetHandleCount( UINT count )
2339 return min( 256, count );
2343 /***********************************************************************
2344 * FlushFileBuffers (KERNEL32.@)
2346 BOOL WINAPI FlushFileBuffers( HANDLE hFile )
2349 SERVER_START_REQ( flush_file )
2351 req->handle = hFile;
2352 ret = !wine_server_call_err( req );
2359 /**************************************************************************
2360 * SetEndOfFile (KERNEL32.@)
2362 BOOL WINAPI SetEndOfFile( HANDLE hFile )
2365 SERVER_START_REQ( truncate_file )
2367 req->handle = hFile;
2368 ret = !wine_server_call_err( req );
2375 /***********************************************************************
2376 * DeleteFile (KERNEL.146)
2378 BOOL16 WINAPI DeleteFile16( LPCSTR path )
2380 return DeleteFileA( path );
2384 /***********************************************************************
2385 * DeleteFileW (KERNEL32.@)
2387 BOOL WINAPI DeleteFileW( LPCWSTR path )
2389 DOS_FULL_NAME full_name;
2394 SetLastError(ERROR_INVALID_PARAMETER);
2397 TRACE("%s\n", debugstr_w(path) );
2401 ERR("Empty path passed\n");
2404 if (DOSFS_GetDevice( path ))
2406 WARN("cannot remove DOS device %s!\n", debugstr_w(path));
2407 SetLastError( ERROR_FILE_NOT_FOUND );
2411 if (!DOSFS_GetFullName( path, TRUE, &full_name )) return FALSE;
2413 /* check if we are allowed to delete the source */
2414 hFile = FILE_CreateFile( full_name.long_name, GENERIC_READ|GENERIC_WRITE, 0,
2415 NULL, OPEN_EXISTING, 0, 0, TRUE,
2416 GetDriveTypeW( full_name.short_name ) );
2417 if (!hFile) return FALSE;
2419 if (unlink( full_name.long_name ) == -1)
2430 /***********************************************************************
2431 * DeleteFileA (KERNEL32.@)
2433 BOOL WINAPI DeleteFileA( LPCSTR path )
2435 UNICODE_STRING pathW;
2440 SetLastError(ERROR_INVALID_PARAMETER);
2444 if (RtlCreateUnicodeStringFromAsciiz(&pathW, path))
2446 ret = DeleteFileW(pathW.Buffer);
2447 RtlFreeUnicodeString(&pathW);
2450 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
2455 /***********************************************************************
2456 * GetFileType (KERNEL32.@)
2458 DWORD WINAPI GetFileType( HANDLE hFile )
2460 DWORD ret = FILE_TYPE_UNKNOWN;
2461 SERVER_START_REQ( get_file_info )
2463 req->handle = hFile;
2464 if (!wine_server_call_err( req )) ret = reply->type;
2471 /* check if a file name is for an executable file (.exe or .com) */
2472 inline static BOOL is_executable( const char *name )
2474 int len = strlen(name);
2476 if (len < 4) return FALSE;
2477 return (!strcasecmp( name + len - 4, ".exe" ) ||
2478 !strcasecmp( name + len - 4, ".com" ));
2482 /***********************************************************************
2483 * FILE_AddBootRenameEntry
2485 * Adds an entry to the registry that is loaded when windows boots and
2486 * checks if there are some files to be removed or renamed/moved.
2487 * <fn1> has to be valid and <fn2> may be NULL. If both pointers are
2488 * non-NULL then the file is moved, otherwise it is deleted. The
2489 * entry of the registrykey is always appended with two zero
2490 * terminated strings. If <fn2> is NULL then the second entry is
2491 * simply a single 0-byte. Otherwise the second filename goes
2492 * there. The entries are prepended with \??\ before the path and the
2493 * second filename gets also a '!' as the first character if
2494 * MOVEFILE_REPLACE_EXISTING is set. After the final string another
2495 * 0-byte follows to indicate the end of the strings.
2497 * \??\D:\test\file1[0]
2498 * !\??\D:\test\file1_renamed[0]
2499 * \??\D:\Test|delete[0]
2500 * [0] <- file is to be deleted, second string empty
2501 * \??\D:\test\file2[0]
2502 * !\??\D:\test\file2_renamed[0]
2503 * [0] <- indicates end of strings
2506 * \??\D:\test\file1[0]
2507 * !\??\D:\test\file1_renamed[0]
2508 * \??\D:\Test|delete[0]
2509 * [0] <- file is to be deleted, second string empty
2510 * [0] <- indicates end of strings
2513 static BOOL FILE_AddBootRenameEntry( LPCWSTR fn1, LPCWSTR fn2, DWORD flags )
2515 static const WCHAR PreString[] = {'\\','?','?','\\',0};
2516 static const WCHAR ValueName[] = {'P','e','n','d','i','n','g',
2517 'F','i','l','e','R','e','n','a','m','e',
2518 'O','p','e','r','a','t','i','o','n','s',0};
2519 static const WCHAR SessionW[] = {'M','a','c','h','i','n','e','\\',
2520 'S','y','s','t','e','m','\\',
2521 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
2522 'C','o','n','t','r','o','l','\\',
2523 'S','e','s','s','i','o','n',' ','M','a','n','a','g','e','r',0};
2524 static const int info_size = FIELD_OFFSET( KEY_VALUE_PARTIAL_INFORMATION, Data );
2526 OBJECT_ATTRIBUTES attr;
2527 UNICODE_STRING nameW;
2528 KEY_VALUE_PARTIAL_INFORMATION *info;
2531 DWORD len0, len1, len2;
2533 BYTE *Buffer = NULL;
2536 attr.Length = sizeof(attr);
2537 attr.RootDirectory = 0;
2538 attr.ObjectName = &nameW;
2539 attr.Attributes = 0;
2540 attr.SecurityDescriptor = NULL;
2541 attr.SecurityQualityOfService = NULL;
2542 RtlInitUnicodeString( &nameW, SessionW );
2544 if (NtCreateKey( &Reboot, KEY_ALL_ACCESS, &attr, 0, NULL, 0, NULL ) != STATUS_SUCCESS)
2546 WARN("Error creating key for reboot managment [%s]\n",
2547 "SYSTEM\\CurrentControlSet\\Control\\Session Manager");
2551 len0 = strlenW(PreString);
2552 len1 = strlenW(fn1) + len0 + 1;
2555 len2 = strlenW(fn2) + len0 + 1;
2556 if (flags & MOVEFILE_REPLACE_EXISTING) len2++; /* Plus 1 because of the leading '!' */
2558 else len2 = 1; /* minimum is the 0 characters for the empty second string */
2560 /* convert characters to bytes */
2561 len0 *= sizeof(WCHAR);
2562 len1 *= sizeof(WCHAR);
2563 len2 *= sizeof(WCHAR);
2565 RtlInitUnicodeString( &nameW, ValueName );
2567 /* First we check if the key exists and if so how many bytes it already contains. */
2568 if (NtQueryValueKey( Reboot, &nameW, KeyValuePartialInformation,
2569 NULL, 0, &DataSize ) == STATUS_BUFFER_OVERFLOW)
2571 if (!(Buffer = HeapAlloc( GetProcessHeap(), 0, DataSize + len1 + len2 + sizeof(WCHAR) )))
2573 if (NtQueryValueKey( Reboot, &nameW, KeyValuePartialInformation,
2574 Buffer, DataSize, &DataSize )) goto Quit;
2575 info = (KEY_VALUE_PARTIAL_INFORMATION *)Buffer;
2576 if (info->Type != REG_MULTI_SZ) goto Quit;
2577 if (DataSize > sizeof(info)) DataSize -= sizeof(WCHAR); /* remove terminating null (will be added back later) */
2581 DataSize = info_size;
2582 if (!(Buffer = HeapAlloc( GetProcessHeap(), 0, DataSize + len1 + len2 + sizeof(WCHAR) )))
2586 p = (WCHAR *)(Buffer + DataSize);
2587 strcpyW( p, PreString );
2592 p = (WCHAR *)(Buffer + DataSize);
2593 if (flags & MOVEFILE_REPLACE_EXISTING)
2595 strcpyW( p, PreString );
2601 p = (WCHAR *)(Buffer + DataSize);
2603 DataSize += sizeof(WCHAR);
2606 /* add final null */
2607 p = (WCHAR *)(Buffer + DataSize);
2609 DataSize += sizeof(WCHAR);
2611 rc = !NtSetValueKey(Reboot, &nameW, 0, REG_MULTI_SZ, Buffer + info_size, DataSize - info_size);
2614 if (Reboot) NtClose(Reboot);
2615 if (Buffer) HeapFree( GetProcessHeap(), 0, Buffer );
2620 /**************************************************************************
2621 * MoveFileExW (KERNEL32.@)
2623 BOOL WINAPI MoveFileExW( LPCWSTR fn1, LPCWSTR fn2, DWORD flag )
2625 DOS_FULL_NAME full_name1, full_name2;
2627 DWORD attr = INVALID_FILE_ATTRIBUTES;
2629 TRACE("(%s,%s,%04lx)\n", debugstr_w(fn1), debugstr_w(fn2), flag);
2631 /* FIXME: <Gerhard W. Gruber>sparhawk@gmx.at
2632 In case of W9x and lesser this function should return 120 (ERROR_CALL_NOT_IMPLEMENTED)
2633 to be really compatible. Most programs wont have any problems though. In case
2634 you encounter one, this is what you should return here. I don't know what's up
2635 with NT 3.5. Is this function available there or not?
2636 Does anybody really care about 3.5? :)
2639 /* Filename1 has to be always set to a valid path. Filename2 may be NULL
2640 if the source file has to be deleted.
2643 SetLastError(ERROR_INVALID_PARAMETER);
2647 /* This function has to be run through in order to process the name properly.
2648 If the BOOTDELAY flag is set, the file doesn't need to exist though. At least
2649 that is the behaviour on NT 4.0. The operation accepts the filenames as
2650 they are given but it can't reply with a reasonable returncode. Success
2651 means in that case success for entering the values into the registry.
2653 if(!DOSFS_GetFullName( fn1, TRUE, &full_name1 ))
2655 if(!(flag & MOVEFILE_DELAY_UNTIL_REBOOT))
2659 if (fn2) /* !fn2 means delete fn1 */
2661 if (DOSFS_GetFullName( fn2, TRUE, &full_name2 ))
2663 if(!(flag & MOVEFILE_DELAY_UNTIL_REBOOT))
2665 /* target exists, check if we may overwrite */
2666 if (!(flag & MOVEFILE_REPLACE_EXISTING))
2668 SetLastError( ERROR_FILE_EXISTS );
2675 if (!DOSFS_GetFullName( fn2, FALSE, &full_name2 ))
2677 if(!(flag & MOVEFILE_DELAY_UNTIL_REBOOT))
2682 /* Source name and target path are valid */
2684 if (flag & MOVEFILE_DELAY_UNTIL_REBOOT)
2686 /* FIXME: (bon@elektron.ikp.physik.th-darmstadt.de 970706)
2687 Perhaps we should queue these command and execute it
2688 when exiting... What about using on_exit(2)
2690 FIXME("Please move existing file %s to file %s when Wine has finished\n",
2691 debugstr_w(fn1), debugstr_w(fn2));
2692 return FILE_AddBootRenameEntry( fn1, fn2, flag );
2695 attr = GetFileAttributesW( fn1 );
2696 if ( attr == INVALID_FILE_ATTRIBUTES ) return FALSE;
2698 /* check if we are allowed to rename the source */
2699 hFile = FILE_CreateFile( full_name1.long_name, 0, 0,
2700 NULL, OPEN_EXISTING, 0, 0, TRUE,
2701 GetDriveTypeW( full_name1.short_name ) );
2704 if (GetLastError() != ERROR_ACCESS_DENIED) return FALSE;
2705 if ( !(attr & FILE_ATTRIBUTE_DIRECTORY) ) return FALSE;
2706 /* if it's a directory we can continue */
2708 else CloseHandle(hFile);
2710 /* check, if we are allowed to delete the destination,
2711 ** (but the file not being there is fine) */
2712 hFile = FILE_CreateFile( full_name2.long_name, GENERIC_READ|GENERIC_WRITE, 0,
2713 NULL, OPEN_EXISTING, 0, 0, TRUE,
2714 GetDriveTypeW( full_name2.short_name ) );
2715 if(!hFile && GetLastError() != ERROR_FILE_NOT_FOUND) return FALSE;
2718 if (full_name1.drive != full_name2.drive)
2720 if (!(flag & MOVEFILE_COPY_ALLOWED))
2722 SetLastError( ERROR_NOT_SAME_DEVICE );
2725 else if ( attr & FILE_ATTRIBUTE_DIRECTORY )
2727 /* Strange, but that's what Windows returns */
2728 SetLastError ( ERROR_ACCESS_DENIED );
2732 if (rename( full_name1.long_name, full_name2.long_name ) == -1)
2733 /* Try copy/delete unless it's a directory. */
2734 /* FIXME: This does not handle the (unlikely) case that the two locations
2735 are on the same Wine drive, but on different Unix file systems. */
2737 if ( attr & FILE_ATTRIBUTE_DIRECTORY )
2744 if ( ! CopyFileW( fn1, fn2, !(flag & MOVEFILE_REPLACE_EXISTING) ))
2746 if ( ! DeleteFileW ( fn1 ) )
2750 if (is_executable( full_name1.long_name ) != is_executable( full_name2.long_name ))
2753 if (stat( full_name2.long_name, &fstat ) != -1)
2755 if (is_executable( full_name2.long_name ))
2756 /* set executable bit where read bit is set */
2757 fstat.st_mode |= (fstat.st_mode & 0444) >> 2;
2759 fstat.st_mode &= ~0111;
2760 chmod( full_name2.long_name, fstat.st_mode );
2765 else /* fn2 == NULL means delete source */
2767 if (flag & MOVEFILE_DELAY_UNTIL_REBOOT)
2769 if (flag & MOVEFILE_COPY_ALLOWED) {
2770 WARN("Illegal flag\n");
2771 SetLastError( ERROR_GEN_FAILURE );
2774 /* FIXME: (bon@elektron.ikp.physik.th-darmstadt.de 970706)
2775 Perhaps we should queue these command and execute it
2776 when exiting... What about using on_exit(2)
2778 FIXME("Please delete file %s when Wine has finished\n", debugstr_w(fn1));
2779 return FILE_AddBootRenameEntry( fn1, NULL, flag );
2782 if (unlink( full_name1.long_name ) == -1)
2787 return TRUE; /* successfully deleted */
2791 /**************************************************************************
2792 * MoveFileExA (KERNEL32.@)
2794 BOOL WINAPI MoveFileExA( LPCSTR fn1, LPCSTR fn2, DWORD flag )
2796 UNICODE_STRING fn1W, fn2W;
2801 SetLastError(ERROR_INVALID_PARAMETER);
2805 RtlCreateUnicodeStringFromAsciiz(&fn1W, fn1);
2806 if (fn2) RtlCreateUnicodeStringFromAsciiz(&fn2W, fn2);
2807 else fn2W.Buffer = NULL;
2809 ret = MoveFileExW( fn1W.Buffer, fn2W.Buffer, flag );
2811 RtlFreeUnicodeString(&fn1W);
2812 RtlFreeUnicodeString(&fn2W);
2817 /**************************************************************************
2818 * MoveFileW (KERNEL32.@)
2820 * Move file or directory
2822 BOOL WINAPI MoveFileW( LPCWSTR fn1, LPCWSTR fn2 )
2824 DOS_FULL_NAME full_name1, full_name2;
2829 SetLastError(ERROR_INVALID_PARAMETER);
2833 TRACE("(%s,%s)\n", debugstr_w(fn1), debugstr_w(fn2) );
2835 if (!DOSFS_GetFullName( fn1, TRUE, &full_name1 )) return FALSE;
2836 if (DOSFS_GetFullName( fn2, TRUE, &full_name2 )) {
2837 /* The new name must not already exist */
2838 SetLastError(ERROR_ALREADY_EXISTS);
2841 if (!DOSFS_GetFullName( fn2, FALSE, &full_name2 )) return FALSE;
2843 if (full_name1.drive == full_name2.drive) /* move */
2844 return MoveFileExW( fn1, fn2, MOVEFILE_COPY_ALLOWED );
2847 if (stat( full_name1.long_name, &fstat ))
2849 WARN("Invalid source file %s\n",
2850 full_name1.long_name);
2854 if (S_ISDIR(fstat.st_mode)) {
2855 /* No Move for directories across file systems */
2856 /* FIXME: Use right error code */
2857 SetLastError( ERROR_GEN_FAILURE );
2860 return CopyFileW(fn1, fn2, TRUE); /*fail, if exist */
2864 /**************************************************************************
2865 * MoveFileA (KERNEL32.@)
2867 BOOL WINAPI MoveFileA( LPCSTR fn1, LPCSTR fn2 )
2869 UNICODE_STRING fn1W, fn2W;
2874 SetLastError(ERROR_INVALID_PARAMETER);
2878 RtlCreateUnicodeStringFromAsciiz(&fn1W, fn1);
2879 RtlCreateUnicodeStringFromAsciiz(&fn2W, fn2);
2881 ret = MoveFileW( fn1W.Buffer, fn2W.Buffer );
2883 RtlFreeUnicodeString(&fn1W);
2884 RtlFreeUnicodeString(&fn2W);
2889 /**************************************************************************
2890 * CopyFileW (KERNEL32.@)
2892 BOOL WINAPI CopyFileW( LPCWSTR source, LPCWSTR dest, BOOL fail_if_exists )
2895 BY_HANDLE_FILE_INFORMATION info;
2900 if (!source || !dest)
2902 SetLastError(ERROR_INVALID_PARAMETER);
2906 TRACE("%s -> %s\n", debugstr_w(source), debugstr_w(dest));
2908 if ((h1 = CreateFileW(source, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE,
2909 NULL, OPEN_EXISTING, 0, 0)) == INVALID_HANDLE_VALUE)
2911 WARN("Unable to open source %s\n", debugstr_w(source));
2915 if (!GetFileInformationByHandle( h1, &info ))
2917 WARN("GetFileInformationByHandle returned error for %s\n", debugstr_w(source));
2922 if ((h2 = CreateFileW( dest, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
2923 fail_if_exists ? CREATE_NEW : CREATE_ALWAYS,
2924 info.dwFileAttributes, h1 )) == INVALID_HANDLE_VALUE)
2926 WARN("Unable to open dest %s\n", debugstr_w(dest));
2931 while (ReadFile( h1, buffer, sizeof(buffer), &count, NULL ) && count)
2937 if (!WriteFile( h2, p, count, &res, NULL ) || !res) goto done;
2950 /**************************************************************************
2951 * CopyFileA (KERNEL32.@)
2953 BOOL WINAPI CopyFileA( LPCSTR source, LPCSTR dest, BOOL fail_if_exists)
2955 UNICODE_STRING sourceW, destW;
2958 if (!source || !dest)
2960 SetLastError(ERROR_INVALID_PARAMETER);
2964 RtlCreateUnicodeStringFromAsciiz(&sourceW, source);
2965 RtlCreateUnicodeStringFromAsciiz(&destW, dest);
2967 ret = CopyFileW(sourceW.Buffer, destW.Buffer, fail_if_exists);
2969 RtlFreeUnicodeString(&sourceW);
2970 RtlFreeUnicodeString(&destW);
2975 /**************************************************************************
2976 * CopyFileExW (KERNEL32.@)
2978 * This implementation ignores most of the extra parameters passed-in into
2979 * the "ex" version of the method and calls the CopyFile method.
2980 * It will have to be fixed eventually.
2982 BOOL WINAPI CopyFileExW(LPCWSTR sourceFilename, LPCWSTR destFilename,
2983 LPPROGRESS_ROUTINE progressRoutine, LPVOID appData,
2984 LPBOOL cancelFlagPointer, DWORD copyFlags)
2987 * Interpret the only flag that CopyFile can interpret.
2989 return CopyFileW(sourceFilename, destFilename, (copyFlags & COPY_FILE_FAIL_IF_EXISTS) != 0);
2992 /**************************************************************************
2993 * CopyFileExA (KERNEL32.@)
2995 BOOL WINAPI CopyFileExA(LPCSTR sourceFilename, LPCSTR destFilename,
2996 LPPROGRESS_ROUTINE progressRoutine, LPVOID appData,
2997 LPBOOL cancelFlagPointer, DWORD copyFlags)
2999 UNICODE_STRING sourceW, destW;
3002 if (!sourceFilename || !destFilename)
3004 SetLastError(ERROR_INVALID_PARAMETER);
3008 RtlCreateUnicodeStringFromAsciiz(&sourceW, sourceFilename);
3009 RtlCreateUnicodeStringFromAsciiz(&destW, destFilename);
3011 ret = CopyFileExW(sourceW.Buffer, destW.Buffer, progressRoutine, appData,
3012 cancelFlagPointer, copyFlags);
3014 RtlFreeUnicodeString(&sourceW);
3015 RtlFreeUnicodeString(&destW);
3020 /***********************************************************************
3021 * SetFileTime (KERNEL32.@)
3023 BOOL WINAPI SetFileTime( HANDLE hFile,
3024 const FILETIME *lpCreationTime,
3025 const FILETIME *lpLastAccessTime,
3026 const FILETIME *lpLastWriteTime )
3029 SERVER_START_REQ( set_file_time )
3031 req->handle = hFile;
3032 if (lpLastAccessTime)
3033 RtlTimeToSecondsSince1970( (PLARGE_INTEGER) lpLastAccessTime, (DWORD *)&req->access_time );
3035 req->access_time = 0; /* FIXME */
3036 if (lpLastWriteTime)
3037 RtlTimeToSecondsSince1970( (PLARGE_INTEGER) lpLastWriteTime, (DWORD *)&req->write_time );
3039 req->write_time = 0; /* FIXME */
3040 ret = !wine_server_call_err( req );
3047 /**************************************************************************
3048 * LockFile (KERNEL32.@)
3050 BOOL WINAPI LockFile( HANDLE hFile, DWORD dwFileOffsetLow, DWORD dwFileOffsetHigh,
3051 DWORD nNumberOfBytesToLockLow, DWORD nNumberOfBytesToLockHigh )
3055 FIXME("not implemented in server\n");
3057 SERVER_START_REQ( lock_file )
3059 req->handle = hFile;
3060 req->offset_low = dwFileOffsetLow;
3061 req->offset_high = dwFileOffsetHigh;
3062 req->count_low = nNumberOfBytesToLockLow;
3063 req->count_high = nNumberOfBytesToLockHigh;
3064 ret = !wine_server_call_err( req );
3070 /**************************************************************************
3071 * LockFileEx [KERNEL32.@]
3073 * Locks a byte range within an open file for shared or exclusive access.
3080 * Per Microsoft docs, the third parameter (reserved) must be set to 0.
3082 BOOL WINAPI LockFileEx( HANDLE hFile, DWORD flags, DWORD reserved,
3083 DWORD nNumberOfBytesToLockLow, DWORD nNumberOfBytesToLockHigh,
3084 LPOVERLAPPED pOverlapped )
3086 FIXME("hFile=%d,flags=%ld,reserved=%ld,lowbytes=%ld,highbytes=%ld,overlapped=%p: stub.\n",
3087 hFile, flags, reserved, nNumberOfBytesToLockLow, nNumberOfBytesToLockHigh,
3090 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
3093 ERR("reserved == %ld: Supposed to be 0??\n", reserved);
3094 SetLastError(ERROR_INVALID_PARAMETER);
3101 /**************************************************************************
3102 * UnlockFile (KERNEL32.@)
3104 BOOL WINAPI UnlockFile( HANDLE hFile, DWORD dwFileOffsetLow, DWORD dwFileOffsetHigh,
3105 DWORD nNumberOfBytesToUnlockLow, DWORD nNumberOfBytesToUnlockHigh )
3109 FIXME("not implemented in server\n");
3111 SERVER_START_REQ( unlock_file )
3113 req->handle = hFile;
3114 req->offset_low = dwFileOffsetLow;
3115 req->offset_high = dwFileOffsetHigh;
3116 req->count_low = nNumberOfBytesToUnlockLow;
3117 req->count_high = nNumberOfBytesToUnlockHigh;
3118 ret = !wine_server_call_err( req );
3125 /**************************************************************************
3126 * UnlockFileEx (KERNEL32.@)
3128 BOOL WINAPI UnlockFileEx(
3131 DWORD nNumberOfBytesToUnlockLow,
3132 DWORD nNumberOfBytesToUnlockHigh,
3133 LPOVERLAPPED lpOverlapped
3136 FIXME("hFile=%d,reserved=%ld,lowbytes=%ld,highbytes=%ld,overlapped=%p: stub.\n",
3137 hFile, dwReserved, nNumberOfBytesToUnlockLow, nNumberOfBytesToUnlockHigh,
3139 if (dwReserved == 0)
3140 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
3143 ERR("reserved == %ld: Supposed to be 0??\n", dwReserved);
3144 SetLastError(ERROR_INVALID_PARAMETER);
3153 struct DOS_FILE_LOCK {
3154 struct DOS_FILE_LOCK * next;
3158 FILE_OBJECT * dos_file;
3159 /* char * unix_name;*/
3162 typedef struct DOS_FILE_LOCK DOS_FILE_LOCK;
3164 static DOS_FILE_LOCK *locks = NULL;
3165 static void DOS_RemoveFileLocks(FILE_OBJECT *file);
3168 /* Locks need to be mirrored because unix file locking is based
3169 * on the pid. Inside of wine there can be multiple WINE processes
3170 * that share the same unix pid.
3171 * Read's and writes should check these locks also - not sure
3172 * how critical that is at this point (FIXME).
3175 static BOOL DOS_AddLock(FILE_OBJECT *file, struct flock *f)
3177 DOS_FILE_LOCK *curr;
3180 processId = GetCurrentProcessId();
3182 /* check if lock overlaps a current lock for the same file */
3184 for (curr = locks; curr; curr = curr->next) {
3185 if (strcmp(curr->unix_name, file->unix_name) == 0) {
3186 if ((f->l_start == curr->base) && (f->l_len == curr->len))
3187 return TRUE;/* region is identic */
3188 if ((f->l_start < (curr->base + curr->len)) &&
3189 ((f->l_start + f->l_len) > curr->base)) {
3190 /* region overlaps */
3197 curr = HeapAlloc( GetProcessHeap(), 0, sizeof(DOS_FILE_LOCK) );
3198 curr->processId = GetCurrentProcessId();
3199 curr->base = f->l_start;
3200 curr->len = f->l_len;
3201 /* curr->unix_name = HEAP_strdupA( GetProcessHeap(), 0, file->unix_name);*/
3203 curr->dos_file = file;
3208 static void DOS_RemoveFileLocks(FILE_OBJECT *file)
3211 DOS_FILE_LOCK **curr;
3214 processId = GetCurrentProcessId();
3217 if ((*curr)->dos_file == file) {
3219 *curr = (*curr)->next;
3220 /* HeapFree( GetProcessHeap(), 0, rem->unix_name );*/
3221 HeapFree( GetProcessHeap(), 0, rem );
3224 curr = &(*curr)->next;
3228 static BOOL DOS_RemoveLock(FILE_OBJECT *file, struct flock *f)
3231 DOS_FILE_LOCK **curr;
3234 processId = GetCurrentProcessId();
3235 for (curr = &locks; *curr; curr = &(*curr)->next) {
3236 if ((*curr)->processId == processId &&
3237 (*curr)->dos_file == file &&
3238 (*curr)->base == f->l_start &&
3239 (*curr)->len == f->l_len) {
3240 /* this is the same lock */
3242 *curr = (*curr)->next;
3243 /* HeapFree( GetProcessHeap(), 0, rem->unix_name );*/
3244 HeapFree( GetProcessHeap(), 0, rem );
3248 /* no matching lock found */
3253 /**************************************************************************
3254 * LockFile (KERNEL32.@)
3256 BOOL WINAPI LockFile(
3257 HANDLE hFile,DWORD dwFileOffsetLow,DWORD dwFileOffsetHigh,
3258 DWORD nNumberOfBytesToLockLow,DWORD nNumberOfBytesToLockHigh )
3263 TRACE("handle %d offsetlow=%ld offsethigh=%ld nbyteslow=%ld nbyteshigh=%ld\n",
3264 hFile, dwFileOffsetLow, dwFileOffsetHigh,
3265 nNumberOfBytesToLockLow, nNumberOfBytesToLockHigh);
3267 if (dwFileOffsetHigh || nNumberOfBytesToLockHigh) {
3268 FIXME("Unimplemented bytes > 32bits\n");
3272 f.l_start = dwFileOffsetLow;
3273 f.l_len = nNumberOfBytesToLockLow;
3274 f.l_whence = SEEK_SET;
3278 if (!(file = FILE_GetFile(hFile,0,NULL))) return FALSE;
3280 /* shadow locks internally */
3281 if (!DOS_AddLock(file, &f)) {
3282 SetLastError( ERROR_LOCK_VIOLATION );
3286 /* FIXME: Unix locking commented out for now, doesn't work with Excel */
3287 #ifdef USE_UNIX_LOCKS
3288 if (fcntl(file->unix_handle, F_SETLK, &f) == -1) {
3289 if (errno == EACCES || errno == EAGAIN) {
3290 SetLastError( ERROR_LOCK_VIOLATION );
3295 /* remove our internal copy of the lock */
3296 DOS_RemoveLock(file, &f);
3304 /**************************************************************************
3305 * UnlockFile (KERNEL32.@)
3307 BOOL WINAPI UnlockFile(
3308 HANDLE hFile,DWORD dwFileOffsetLow,DWORD dwFileOffsetHigh,
3309 DWORD nNumberOfBytesToUnlockLow,DWORD nNumberOfBytesToUnlockHigh )
3314 TRACE("handle %d offsetlow=%ld offsethigh=%ld nbyteslow=%ld nbyteshigh=%ld\n",
3315 hFile, dwFileOffsetLow, dwFileOffsetHigh,
3316 nNumberOfBytesToUnlockLow, nNumberOfBytesToUnlockHigh);
3318 if (dwFileOffsetHigh || nNumberOfBytesToUnlockHigh) {
3319 WARN("Unimplemented bytes > 32bits\n");
3323 f.l_start = dwFileOffsetLow;
3324 f.l_len = nNumberOfBytesToUnlockLow;
3325 f.l_whence = SEEK_SET;
3329 if (!(file = FILE_GetFile(hFile,0,NULL))) return FALSE;
3331 DOS_RemoveLock(file, &f); /* ok if fails - may be another wine */
3333 /* FIXME: Unix locking commented out for now, doesn't work with Excel */
3334 #ifdef USE_UNIX_LOCKS
3335 if (fcntl(file->unix_handle, F_SETLK, &f) == -1) {
3344 /**************************************************************************
3345 * GetFileAttributesExW (KERNEL32.@)
3347 BOOL WINAPI GetFileAttributesExW(
3348 LPCWSTR lpFileName, GET_FILEEX_INFO_LEVELS fInfoLevelId,
3349 LPVOID lpFileInformation)
3351 DOS_FULL_NAME full_name;
3352 BY_HANDLE_FILE_INFORMATION info;
3354 if (!lpFileName || !lpFileInformation)
3356 SetLastError(ERROR_INVALID_PARAMETER);
3360 if (fInfoLevelId == GetFileExInfoStandard) {
3361 LPWIN32_FILE_ATTRIBUTE_DATA lpFad =
3362 (LPWIN32_FILE_ATTRIBUTE_DATA) lpFileInformation;
3363 if (!DOSFS_GetFullName( lpFileName, TRUE, &full_name )) return FALSE;
3364 if (!FILE_Stat( full_name.long_name, &info )) return FALSE;
3366 lpFad->dwFileAttributes = info.dwFileAttributes;
3367 lpFad->ftCreationTime = info.ftCreationTime;
3368 lpFad->ftLastAccessTime = info.ftLastAccessTime;
3369 lpFad->ftLastWriteTime = info.ftLastWriteTime;
3370 lpFad->nFileSizeHigh = info.nFileSizeHigh;
3371 lpFad->nFileSizeLow = info.nFileSizeLow;
3374 FIXME("invalid info level %d!\n", fInfoLevelId);
3382 /**************************************************************************
3383 * GetFileAttributesExA (KERNEL32.@)
3385 BOOL WINAPI GetFileAttributesExA(
3386 LPCSTR filename, GET_FILEEX_INFO_LEVELS fInfoLevelId,
3387 LPVOID lpFileInformation)
3389 UNICODE_STRING filenameW;
3392 if (!filename || !lpFileInformation)
3394 SetLastError(ERROR_INVALID_PARAMETER);
3398 if (RtlCreateUnicodeStringFromAsciiz(&filenameW, filename))
3400 ret = GetFileAttributesExW(filenameW.Buffer, fInfoLevelId, lpFileInformation);
3401 RtlFreeUnicodeString(&filenameW);
3404 SetLastError(ERROR_NOT_ENOUGH_MEMORY);