Complete ICatInformation implementation.
[wine.git] / files / file.c
blob214fceadd8afe50ed30d66e2ad38940285bb6fd2
1 /*
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
21 * TODO:
22 * Fix the CopyFileEx methods to implement the "extended" functionality.
23 * Right now, they simply call the CopyFile method.
26 #include "config.h"
27 #include "wine/port.h"
29 #include <assert.h>
30 #include <ctype.h>
31 #include <errno.h>
32 #include <fcntl.h>
33 #include <stdlib.h>
34 #include <stdio.h>
35 #include <string.h>
36 #ifdef HAVE_SYS_ERRNO_H
37 #include <sys/errno.h>
38 #endif
39 #include <sys/types.h>
40 #include <sys/stat.h>
41 #ifdef HAVE_SYS_MMAN_H
42 #include <sys/mman.h>
43 #endif
44 #include <sys/time.h>
45 #include <sys/poll.h>
46 #include <time.h>
47 #include <unistd.h>
48 #include <utime.h>
50 #include "winerror.h"
51 #include "windef.h"
52 #include "winbase.h"
53 #include "wine/winbase16.h"
54 #include "wine/server.h"
56 #include "drive.h"
57 #include "file.h"
58 #include "async.h"
59 #include "heap.h"
60 #include "msdos.h"
61 #include "wincon.h"
63 #include "smb.h"
64 #include "wine/debug.h"
66 WINE_DEFAULT_DEBUG_CHANNEL(file);
68 #if defined(MAP_ANONYMOUS) && !defined(MAP_ANON)
69 #define MAP_ANON MAP_ANONYMOUS
70 #endif
72 /* Size of per-process table of DOS handles */
73 #define DOS_TABLE_SIZE 256
75 /* Macro to derive file offset from OVERLAPPED struct */
76 #define OVERLAPPED_OFFSET(overlapped) ((off_t) (overlapped)->Offset + ((off_t) (overlapped)->OffsetHigh << 32))
78 static HANDLE dos_handles[DOS_TABLE_SIZE];
80 mode_t FILE_umask;
82 extern HANDLE WINAPI FILE_SmbOpen(LPCSTR name);
84 /***********************************************************************
85 * Asynchronous file I/O *
87 static DWORD fileio_get_async_status (const async_private *ovp);
88 static DWORD fileio_get_async_count (const async_private *ovp);
89 static void fileio_set_async_status (async_private *ovp, const DWORD status);
90 static void CALLBACK fileio_call_completion_func (ULONG_PTR data);
91 static void fileio_async_cleanup (async_private *ovp);
93 static async_ops fileio_async_ops =
95 fileio_get_async_status, /* get_status */
96 fileio_set_async_status, /* set_status */
97 fileio_get_async_count, /* get_count */
98 fileio_call_completion_func, /* call_completion */
99 fileio_async_cleanup /* cleanup */
102 static async_ops fileio_nocomp_async_ops =
104 fileio_get_async_status, /* get_status */
105 fileio_set_async_status, /* set_status */
106 fileio_get_async_count, /* get_count */
107 NULL, /* call_completion */
108 fileio_async_cleanup /* cleanup */
111 typedef struct async_fileio
113 struct async_private async;
114 LPOVERLAPPED lpOverlapped;
115 LPOVERLAPPED_COMPLETION_ROUTINE completion_func;
116 char *buffer;
117 int count;
118 enum fd_type fd_type;
119 } async_fileio;
121 static DWORD fileio_get_async_status (const struct async_private *ovp)
123 return ((async_fileio*) ovp)->lpOverlapped->Internal;
126 static void fileio_set_async_status (async_private *ovp, const DWORD status)
128 ((async_fileio*) ovp)->lpOverlapped->Internal = status;
131 static DWORD fileio_get_async_count (const struct async_private *ovp)
133 async_fileio *fileio = (async_fileio*) ovp;
134 DWORD ret = fileio->count - fileio->lpOverlapped->InternalHigh;
135 return (ret < 0 ? 0 : ret);
138 static void CALLBACK fileio_call_completion_func (ULONG_PTR data)
140 async_fileio *ovp = (async_fileio*) data;
141 TRACE ("data: %p\n", ovp);
143 ovp->completion_func( ovp->lpOverlapped->Internal,
144 ovp->lpOverlapped->InternalHigh,
145 ovp->lpOverlapped );
147 fileio_async_cleanup ( &ovp->async );
150 static void fileio_async_cleanup ( struct async_private *ovp )
152 HeapFree ( GetProcessHeap(), 0, ovp );
155 /***********************************************************************
156 * FILE_ConvertOFMode
158 * Convert OF_* mode into flags for CreateFile.
160 static void FILE_ConvertOFMode( INT mode, DWORD *access, DWORD *sharing )
162 switch(mode & 0x03)
164 case OF_READ: *access = GENERIC_READ; break;
165 case OF_WRITE: *access = GENERIC_WRITE; break;
166 case OF_READWRITE: *access = GENERIC_READ | GENERIC_WRITE; break;
167 default: *access = 0; break;
169 switch(mode & 0x70)
171 case OF_SHARE_EXCLUSIVE: *sharing = 0; break;
172 case OF_SHARE_DENY_WRITE: *sharing = FILE_SHARE_READ; break;
173 case OF_SHARE_DENY_READ: *sharing = FILE_SHARE_WRITE; break;
174 case OF_SHARE_DENY_NONE:
175 case OF_SHARE_COMPAT:
176 default: *sharing = FILE_SHARE_READ | FILE_SHARE_WRITE; break;
181 /***********************************************************************
182 * FILE_strcasecmp
184 * locale-independent case conversion for file I/O
186 int FILE_strcasecmp( const char *str1, const char *str2 )
188 for (;;)
190 int ret = FILE_toupper(*str1) - FILE_toupper(*str2);
191 if (ret || !*str1) return ret;
192 str1++;
193 str2++;
198 /***********************************************************************
199 * FILE_strncasecmp
201 * locale-independent case conversion for file I/O
203 int FILE_strncasecmp( const char *str1, const char *str2, int len )
205 int ret = 0;
206 for ( ; len > 0; len--, str1++, str2++)
207 if ((ret = FILE_toupper(*str1) - FILE_toupper(*str2)) || !*str1) break;
208 return ret;
212 /***********************************************************************
213 * FILE_GetNtStatus(void)
215 * Retrieve the Nt Status code from errno.
216 * Try to be consistent with FILE_SetDosError().
218 DWORD FILE_GetNtStatus(void)
220 int err = errno;
221 DWORD nt;
222 TRACE ( "errno = %d\n", errno );
223 switch ( err )
225 case EAGAIN: nt = STATUS_SHARING_VIOLATION; break;
226 case EBADF: nt = STATUS_INVALID_HANDLE; break;
227 case ENOSPC: nt = STATUS_DISK_FULL; break;
228 case EPERM:
229 case EROFS:
230 case EACCES: nt = STATUS_ACCESS_DENIED; break;
231 case ENOENT: nt = STATUS_SHARING_VIOLATION; break;
232 case EISDIR: nt = STATUS_FILE_IS_A_DIRECTORY; break;
233 case EMFILE:
234 case ENFILE: nt = STATUS_NO_MORE_FILES; break;
235 case EINVAL:
236 case ENOTEMPTY: nt = STATUS_DIRECTORY_NOT_EMPTY; break;
237 case EPIPE: nt = STATUS_PIPE_BROKEN; break;
238 case ENOEXEC: /* ?? */
239 case ESPIPE: /* ?? */
240 case EEXIST: /* ?? */
241 default:
242 FIXME ( "Converting errno %d to STATUS_UNSUCCESSFUL\n", err );
243 nt = STATUS_UNSUCCESSFUL;
245 return nt;
248 /***********************************************************************
249 * FILE_SetDosError
251 * Set the DOS error code from errno.
253 void FILE_SetDosError(void)
255 int save_errno = errno; /* errno gets overwritten by printf */
257 TRACE("errno = %d %s\n", errno, strerror(errno));
258 switch (save_errno)
260 case EAGAIN:
261 SetLastError( ERROR_SHARING_VIOLATION );
262 break;
263 case EBADF:
264 SetLastError( ERROR_INVALID_HANDLE );
265 break;
266 case ENOSPC:
267 SetLastError( ERROR_HANDLE_DISK_FULL );
268 break;
269 case EACCES:
270 case EPERM:
271 case EROFS:
272 SetLastError( ERROR_ACCESS_DENIED );
273 break;
274 case EBUSY:
275 SetLastError( ERROR_LOCK_VIOLATION );
276 break;
277 case ENOENT:
278 SetLastError( ERROR_FILE_NOT_FOUND );
279 break;
280 case EISDIR:
281 SetLastError( ERROR_CANNOT_MAKE );
282 break;
283 case ENFILE:
284 case EMFILE:
285 SetLastError( ERROR_NO_MORE_FILES );
286 break;
287 case EEXIST:
288 SetLastError( ERROR_FILE_EXISTS );
289 break;
290 case EINVAL:
291 case ESPIPE:
292 SetLastError( ERROR_SEEK );
293 break;
294 case ENOTEMPTY:
295 SetLastError( ERROR_DIR_NOT_EMPTY );
296 break;
297 case ENOEXEC:
298 SetLastError( ERROR_BAD_FORMAT );
299 break;
300 default:
301 WARN("unknown file error: %s\n", strerror(save_errno) );
302 SetLastError( ERROR_GEN_FAILURE );
303 break;
305 errno = save_errno;
309 /***********************************************************************
310 * FILE_GetUnixHandleType
312 * Retrieve the Unix handle corresponding to a file handle.
313 * Returns -1 on failure.
315 static int FILE_GetUnixHandleType( HANDLE handle, DWORD access, enum fd_type *type, int *flags_ptr )
317 int ret, flags, fd = -1;
319 ret = wine_server_handle_to_fd( handle, access, &fd, type, &flags );
320 if (flags_ptr) *flags_ptr = flags;
321 if (ret) SetLastError( RtlNtStatusToDosError(ret) );
322 else if (((access & GENERIC_READ) && (flags & FD_FLAG_RECV_SHUTDOWN)) ||
323 ((access & GENERIC_WRITE) && (flags & FD_FLAG_SEND_SHUTDOWN)))
325 close (fd);
326 SetLastError ( ERROR_PIPE_NOT_CONNECTED );
327 return -1;
329 return fd;
332 /***********************************************************************
333 * FILE_GetUnixHandle
335 * Retrieve the Unix handle corresponding to a file handle.
336 * Returns -1 on failure.
338 int FILE_GetUnixHandle( HANDLE handle, DWORD access )
340 return FILE_GetUnixHandleType( handle, access, NULL, NULL );
343 /*************************************************************************
344 * FILE_OpenConsole
346 * Open a handle to the current process console.
347 * Returns 0 on failure.
349 static HANDLE FILE_OpenConsole( BOOL output, DWORD access, DWORD sharing, LPSECURITY_ATTRIBUTES sa )
351 HANDLE ret;
353 SERVER_START_REQ( open_console )
355 req->from = output;
356 req->access = access;
357 req->share = sharing;
358 req->inherit = (sa && (sa->nLength>=sizeof(*sa)) && sa->bInheritHandle);
359 SetLastError(0);
360 wine_server_call_err( req );
361 ret = reply->handle;
363 SERVER_END_REQ;
364 return ret;
368 /***********************************************************************
369 * FILE_CreateFile
371 * Implementation of CreateFile. Takes a Unix path name.
372 * Returns 0 on failure.
374 HANDLE FILE_CreateFile( LPCSTR filename, DWORD access, DWORD sharing,
375 LPSECURITY_ATTRIBUTES sa, DWORD creation,
376 DWORD attributes, HANDLE template, BOOL fail_read_only,
377 UINT drive_type )
379 unsigned int err;
380 HANDLE ret;
382 for (;;)
384 SERVER_START_REQ( create_file )
386 req->access = access;
387 req->inherit = (sa && (sa->nLength>=sizeof(*sa)) && sa->bInheritHandle);
388 req->sharing = sharing;
389 req->create = creation;
390 req->attrs = attributes;
391 req->drive_type = drive_type;
392 wine_server_add_data( req, filename, strlen(filename) );
393 SetLastError(0);
394 err = wine_server_call( req );
395 ret = reply->handle;
397 SERVER_END_REQ;
399 /* If write access failed, retry without GENERIC_WRITE */
401 if (!ret && !fail_read_only && (access & GENERIC_WRITE))
403 if ((err == STATUS_MEDIA_WRITE_PROTECTED) || (err == STATUS_ACCESS_DENIED))
405 TRACE("Write access failed for file '%s', trying without "
406 "write access\n", filename);
407 access &= ~GENERIC_WRITE;
408 continue;
412 if (err) SetLastError( RtlNtStatusToDosError(err) );
414 if (!ret) WARN("Unable to create file '%s' (GLE %ld)\n", filename, GetLastError());
415 return ret;
420 /***********************************************************************
421 * FILE_CreateDevice
423 * Same as FILE_CreateFile but for a device
424 * Returns 0 on failure.
426 HANDLE FILE_CreateDevice( int client_id, DWORD access, LPSECURITY_ATTRIBUTES sa )
428 HANDLE ret;
429 SERVER_START_REQ( create_device )
431 req->access = access;
432 req->inherit = (sa && (sa->nLength>=sizeof(*sa)) && sa->bInheritHandle);
433 req->id = client_id;
434 SetLastError(0);
435 wine_server_call_err( req );
436 ret = reply->handle;
438 SERVER_END_REQ;
439 return ret;
442 static HANDLE FILE_OpenPipe(LPCSTR name, DWORD access)
444 WCHAR buffer[MAX_PATH];
445 HANDLE ret;
446 DWORD len = 0;
448 if (name && !(len = MultiByteToWideChar( CP_ACP, 0, name, strlen(name), buffer, MAX_PATH )))
450 SetLastError( ERROR_FILENAME_EXCED_RANGE );
451 return 0;
453 SERVER_START_REQ( open_named_pipe )
455 req->access = access;
456 SetLastError(0);
457 wine_server_add_data( req, buffer, len * sizeof(WCHAR) );
458 wine_server_call_err( req );
459 ret = reply->handle;
461 SERVER_END_REQ;
462 TRACE("Returned %d\n",ret);
463 return ret;
466 /*************************************************************************
467 * CreateFileA [KERNEL32.@] Creates or opens a file or other object
469 * Creates or opens an object, and returns a handle that can be used to
470 * access that object.
472 * PARAMS
474 * filename [in] pointer to filename to be accessed
475 * access [in] access mode requested
476 * sharing [in] share mode
477 * sa [in] pointer to security attributes
478 * creation [in] how to create the file
479 * attributes [in] attributes for newly created file
480 * template [in] handle to file with extended attributes to copy
482 * RETURNS
483 * Success: Open handle to specified file
484 * Failure: INVALID_HANDLE_VALUE
486 * NOTES
487 * Should call SetLastError() on failure.
489 * BUGS
491 * Doesn't support character devices, template files, or a
492 * lot of the 'attributes' flags yet.
494 HANDLE WINAPI CreateFileA( LPCSTR filename, DWORD access, DWORD sharing,
495 LPSECURITY_ATTRIBUTES sa, DWORD creation,
496 DWORD attributes, HANDLE template )
498 DOS_FULL_NAME full_name;
499 HANDLE ret;
501 if (!filename)
503 SetLastError( ERROR_INVALID_PARAMETER );
504 return INVALID_HANDLE_VALUE;
506 TRACE("%s %s%s%s%s%s%s%s\n",filename,
507 ((access & GENERIC_READ)==GENERIC_READ)?"GENERIC_READ ":"",
508 ((access & GENERIC_WRITE)==GENERIC_WRITE)?"GENERIC_WRITE ":"",
509 (!access)?"QUERY_ACCESS ":"",
510 ((sharing & FILE_SHARE_READ)==FILE_SHARE_READ)?"FILE_SHARE_READ ":"",
511 ((sharing & FILE_SHARE_WRITE)==FILE_SHARE_WRITE)?"FILE_SHARE_WRITE ":"",
512 ((sharing & FILE_SHARE_DELETE)==FILE_SHARE_DELETE)?"FILE_SHARE_DELETE ":"",
513 (creation ==CREATE_NEW)?"CREATE_NEW":
514 (creation ==CREATE_ALWAYS)?"CREATE_ALWAYS ":
515 (creation ==OPEN_EXISTING)?"OPEN_EXISTING ":
516 (creation ==OPEN_ALWAYS)?"OPEN_ALWAYS ":
517 (creation ==TRUNCATE_EXISTING)?"TRUNCATE_EXISTING ":"");
519 /* If the name starts with '\\?\', ignore the first 4 chars. */
520 if (!strncmp(filename, "\\\\?\\", 4))
522 filename += 4;
523 if (!strncmp(filename, "UNC\\", 4))
525 FIXME("UNC name (%s) not supported.\n", filename );
526 SetLastError( ERROR_PATH_NOT_FOUND );
527 return INVALID_HANDLE_VALUE;
531 if (!strncmp(filename, "\\\\.\\", 4)) {
532 if(!strncasecmp(&filename[4],"pipe\\",5))
534 TRACE("Opening a pipe: %s\n",filename);
535 ret = FILE_OpenPipe(filename,access);
536 goto done;
538 else if (isalpha(filename[4]) && filename[5] == ':' && filename[6] == '\0')
540 ret = FILE_CreateDevice( (toupper(filename[4]) - 'A') | 0x20000, access, sa );
541 goto done;
543 else if (!DOSFS_GetDevice( filename ))
545 ret = DEVICE_Open( filename+4, access, sa );
546 goto done;
548 else
549 filename+=4; /* fall into DOSFS_Device case below */
552 /* If the name still starts with '\\', it's a UNC name. */
553 if (!strncmp(filename, "\\\\", 2))
555 ret = SMB_CreateFileA(filename, access, sharing, sa, creation, attributes, template );
556 goto done;
559 /* If the name contains a DOS wild card (* or ?), do no create a file */
560 if(strchr(filename,'*') || strchr(filename,'?'))
561 return INVALID_HANDLE_VALUE;
563 /* Open a console for CONIN$ or CONOUT$ */
564 if (!strcasecmp(filename, "CONIN$"))
566 ret = FILE_OpenConsole( FALSE, access, sharing, sa );
567 goto done;
569 if (!strcasecmp(filename, "CONOUT$"))
571 ret = FILE_OpenConsole( TRUE, access, sharing, sa );
572 goto done;
575 if (DOSFS_GetDevice( filename ))
577 TRACE("opening device '%s'\n", filename );
579 if (!(ret = DOSFS_OpenDevice( filename, access, attributes, sa )))
581 /* Do not silence this please. It is a critical error. -MM */
582 ERR("Couldn't open device '%s'!\n",filename);
583 SetLastError( ERROR_FILE_NOT_FOUND );
585 goto done;
588 /* check for filename, don't check for last entry if creating */
589 if (!DOSFS_GetFullName( filename,
590 (creation == OPEN_EXISTING) ||
591 (creation == TRUNCATE_EXISTING),
592 &full_name )) {
593 WARN("Unable to get full filename from '%s' (GLE %ld)\n",
594 filename, GetLastError());
595 return INVALID_HANDLE_VALUE;
598 ret = FILE_CreateFile( full_name.long_name, access, sharing,
599 sa, creation, attributes, template,
600 DRIVE_GetFlags(full_name.drive) & DRIVE_FAIL_READ_ONLY,
601 GetDriveTypeA( full_name.short_name ) );
602 done:
603 if (!ret) ret = INVALID_HANDLE_VALUE;
604 return ret;
609 /*************************************************************************
610 * CreateFileW (KERNEL32.@)
612 HANDLE WINAPI CreateFileW( LPCWSTR filename, DWORD access, DWORD sharing,
613 LPSECURITY_ATTRIBUTES sa, DWORD creation,
614 DWORD attributes, HANDLE template)
616 LPSTR afn = HEAP_strdupWtoA( GetProcessHeap(), 0, filename );
617 HANDLE res = CreateFileA( afn, access, sharing, sa, creation, attributes, template );
618 HeapFree( GetProcessHeap(), 0, afn );
619 return res;
623 /***********************************************************************
624 * FILE_FillInfo
626 * Fill a file information from a struct stat.
628 static void FILE_FillInfo( struct stat *st, BY_HANDLE_FILE_INFORMATION *info )
630 if (S_ISDIR(st->st_mode))
631 info->dwFileAttributes = FILE_ATTRIBUTE_DIRECTORY;
632 else
633 info->dwFileAttributes = FILE_ATTRIBUTE_ARCHIVE;
634 if (!(st->st_mode & S_IWUSR))
635 info->dwFileAttributes |= FILE_ATTRIBUTE_READONLY;
637 RtlSecondsSince1970ToTime( st->st_mtime, &info->ftCreationTime );
638 RtlSecondsSince1970ToTime( st->st_mtime, &info->ftLastWriteTime );
639 RtlSecondsSince1970ToTime( st->st_atime, &info->ftLastAccessTime );
641 info->dwVolumeSerialNumber = 0; /* FIXME */
642 info->nFileSizeHigh = 0;
643 info->nFileSizeLow = 0;
644 if (!S_ISDIR(st->st_mode)) {
645 info->nFileSizeHigh = st->st_size >> 32;
646 info->nFileSizeLow = st->st_size & 0xffffffff;
648 info->nNumberOfLinks = st->st_nlink;
649 info->nFileIndexHigh = 0;
650 info->nFileIndexLow = st->st_ino;
654 /***********************************************************************
655 * FILE_Stat
657 * Stat a Unix path name. Return TRUE if OK.
659 BOOL FILE_Stat( LPCSTR unixName, BY_HANDLE_FILE_INFORMATION *info )
661 struct stat st;
663 if (lstat( unixName, &st ) == -1)
665 FILE_SetDosError();
666 return FALSE;
668 if (!S_ISLNK(st.st_mode)) FILE_FillInfo( &st, info );
669 else
671 /* do a "real" stat to find out
672 about the type of the symlink destination */
673 if (stat( unixName, &st ) == -1)
675 FILE_SetDosError();
676 return FALSE;
678 FILE_FillInfo( &st, info );
679 info->dwFileAttributes |= FILE_ATTRIBUTE_SYMLINK;
681 return TRUE;
685 /***********************************************************************
686 * GetFileInformationByHandle (KERNEL32.@)
688 DWORD WINAPI GetFileInformationByHandle( HANDLE hFile,
689 BY_HANDLE_FILE_INFORMATION *info )
691 DWORD ret;
692 if (!info) return 0;
694 SERVER_START_REQ( get_file_info )
696 req->handle = hFile;
697 if ((ret = !wine_server_call_err( req )))
699 /* FIXME: which file types are supported ?
700 * Serial ports (FILE_TYPE_CHAR) are not,
701 * and MSDN also says that pipes are not supported.
702 * FILE_TYPE_REMOTE seems to be supported according to
703 * MSDN q234741.txt */
704 if ((reply->type == FILE_TYPE_DISK) || (reply->type == FILE_TYPE_REMOTE))
706 RtlSecondsSince1970ToTime( reply->write_time, &info->ftCreationTime );
707 RtlSecondsSince1970ToTime( reply->write_time, &info->ftLastWriteTime );
708 RtlSecondsSince1970ToTime( reply->access_time, &info->ftLastAccessTime );
709 info->dwFileAttributes = reply->attr;
710 info->dwVolumeSerialNumber = reply->serial;
711 info->nFileSizeHigh = reply->size_high;
712 info->nFileSizeLow = reply->size_low;
713 info->nNumberOfLinks = reply->links;
714 info->nFileIndexHigh = reply->index_high;
715 info->nFileIndexLow = reply->index_low;
717 else
719 SetLastError(ERROR_NOT_SUPPORTED);
720 ret = 0;
724 SERVER_END_REQ;
725 return ret;
729 /**************************************************************************
730 * GetFileAttributes (KERNEL.420)
732 DWORD WINAPI GetFileAttributes16( LPCSTR name )
734 return GetFileAttributesA( name );
738 /**************************************************************************
739 * GetFileAttributesA (KERNEL32.@)
741 DWORD WINAPI GetFileAttributesA( LPCSTR name )
743 DOS_FULL_NAME full_name;
744 BY_HANDLE_FILE_INFORMATION info;
746 if (name == NULL)
748 SetLastError( ERROR_INVALID_PARAMETER );
749 return -1;
751 if (!DOSFS_GetFullName( name, TRUE, &full_name) )
752 return -1;
753 if (!FILE_Stat( full_name.long_name, &info )) return -1;
754 return info.dwFileAttributes;
758 /**************************************************************************
759 * GetFileAttributesW (KERNEL32.@)
761 DWORD WINAPI GetFileAttributesW( LPCWSTR name )
763 LPSTR nameA = HEAP_strdupWtoA( GetProcessHeap(), 0, name );
764 DWORD res = GetFileAttributesA( nameA );
765 HeapFree( GetProcessHeap(), 0, nameA );
766 return res;
770 /**************************************************************************
771 * SetFileAttributes (KERNEL.421)
773 BOOL16 WINAPI SetFileAttributes16( LPCSTR lpFileName, DWORD attributes )
775 return SetFileAttributesA( lpFileName, attributes );
779 /**************************************************************************
780 * SetFileAttributesA (KERNEL32.@)
782 BOOL WINAPI SetFileAttributesA(LPCSTR lpFileName, DWORD attributes)
784 struct stat buf;
785 DOS_FULL_NAME full_name;
787 if (!DOSFS_GetFullName( lpFileName, TRUE, &full_name ))
788 return FALSE;
790 TRACE("(%s,%lx)\n",lpFileName,attributes);
791 if(stat(full_name.long_name,&buf)==-1)
793 FILE_SetDosError();
794 return FALSE;
796 if (attributes & FILE_ATTRIBUTE_READONLY)
798 if(S_ISDIR(buf.st_mode))
799 /* FIXME */
800 WARN("FILE_ATTRIBUTE_READONLY ignored for directory.\n");
801 else
802 buf.st_mode &= ~0222; /* octal!, clear write permission bits */
803 attributes &= ~FILE_ATTRIBUTE_READONLY;
805 else
807 /* add write permission */
808 buf.st_mode |= (0600 | ((buf.st_mode & 044) >> 1)) & (~FILE_umask);
810 if (attributes & FILE_ATTRIBUTE_DIRECTORY)
812 if (!S_ISDIR(buf.st_mode))
813 FIXME("SetFileAttributes expected the file '%s' to be a directory\n",
814 lpFileName);
815 attributes &= ~FILE_ATTRIBUTE_DIRECTORY;
817 attributes &= ~(FILE_ATTRIBUTE_NORMAL|FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_HIDDEN|FILE_ATTRIBUTE_SYSTEM);
818 if (attributes)
819 FIXME("(%s):%lx attribute(s) not implemented.\n", lpFileName,attributes);
820 if (-1==chmod(full_name.long_name,buf.st_mode))
822 if(GetDriveTypeA(lpFileName) == DRIVE_CDROM) {
823 SetLastError( ERROR_ACCESS_DENIED );
824 return FALSE;
828 * FIXME: We don't return FALSE here because of differences between
829 * Linux and Windows privileges. Under Linux only the owner of
830 * the file is allowed to change file attributes. Under Windows,
831 * applications expect that if you can write to a file, you can also
832 * change its attributes (see GENERIC_WRITE). We could try to be
833 * clever here but that would break multi-user installations where
834 * users share read-only DLLs. This is because some installers like
835 * to change attributes of already installed DLLs.
837 FIXME("Couldn't set file attributes for existing file \"%s\".\n"
838 "Check permissions or set VFAT \"quiet\" mount flag\n", full_name.long_name);
840 return TRUE;
844 /**************************************************************************
845 * SetFileAttributesW (KERNEL32.@)
847 BOOL WINAPI SetFileAttributesW(LPCWSTR lpFileName, DWORD attributes)
849 BOOL res;
850 DWORD len = WideCharToMultiByte( CP_ACP, 0, lpFileName, -1, NULL, 0, NULL, NULL );
851 LPSTR afn = HeapAlloc( GetProcessHeap(), 0, len );
853 WideCharToMultiByte( CP_ACP, 0, lpFileName, -1, afn, len, NULL, NULL );
854 res = SetFileAttributesA( afn, attributes );
855 HeapFree( GetProcessHeap(), 0, afn );
856 return res;
860 /***********************************************************************
861 * GetFileSize (KERNEL32.@)
863 DWORD WINAPI GetFileSize( HANDLE hFile, LPDWORD filesizehigh )
865 BY_HANDLE_FILE_INFORMATION info;
866 if (!GetFileInformationByHandle( hFile, &info )) return -1;
867 if (filesizehigh) *filesizehigh = info.nFileSizeHigh;
868 return info.nFileSizeLow;
872 /***********************************************************************
873 * GetFileTime (KERNEL32.@)
875 BOOL WINAPI GetFileTime( HANDLE hFile, FILETIME *lpCreationTime,
876 FILETIME *lpLastAccessTime,
877 FILETIME *lpLastWriteTime )
879 BY_HANDLE_FILE_INFORMATION info;
880 if (!GetFileInformationByHandle( hFile, &info )) return FALSE;
881 if (lpCreationTime) *lpCreationTime = info.ftCreationTime;
882 if (lpLastAccessTime) *lpLastAccessTime = info.ftLastAccessTime;
883 if (lpLastWriteTime) *lpLastWriteTime = info.ftLastWriteTime;
884 return TRUE;
887 /***********************************************************************
888 * CompareFileTime (KERNEL32.@)
890 INT WINAPI CompareFileTime( LPFILETIME x, LPFILETIME y )
892 if (!x || !y) return -1;
894 if (x->dwHighDateTime > y->dwHighDateTime)
895 return 1;
896 if (x->dwHighDateTime < y->dwHighDateTime)
897 return -1;
898 if (x->dwLowDateTime > y->dwLowDateTime)
899 return 1;
900 if (x->dwLowDateTime < y->dwLowDateTime)
901 return -1;
902 return 0;
905 /***********************************************************************
906 * FILE_GetTempFileName : utility for GetTempFileName
908 static UINT FILE_GetTempFileName( LPCSTR path, LPCSTR prefix, UINT unique,
909 LPSTR buffer, BOOL isWin16 )
911 static UINT unique_temp;
912 DOS_FULL_NAME full_name;
913 int i;
914 LPSTR p;
915 UINT num;
917 if ( !path || !prefix || !buffer ) return 0;
919 if (!unique_temp) unique_temp = time(NULL) & 0xffff;
920 num = unique ? (unique & 0xffff) : (unique_temp++ & 0xffff);
922 strcpy( buffer, path );
923 p = buffer + strlen(buffer);
925 /* add a \, if there isn't one and path is more than just the drive letter ... */
926 if ( !((strlen(buffer) == 2) && (buffer[1] == ':'))
927 && ((p == buffer) || (p[-1] != '\\'))) *p++ = '\\';
929 if (isWin16) *p++ = '~';
930 for (i = 3; (i > 0) && (*prefix); i--) *p++ = *prefix++;
931 sprintf( p, "%04x.tmp", num );
933 /* Now try to create it */
935 if (!unique)
939 HFILE handle = CreateFileA( buffer, GENERIC_WRITE, 0, NULL,
940 CREATE_NEW, FILE_ATTRIBUTE_NORMAL, 0 );
941 if (handle != INVALID_HANDLE_VALUE)
942 { /* We created it */
943 TRACE("created %s\n",
944 buffer);
945 CloseHandle( handle );
946 break;
948 if (GetLastError() != ERROR_FILE_EXISTS)
949 break; /* No need to go on */
950 num++;
951 sprintf( p, "%04x.tmp", num );
952 } while (num != (unique & 0xffff));
955 /* Get the full path name */
957 if (DOSFS_GetFullName( buffer, FALSE, &full_name ))
959 /* Check if we have write access in the directory */
960 if ((p = strrchr( full_name.long_name, '/' ))) *p = '\0';
961 if (access( full_name.long_name, W_OK ) == -1)
962 WARN("returns '%s', which doesn't seem to be writeable.\n",
963 buffer);
965 TRACE("returning %s\n", buffer );
966 return unique ? unique : num;
970 /***********************************************************************
971 * GetTempFileNameA (KERNEL32.@)
973 UINT WINAPI GetTempFileNameA( LPCSTR path, LPCSTR prefix, UINT unique,
974 LPSTR buffer)
976 return FILE_GetTempFileName(path, prefix, unique, buffer, FALSE);
979 /***********************************************************************
980 * GetTempFileNameW (KERNEL32.@)
982 UINT WINAPI GetTempFileNameW( LPCWSTR path, LPCWSTR prefix, UINT unique,
983 LPWSTR buffer )
985 LPSTR patha,prefixa;
986 char buffera[144];
987 UINT ret;
989 if (!path) return 0;
990 patha = HEAP_strdupWtoA( GetProcessHeap(), 0, path );
991 prefixa = HEAP_strdupWtoA( GetProcessHeap(), 0, prefix );
992 ret = FILE_GetTempFileName( patha, prefixa, unique, buffera, FALSE );
993 MultiByteToWideChar( CP_ACP, 0, buffera, -1, buffer, MAX_PATH );
994 HeapFree( GetProcessHeap(), 0, patha );
995 HeapFree( GetProcessHeap(), 0, prefixa );
996 return ret;
1000 /***********************************************************************
1001 * GetTempFileName (KERNEL.97)
1003 UINT16 WINAPI GetTempFileName16( BYTE drive, LPCSTR prefix, UINT16 unique,
1004 LPSTR buffer )
1006 char temppath[144];
1008 if (!(drive & ~TF_FORCEDRIVE)) /* drive 0 means current default drive */
1009 drive |= DRIVE_GetCurrentDrive() + 'A';
1011 if ((drive & TF_FORCEDRIVE) &&
1012 !DRIVE_IsValid( toupper(drive & ~TF_FORCEDRIVE) - 'A' ))
1014 drive &= ~TF_FORCEDRIVE;
1015 WARN("invalid drive %d specified\n", drive );
1018 if (drive & TF_FORCEDRIVE)
1019 sprintf(temppath,"%c:", drive & ~TF_FORCEDRIVE );
1020 else
1021 GetTempPathA( 132, temppath );
1022 return (UINT16)FILE_GetTempFileName( temppath, prefix, unique, buffer, TRUE );
1025 /***********************************************************************
1026 * FILE_DoOpenFile
1028 * Implementation of OpenFile16() and OpenFile32().
1030 static HFILE FILE_DoOpenFile( LPCSTR name, OFSTRUCT *ofs, UINT mode,
1031 BOOL win32 )
1033 HFILE hFileRet;
1034 FILETIME filetime;
1035 WORD filedatetime[2];
1036 DOS_FULL_NAME full_name;
1037 DWORD access, sharing;
1038 char *p;
1040 if (!ofs) return HFILE_ERROR;
1042 TRACE("%s %s %s %s%s%s%s%s%s%s%s%s\n",name,
1043 ((mode & 0x3 )==OF_READ)?"OF_READ":
1044 ((mode & 0x3 )==OF_WRITE)?"OF_WRITE":
1045 ((mode & 0x3 )==OF_READWRITE)?"OF_READWRITE":"unknown",
1046 ((mode & 0x70 )==OF_SHARE_COMPAT)?"OF_SHARE_COMPAT":
1047 ((mode & 0x70 )==OF_SHARE_DENY_NONE)?"OF_SHARE_DENY_NONE":
1048 ((mode & 0x70 )==OF_SHARE_DENY_READ)?"OF_SHARE_DENY_READ":
1049 ((mode & 0x70 )==OF_SHARE_DENY_WRITE)?"OF_SHARE_DENY_WRITE":
1050 ((mode & 0x70 )==OF_SHARE_EXCLUSIVE)?"OF_SHARE_EXCLUSIVE":"unknown",
1051 ((mode & OF_PARSE )==OF_PARSE)?"OF_PARSE ":"",
1052 ((mode & OF_DELETE )==OF_DELETE)?"OF_DELETE ":"",
1053 ((mode & OF_VERIFY )==OF_VERIFY)?"OF_VERIFY ":"",
1054 ((mode & OF_SEARCH )==OF_SEARCH)?"OF_SEARCH ":"",
1055 ((mode & OF_CANCEL )==OF_CANCEL)?"OF_CANCEL ":"",
1056 ((mode & OF_CREATE )==OF_CREATE)?"OF_CREATE ":"",
1057 ((mode & OF_PROMPT )==OF_PROMPT)?"OF_PROMPT ":"",
1058 ((mode & OF_EXIST )==OF_EXIST)?"OF_EXIST ":"",
1059 ((mode & OF_REOPEN )==OF_REOPEN)?"OF_REOPEN ":""
1063 ofs->cBytes = sizeof(OFSTRUCT);
1064 ofs->nErrCode = 0;
1065 if (mode & OF_REOPEN) name = ofs->szPathName;
1067 if (!name) {
1068 ERR("called with `name' set to NULL ! Please debug.\n");
1069 return HFILE_ERROR;
1072 TRACE("%s %04x\n", name, mode );
1074 /* the watcom 10.6 IDE relies on a valid path returned in ofs->szPathName
1075 Are there any cases where getting the path here is wrong?
1076 Uwe Bonnes 1997 Apr 2 */
1077 if (!GetFullPathNameA( name, sizeof(ofs->szPathName),
1078 ofs->szPathName, NULL )) goto error;
1079 FILE_ConvertOFMode( mode, &access, &sharing );
1081 /* OF_PARSE simply fills the structure */
1083 if (mode & OF_PARSE)
1085 ofs->fFixedDisk = (GetDriveType16( ofs->szPathName[0]-'A' )
1086 != DRIVE_REMOVABLE);
1087 TRACE("(%s): OF_PARSE, res = '%s'\n",
1088 name, ofs->szPathName );
1089 return 0;
1092 /* OF_CREATE is completely different from all other options, so
1093 handle it first */
1095 if (mode & OF_CREATE)
1097 if ((hFileRet = CreateFileA( name, GENERIC_READ | GENERIC_WRITE,
1098 sharing, NULL, CREATE_ALWAYS,
1099 FILE_ATTRIBUTE_NORMAL, 0 ))== INVALID_HANDLE_VALUE)
1100 goto error;
1101 goto success;
1104 /* If OF_SEARCH is set, ignore the given path */
1106 if ((mode & OF_SEARCH) && !(mode & OF_REOPEN))
1108 /* First try the file name as is */
1109 if (DOSFS_GetFullName( name, TRUE, &full_name )) goto found;
1110 /* Now remove the path */
1111 if (name[0] && (name[1] == ':')) name += 2;
1112 if ((p = strrchr( name, '\\' ))) name = p + 1;
1113 if ((p = strrchr( name, '/' ))) name = p + 1;
1114 if (!name[0]) goto not_found;
1117 /* Now look for the file */
1119 if (!DIR_SearchPath( NULL, name, NULL, &full_name, win32 )) goto not_found;
1121 found:
1122 TRACE("found %s = %s\n",
1123 full_name.long_name, full_name.short_name );
1124 lstrcpynA( ofs->szPathName, full_name.short_name,
1125 sizeof(ofs->szPathName) );
1127 if (mode & OF_SHARE_EXCLUSIVE)
1128 /* Some InstallShield version uses OF_SHARE_EXCLUSIVE
1129 on the file <tempdir>/_ins0432._mp to determine how
1130 far installation has proceeded.
1131 _ins0432._mp is an executable and while running the
1132 application expects the open with OF_SHARE_ to fail*/
1133 /* Probable FIXME:
1134 As our loader closes the files after loading the executable,
1135 we can't find the running executable with FILE_InUse.
1136 The loader should keep the file open, as Windows does that, too.
1139 char *last = strrchr(full_name.long_name,'/');
1140 if (!last)
1141 last = full_name.long_name - 1;
1142 if (GetModuleHandle16(last+1))
1144 TRACE("Denying shared open for %s\n",full_name.long_name);
1145 return HFILE_ERROR;
1149 if (mode & OF_DELETE)
1151 if (unlink( full_name.long_name ) == -1) goto not_found;
1152 TRACE("(%s): OF_DELETE return = OK\n", name);
1153 return 1;
1156 hFileRet = FILE_CreateFile( full_name.long_name, access, sharing,
1157 NULL, OPEN_EXISTING, 0, 0,
1158 DRIVE_GetFlags(full_name.drive) & DRIVE_FAIL_READ_ONLY,
1159 GetDriveTypeA( full_name.short_name ) );
1160 if (!hFileRet) goto not_found;
1162 GetFileTime( hFileRet, NULL, NULL, &filetime );
1163 FileTimeToDosDateTime( &filetime, &filedatetime[0], &filedatetime[1] );
1164 if ((mode & OF_VERIFY) && (mode & OF_REOPEN))
1166 if (memcmp( ofs->reserved, filedatetime, sizeof(ofs->reserved) ))
1168 CloseHandle( hFileRet );
1169 WARN("(%s): OF_VERIFY failed\n", name );
1170 /* FIXME: what error here? */
1171 SetLastError( ERROR_FILE_NOT_FOUND );
1172 goto error;
1175 memcpy( ofs->reserved, filedatetime, sizeof(ofs->reserved) );
1177 success: /* We get here if the open was successful */
1178 TRACE("(%s): OK, return = %d\n", name, hFileRet );
1179 if (win32)
1181 if (mode & OF_EXIST) /* Return the handle, but close it first */
1182 CloseHandle( hFileRet );
1184 else
1186 hFileRet = Win32HandleToDosFileHandle( hFileRet );
1187 if (hFileRet == HFILE_ERROR16) goto error;
1188 if (mode & OF_EXIST) /* Return the handle, but close it first */
1189 _lclose16( hFileRet );
1191 return hFileRet;
1193 not_found: /* We get here if the file does not exist */
1194 WARN("'%s' not found or sharing violation\n", name );
1195 SetLastError( ERROR_FILE_NOT_FOUND );
1196 /* fall through */
1198 error: /* We get here if there was an error opening the file */
1199 ofs->nErrCode = GetLastError();
1200 WARN("(%s): return = HFILE_ERROR error= %d\n",
1201 name,ofs->nErrCode );
1202 return HFILE_ERROR;
1206 /***********************************************************************
1207 * OpenFile (KERNEL.74)
1208 * OpenFileEx (KERNEL.360)
1210 HFILE16 WINAPI OpenFile16( LPCSTR name, OFSTRUCT *ofs, UINT16 mode )
1212 return FILE_DoOpenFile( name, ofs, mode, FALSE );
1216 /***********************************************************************
1217 * OpenFile (KERNEL32.@)
1219 HFILE WINAPI OpenFile( LPCSTR name, OFSTRUCT *ofs, UINT mode )
1221 return FILE_DoOpenFile( name, ofs, mode, TRUE );
1225 /***********************************************************************
1226 * FILE_InitProcessDosHandles
1228 * Allocates the default DOS handles for a process. Called either by
1229 * Win32HandleToDosFileHandle below or by the DOSVM stuff.
1231 static void FILE_InitProcessDosHandles( void )
1233 dos_handles[0] = GetStdHandle(STD_INPUT_HANDLE);
1234 dos_handles[1] = GetStdHandle(STD_OUTPUT_HANDLE);
1235 dos_handles[2] = GetStdHandle(STD_ERROR_HANDLE);
1236 dos_handles[3] = GetStdHandle(STD_ERROR_HANDLE);
1237 dos_handles[4] = GetStdHandle(STD_ERROR_HANDLE);
1240 /***********************************************************************
1241 * Win32HandleToDosFileHandle (KERNEL32.21)
1243 * Allocate a DOS handle for a Win32 handle. The Win32 handle is no
1244 * longer valid after this function (even on failure).
1246 * Note: this is not exactly right, since on Win95 the Win32 handles
1247 * are on top of DOS handles and we do it the other way
1248 * around. Should be good enough though.
1250 HFILE WINAPI Win32HandleToDosFileHandle( HANDLE handle )
1252 int i;
1254 if (!handle || (handle == INVALID_HANDLE_VALUE))
1255 return HFILE_ERROR;
1257 for (i = 5; i < DOS_TABLE_SIZE; i++)
1258 if (!dos_handles[i])
1260 dos_handles[i] = handle;
1261 TRACE("Got %d for h32 %d\n", i, handle );
1262 return (HFILE)i;
1264 CloseHandle( handle );
1265 SetLastError( ERROR_TOO_MANY_OPEN_FILES );
1266 return HFILE_ERROR;
1270 /***********************************************************************
1271 * DosFileHandleToWin32Handle (KERNEL32.20)
1273 * Return the Win32 handle for a DOS handle.
1275 * Note: this is not exactly right, since on Win95 the Win32 handles
1276 * are on top of DOS handles and we do it the other way
1277 * around. Should be good enough though.
1279 HANDLE WINAPI DosFileHandleToWin32Handle( HFILE handle )
1281 HFILE16 hfile = (HFILE16)handle;
1282 if (hfile < 5 && !dos_handles[hfile]) FILE_InitProcessDosHandles();
1283 if ((hfile >= DOS_TABLE_SIZE) || !dos_handles[hfile])
1285 SetLastError( ERROR_INVALID_HANDLE );
1286 return INVALID_HANDLE_VALUE;
1288 return dos_handles[hfile];
1292 /***********************************************************************
1293 * DisposeLZ32Handle (KERNEL32.22)
1295 * Note: this is not entirely correct, we should only close the
1296 * 32-bit handle and not the 16-bit one, but we cannot do
1297 * this because of the way our DOS handles are implemented.
1298 * It shouldn't break anything though.
1300 void WINAPI DisposeLZ32Handle( HANDLE handle )
1302 int i;
1304 if (!handle || (handle == INVALID_HANDLE_VALUE)) return;
1306 for (i = 5; i < DOS_TABLE_SIZE; i++)
1307 if (dos_handles[i] == handle)
1309 dos_handles[i] = 0;
1310 CloseHandle( handle );
1311 break;
1316 /***********************************************************************
1317 * FILE_Dup2
1319 * dup2() function for DOS handles.
1321 HFILE16 FILE_Dup2( HFILE16 hFile1, HFILE16 hFile2 )
1323 HANDLE new_handle;
1325 if (hFile1 < 5 && !dos_handles[hFile1]) FILE_InitProcessDosHandles();
1327 if ((hFile1 >= DOS_TABLE_SIZE) || (hFile2 >= DOS_TABLE_SIZE) || !dos_handles[hFile1])
1329 SetLastError( ERROR_INVALID_HANDLE );
1330 return HFILE_ERROR16;
1332 if (hFile2 < 5)
1334 FIXME("stdio handle closed, need proper conversion\n" );
1335 SetLastError( ERROR_INVALID_HANDLE );
1336 return HFILE_ERROR16;
1338 if (!DuplicateHandle( GetCurrentProcess(), dos_handles[hFile1],
1339 GetCurrentProcess(), &new_handle,
1340 0, FALSE, DUPLICATE_SAME_ACCESS ))
1341 return HFILE_ERROR16;
1342 if (dos_handles[hFile2]) CloseHandle( dos_handles[hFile2] );
1343 dos_handles[hFile2] = new_handle;
1344 return hFile2;
1348 /***********************************************************************
1349 * _lclose (KERNEL.81)
1351 HFILE16 WINAPI _lclose16( HFILE16 hFile )
1353 if (hFile < 5)
1355 FIXME("stdio handle closed, need proper conversion\n" );
1356 SetLastError( ERROR_INVALID_HANDLE );
1357 return HFILE_ERROR16;
1359 if ((hFile >= DOS_TABLE_SIZE) || !dos_handles[hFile])
1361 SetLastError( ERROR_INVALID_HANDLE );
1362 return HFILE_ERROR16;
1364 TRACE("%d (handle32=%d)\n", hFile, dos_handles[hFile] );
1365 CloseHandle( dos_handles[hFile] );
1366 dos_handles[hFile] = 0;
1367 return 0;
1371 /***********************************************************************
1372 * _lclose (KERNEL32.@)
1374 HFILE WINAPI _lclose( HFILE hFile )
1376 TRACE("handle %d\n", hFile );
1377 return CloseHandle( hFile ) ? 0 : HFILE_ERROR;
1380 /***********************************************************************
1381 * GetOverlappedResult (KERNEL32.@)
1383 * Check the result of an Asynchronous data transfer from a file.
1385 * RETURNS
1386 * TRUE on success
1387 * FALSE on failure
1389 * If successful (and relevant) lpTransferred will hold the number of
1390 * bytes transferred during the async operation.
1392 * BUGS
1394 * Currently only works for WaitCommEvent, ReadFile, WriteFile
1395 * with communications ports.
1398 BOOL WINAPI GetOverlappedResult(
1399 HANDLE hFile, /* [in] handle of file to check on */
1400 LPOVERLAPPED lpOverlapped, /* [in/out] pointer to overlapped */
1401 LPDWORD lpTransferred, /* [in/out] number of bytes transferred */
1402 BOOL bWait /* [in] wait for the transfer to complete ? */
1404 DWORD r;
1406 TRACE("(%d %p %p %x)\n", hFile, lpOverlapped, lpTransferred, bWait);
1408 if(lpOverlapped==NULL)
1410 ERR("lpOverlapped was null\n");
1411 return FALSE;
1413 if(!lpOverlapped->hEvent)
1415 ERR("lpOverlapped->hEvent was null\n");
1416 return FALSE;
1419 do {
1420 TRACE("waiting on %p\n",lpOverlapped);
1421 r = WaitForSingleObjectEx(lpOverlapped->hEvent, bWait?INFINITE:0, TRUE);
1422 TRACE("wait on %p returned %ld\n",lpOverlapped,r);
1423 } while (r==STATUS_USER_APC);
1425 if(lpTransferred)
1426 *lpTransferred = lpOverlapped->InternalHigh;
1428 SetLastError ( lpOverlapped->Internal == STATUS_PENDING ?
1429 ERROR_IO_INCOMPLETE : RtlNtStatusToDosError ( lpOverlapped->Internal ) );
1431 return (r==WAIT_OBJECT_0);
1434 /***********************************************************************
1435 * CancelIo (KERNEL32.@)
1437 BOOL WINAPI CancelIo(HANDLE handle)
1439 async_private *ovp,*t;
1441 TRACE("handle = %x\n",handle);
1443 for (ovp = NtCurrentTeb()->pending_list; ovp; ovp = t)
1445 t = ovp->next;
1446 if ( ovp->handle == handle )
1447 cancel_async ( ovp );
1449 WaitForMultipleObjectsEx(0,NULL,FALSE,1,TRUE);
1450 return TRUE;
1453 /***********************************************************************
1454 * FILE_AsyncReadService (INTERNAL)
1456 * This function is called while the client is waiting on the
1457 * server, so we can't make any server calls here.
1459 static void FILE_AsyncReadService(async_private *ovp)
1461 async_fileio *fileio = (async_fileio*) ovp;
1462 LPOVERLAPPED lpOverlapped = fileio->lpOverlapped;
1463 int result, r;
1464 int already = lpOverlapped->InternalHigh;
1466 TRACE("%p %p\n", lpOverlapped, fileio->buffer );
1468 /* check to see if the data is ready (non-blocking) */
1470 if ( fileio->fd_type == FD_TYPE_SOCKET )
1471 result = read (ovp->fd, &fileio->buffer[already], fileio->count - already);
1472 else
1474 result = pread (ovp->fd, &fileio->buffer[already], fileio->count - already,
1475 OVERLAPPED_OFFSET (lpOverlapped) + already);
1476 if ((result < 0) && (errno == ESPIPE))
1477 result = read (ovp->fd, &fileio->buffer[already], fileio->count - already);
1480 if ( (result<0) && ((errno == EAGAIN) || (errno == EINTR)))
1482 TRACE("Deferred read %d\n",errno);
1483 r = STATUS_PENDING;
1484 goto async_end;
1487 /* check to see if the transfer is complete */
1488 if(result<0)
1490 r = FILE_GetNtStatus ();
1491 goto async_end;
1494 lpOverlapped->InternalHigh += result;
1495 TRACE("read %d more bytes %ld/%d so far\n",result,lpOverlapped->InternalHigh,fileio->count);
1497 if(lpOverlapped->InternalHigh >= fileio->count || fileio->fd_type == FD_TYPE_SOCKET )
1498 r = STATUS_SUCCESS;
1499 else
1500 r = STATUS_PENDING;
1502 async_end:
1503 lpOverlapped->Internal = r;
1506 /***********************************************************************
1507 * FILE_ReadFileEx (INTERNAL)
1509 static BOOL FILE_ReadFileEx(HANDLE hFile, LPVOID buffer, DWORD bytesToRead,
1510 LPOVERLAPPED overlapped,
1511 LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine,
1512 HANDLE hEvent)
1514 async_fileio *ovp;
1515 int fd;
1516 int flags;
1517 enum fd_type type;
1519 TRACE("file %d to buf %p num %ld %p func %p\n",
1520 hFile, buffer, bytesToRead, overlapped, lpCompletionRoutine);
1522 /* check that there is an overlapped struct */
1523 if (overlapped==NULL)
1525 SetLastError(ERROR_INVALID_PARAMETER);
1526 return FALSE;
1529 fd = FILE_GetUnixHandleType ( hFile, GENERIC_READ, &type, &flags);
1530 if ( fd < 0 )
1532 WARN ( "Couldn't get FD\n" );
1533 return FALSE;
1536 ovp = (async_fileio*) HeapAlloc(GetProcessHeap(), 0, sizeof (async_fileio));
1537 if(!ovp)
1539 TRACE("HeapAlloc Failed\n");
1540 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1541 goto error;
1544 ovp->async.ops = ( lpCompletionRoutine ? &fileio_async_ops : &fileio_nocomp_async_ops );
1545 ovp->async.handle = hFile;
1546 ovp->async.fd = fd;
1547 ovp->async.type = ASYNC_TYPE_READ;
1548 ovp->async.func = FILE_AsyncReadService;
1549 ovp->async.event = hEvent;
1550 ovp->lpOverlapped = overlapped;
1551 ovp->count = bytesToRead;
1552 ovp->completion_func = lpCompletionRoutine;
1553 ovp->buffer = buffer;
1554 ovp->fd_type = type;
1556 return !register_new_async (&ovp->async);
1558 error:
1559 close (fd);
1560 return FALSE;
1564 /***********************************************************************
1565 * ReadFileEx (KERNEL32.@)
1567 BOOL WINAPI ReadFileEx(HANDLE hFile, LPVOID buffer, DWORD bytesToRead,
1568 LPOVERLAPPED overlapped,
1569 LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine)
1571 overlapped->InternalHigh = 0;
1572 return FILE_ReadFileEx(hFile,buffer,bytesToRead,overlapped,lpCompletionRoutine, INVALID_HANDLE_VALUE);
1575 static BOOL FILE_TimeoutRead(HANDLE hFile, LPVOID buffer, DWORD bytesToRead, LPDWORD bytesRead)
1577 OVERLAPPED ov;
1578 BOOL r = FALSE;
1580 TRACE("%d %p %ld %p\n", hFile, buffer, bytesToRead, bytesRead );
1582 ZeroMemory(&ov, sizeof (OVERLAPPED));
1583 if(STATUS_SUCCESS==NtCreateEvent(&ov.hEvent, SYNCHRONIZE, NULL, 0, 0))
1585 if(FILE_ReadFileEx(hFile, buffer, bytesToRead, &ov, NULL, ov.hEvent))
1587 r = GetOverlappedResult(hFile, &ov, bytesRead, TRUE);
1590 CloseHandle(ov.hEvent);
1591 return r;
1594 /***********************************************************************
1595 * ReadFile (KERNEL32.@)
1597 BOOL WINAPI ReadFile( HANDLE hFile, LPVOID buffer, DWORD bytesToRead,
1598 LPDWORD bytesRead, LPOVERLAPPED overlapped )
1600 int unix_handle, result, flags;
1601 enum fd_type type;
1603 TRACE("%d %p %ld %p %p\n", hFile, buffer, bytesToRead,
1604 bytesRead, overlapped );
1606 if (bytesRead) *bytesRead = 0; /* Do this before anything else */
1607 if (!bytesToRead) return TRUE;
1609 unix_handle = FILE_GetUnixHandleType( hFile, GENERIC_READ, &type, &flags );
1611 if (flags & FD_FLAG_OVERLAPPED)
1613 if (unix_handle == -1) return FALSE;
1614 if ( (overlapped==NULL) || NtResetEvent( overlapped->hEvent, NULL ) )
1616 TRACE("Overlapped not specified or invalid event flag\n");
1617 close(unix_handle);
1618 SetLastError(ERROR_INVALID_PARAMETER);
1619 return FALSE;
1622 close(unix_handle);
1623 overlapped->InternalHigh = 0;
1625 if(!FILE_ReadFileEx(hFile, buffer, bytesToRead, overlapped, NULL, overlapped->hEvent))
1626 return FALSE;
1628 if ( !GetOverlappedResult (hFile, overlapped, bytesRead, FALSE) )
1630 if ( GetLastError() == ERROR_IO_INCOMPLETE )
1631 SetLastError ( ERROR_IO_PENDING );
1632 return FALSE;
1635 return TRUE;
1637 if (flags & FD_FLAG_TIMEOUT)
1639 close(unix_handle);
1640 return FILE_TimeoutRead(hFile, buffer, bytesToRead, bytesRead);
1642 switch(type)
1644 case FD_TYPE_SMB:
1645 return SMB_ReadFile(hFile, buffer, bytesToRead, bytesRead, NULL);
1646 case FD_TYPE_CONSOLE:
1647 return ReadConsoleA(hFile, buffer, bytesToRead, bytesRead, NULL);
1649 default:
1650 /* normal unix files */
1651 if (unix_handle == -1)
1652 return FALSE;
1653 if (overlapped)
1655 close(unix_handle);
1656 SetLastError(ERROR_INVALID_PARAMETER);
1657 return FALSE;
1659 break;
1662 /* code for synchronous reads */
1663 while ((result = read( unix_handle, buffer, bytesToRead )) == -1)
1665 if ((errno == EAGAIN) || (errno == EINTR)) continue;
1666 if ((errno == EFAULT) && !IsBadWritePtr( buffer, bytesToRead )) continue;
1667 FILE_SetDosError();
1668 break;
1670 close( unix_handle );
1671 if (result == -1) return FALSE;
1672 if (bytesRead) *bytesRead = result;
1673 return TRUE;
1677 /***********************************************************************
1678 * FILE_AsyncWriteService (INTERNAL)
1680 * This function is called while the client is waiting on the
1681 * server, so we can't make any server calls here.
1683 static void FILE_AsyncWriteService(struct async_private *ovp)
1685 async_fileio *fileio = (async_fileio *) ovp;
1686 LPOVERLAPPED lpOverlapped = fileio->lpOverlapped;
1687 int result, r;
1688 int already = lpOverlapped->InternalHigh;
1690 TRACE("(%p %p)\n",lpOverlapped,fileio->buffer);
1692 /* write some data (non-blocking) */
1694 if ( fileio->fd_type == FD_TYPE_SOCKET )
1695 result = write(ovp->fd, &fileio->buffer[already], fileio->count - already);
1696 else
1698 result = pwrite(ovp->fd, &fileio->buffer[already], fileio->count - already,
1699 OVERLAPPED_OFFSET (lpOverlapped) + already);
1700 if ((result < 0) && (errno == ESPIPE))
1701 result = write(ovp->fd, &fileio->buffer[already], fileio->count - already);
1704 if ( (result<0) && ((errno == EAGAIN) || (errno == EINTR)))
1706 r = STATUS_PENDING;
1707 goto async_end;
1710 /* check to see if the transfer is complete */
1711 if(result<0)
1713 r = FILE_GetNtStatus ();
1714 goto async_end;
1717 lpOverlapped->InternalHigh += result;
1719 TRACE("wrote %d more bytes %ld/%d so far\n",result,lpOverlapped->InternalHigh,fileio->count);
1721 if(lpOverlapped->InternalHigh < fileio->count)
1722 r = STATUS_PENDING;
1723 else
1724 r = STATUS_SUCCESS;
1726 async_end:
1727 lpOverlapped->Internal = r;
1730 /***********************************************************************
1731 * FILE_WriteFileEx
1733 static BOOL FILE_WriteFileEx(HANDLE hFile, LPCVOID buffer, DWORD bytesToWrite,
1734 LPOVERLAPPED overlapped,
1735 LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine,
1736 HANDLE hEvent)
1738 async_fileio *ovp;
1739 int fd;
1740 int flags;
1741 enum fd_type type;
1743 TRACE("file %d to buf %p num %ld %p func %p handle %d\n",
1744 hFile, buffer, bytesToWrite, overlapped, lpCompletionRoutine, hEvent);
1746 if (overlapped == NULL)
1748 SetLastError(ERROR_INVALID_PARAMETER);
1749 return FALSE;
1752 fd = FILE_GetUnixHandleType ( hFile, GENERIC_WRITE, &type, &flags );
1753 if ( fd < 0 )
1755 TRACE( "Couldn't get FD\n" );
1756 return FALSE;
1759 ovp = (async_fileio*) HeapAlloc(GetProcessHeap(), 0, sizeof (async_fileio));
1760 if(!ovp)
1762 TRACE("HeapAlloc Failed\n");
1763 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1764 goto error;
1767 ovp->async.ops = ( lpCompletionRoutine ? &fileio_async_ops : &fileio_nocomp_async_ops );
1768 ovp->async.handle = hFile;
1769 ovp->async.fd = fd;
1770 ovp->async.type = ASYNC_TYPE_WRITE;
1771 ovp->async.func = FILE_AsyncWriteService;
1772 ovp->lpOverlapped = overlapped;
1773 ovp->async.event = hEvent;
1774 ovp->buffer = (LPVOID) buffer;
1775 ovp->count = bytesToWrite;
1776 ovp->completion_func = lpCompletionRoutine;
1777 ovp->fd_type = type;
1779 return !register_new_async (&ovp->async);
1781 error:
1782 close (fd);
1783 return FALSE;
1786 /***********************************************************************
1787 * WriteFileEx (KERNEL32.@)
1789 BOOL WINAPI WriteFileEx(HANDLE hFile, LPCVOID buffer, DWORD bytesToWrite,
1790 LPOVERLAPPED overlapped,
1791 LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine)
1793 overlapped->InternalHigh = 0;
1795 return FILE_WriteFileEx(hFile, buffer, bytesToWrite, overlapped, lpCompletionRoutine, INVALID_HANDLE_VALUE);
1798 /***********************************************************************
1799 * WriteFile (KERNEL32.@)
1801 BOOL WINAPI WriteFile( HANDLE hFile, LPCVOID buffer, DWORD bytesToWrite,
1802 LPDWORD bytesWritten, LPOVERLAPPED overlapped )
1804 int unix_handle, result, flags;
1805 enum fd_type type;
1807 TRACE("%d %p %ld %p %p\n", hFile, buffer, bytesToWrite,
1808 bytesWritten, overlapped );
1810 if (bytesWritten) *bytesWritten = 0; /* Do this before anything else */
1811 if (!bytesToWrite) return TRUE;
1813 unix_handle = FILE_GetUnixHandleType( hFile, GENERIC_WRITE, &type, &flags );
1815 if (flags & FD_FLAG_OVERLAPPED)
1817 if (unix_handle == -1) return FALSE;
1818 if ( (overlapped==NULL) || NtResetEvent( overlapped->hEvent, NULL ) )
1820 TRACE("Overlapped not specified or invalid event flag\n");
1821 close(unix_handle);
1822 SetLastError(ERROR_INVALID_PARAMETER);
1823 return FALSE;
1826 close(unix_handle);
1827 overlapped->InternalHigh = 0;
1829 if(!FILE_WriteFileEx(hFile, buffer, bytesToWrite, overlapped, NULL, overlapped->hEvent))
1830 return FALSE;
1832 if ( !GetOverlappedResult (hFile, overlapped, bytesWritten, FALSE) )
1834 if ( GetLastError() == ERROR_IO_INCOMPLETE )
1835 SetLastError ( ERROR_IO_PENDING );
1836 return FALSE;
1839 return TRUE;
1842 switch(type)
1844 case FD_TYPE_CONSOLE:
1845 TRACE("%d %s %ld %p %p\n", hFile, debugstr_an(buffer, bytesToWrite), bytesToWrite,
1846 bytesWritten, overlapped );
1847 return WriteConsoleA(hFile, buffer, bytesToWrite, bytesWritten, NULL);
1848 default:
1849 if (unix_handle == -1)
1850 return FALSE;
1853 /* synchronous file write */
1854 while ((result = write( unix_handle, buffer, bytesToWrite )) == -1)
1856 if ((errno == EAGAIN) || (errno == EINTR)) continue;
1857 if ((errno == EFAULT) && !IsBadReadPtr( buffer, bytesToWrite )) continue;
1858 if (errno == ENOSPC)
1859 SetLastError( ERROR_DISK_FULL );
1860 else
1861 FILE_SetDosError();
1862 break;
1864 close( unix_handle );
1865 if (result == -1) return FALSE;
1866 if (bytesWritten) *bytesWritten = result;
1867 return TRUE;
1871 /***********************************************************************
1872 * _hread (KERNEL.349)
1874 LONG WINAPI WIN16_hread( HFILE16 hFile, SEGPTR buffer, LONG count )
1876 LONG maxlen;
1878 TRACE("%d %08lx %ld\n",
1879 hFile, (DWORD)buffer, count );
1881 /* Some programs pass a count larger than the allocated buffer */
1882 maxlen = GetSelectorLimit16( SELECTOROF(buffer) ) - OFFSETOF(buffer) + 1;
1883 if (count > maxlen) count = maxlen;
1884 return _lread(DosFileHandleToWin32Handle(hFile), MapSL(buffer), count );
1888 /***********************************************************************
1889 * _lread (KERNEL.82)
1891 UINT16 WINAPI WIN16_lread( HFILE16 hFile, SEGPTR buffer, UINT16 count )
1893 return (UINT16)WIN16_hread( hFile, buffer, (LONG)count );
1897 /***********************************************************************
1898 * _lread (KERNEL32.@)
1900 UINT WINAPI _lread( HFILE handle, LPVOID buffer, UINT count )
1902 DWORD result;
1903 if (!ReadFile( handle, buffer, count, &result, NULL )) return -1;
1904 return result;
1908 /***********************************************************************
1909 * _lread16 (KERNEL.82)
1911 UINT16 WINAPI _lread16( HFILE16 hFile, LPVOID buffer, UINT16 count )
1913 return (UINT16)_lread(DosFileHandleToWin32Handle(hFile), buffer, (LONG)count );
1917 /***********************************************************************
1918 * _lcreat (KERNEL.83)
1920 HFILE16 WINAPI _lcreat16( LPCSTR path, INT16 attr )
1922 return Win32HandleToDosFileHandle( _lcreat( path, attr ) );
1926 /***********************************************************************
1927 * _lcreat (KERNEL32.@)
1929 HFILE WINAPI _lcreat( LPCSTR path, INT attr )
1931 /* Mask off all flags not explicitly allowed by the doc */
1932 attr &= FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM;
1933 TRACE("%s %02x\n", path, attr );
1934 return CreateFileA( path, GENERIC_READ | GENERIC_WRITE,
1935 FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
1936 CREATE_ALWAYS, attr, 0 );
1940 /***********************************************************************
1941 * SetFilePointer (KERNEL32.@)
1943 DWORD WINAPI SetFilePointer( HANDLE hFile, LONG distance, LONG *highword,
1944 DWORD method )
1946 DWORD ret = 0xffffffff;
1948 TRACE("handle %d offset %ld high %ld origin %ld\n",
1949 hFile, distance, highword?*highword:0, method );
1951 SERVER_START_REQ( set_file_pointer )
1953 req->handle = hFile;
1954 req->low = distance;
1955 req->high = highword ? *highword : (distance >= 0) ? 0 : -1;
1956 /* FIXME: assumes 1:1 mapping between Windows and Unix seek constants */
1957 req->whence = method;
1958 SetLastError( 0 );
1959 if (!wine_server_call_err( req ))
1961 ret = reply->new_low;
1962 if (highword) *highword = reply->new_high;
1965 SERVER_END_REQ;
1966 return ret;
1970 /***********************************************************************
1971 * _llseek (KERNEL.84)
1973 * FIXME:
1974 * Seeking before the start of the file should be allowed for _llseek16,
1975 * but cause subsequent I/O operations to fail (cf. interrupt list)
1978 LONG WINAPI _llseek16( HFILE16 hFile, LONG lOffset, INT16 nOrigin )
1980 return SetFilePointer( DosFileHandleToWin32Handle(hFile), lOffset, NULL, nOrigin );
1984 /***********************************************************************
1985 * _llseek (KERNEL32.@)
1987 LONG WINAPI _llseek( HFILE hFile, LONG lOffset, INT nOrigin )
1989 return SetFilePointer( hFile, lOffset, NULL, nOrigin );
1993 /***********************************************************************
1994 * _lopen (KERNEL.85)
1996 HFILE16 WINAPI _lopen16( LPCSTR path, INT16 mode )
1998 return Win32HandleToDosFileHandle( _lopen( path, mode ) );
2002 /***********************************************************************
2003 * _lopen (KERNEL32.@)
2005 HFILE WINAPI _lopen( LPCSTR path, INT mode )
2007 DWORD access, sharing;
2009 TRACE("('%s',%04x)\n", path, mode );
2010 FILE_ConvertOFMode( mode, &access, &sharing );
2011 return CreateFileA( path, access, sharing, NULL, OPEN_EXISTING, 0, 0 );
2015 /***********************************************************************
2016 * _lwrite (KERNEL.86)
2018 UINT16 WINAPI _lwrite16( HFILE16 hFile, LPCSTR buffer, UINT16 count )
2020 return (UINT16)_hwrite( DosFileHandleToWin32Handle(hFile), buffer, (LONG)count );
2023 /***********************************************************************
2024 * _lwrite (KERNEL32.@)
2026 UINT WINAPI _lwrite( HFILE hFile, LPCSTR buffer, UINT count )
2028 return (UINT)_hwrite( hFile, buffer, (LONG)count );
2032 /***********************************************************************
2033 * _hread16 (KERNEL.349)
2035 LONG WINAPI _hread16( HFILE16 hFile, LPVOID buffer, LONG count)
2037 return _lread( DosFileHandleToWin32Handle(hFile), buffer, count );
2041 /***********************************************************************
2042 * _hread (KERNEL32.@)
2044 LONG WINAPI _hread( HFILE hFile, LPVOID buffer, LONG count)
2046 return _lread( hFile, buffer, count );
2050 /***********************************************************************
2051 * _hwrite (KERNEL.350)
2053 LONG WINAPI _hwrite16( HFILE16 hFile, LPCSTR buffer, LONG count )
2055 return _hwrite( DosFileHandleToWin32Handle(hFile), buffer, count );
2059 /***********************************************************************
2060 * _hwrite (KERNEL32.@)
2062 * experimentation yields that _lwrite:
2063 * o truncates the file at the current position with
2064 * a 0 len write
2065 * o returns 0 on a 0 length write
2066 * o works with console handles
2069 LONG WINAPI _hwrite( HFILE handle, LPCSTR buffer, LONG count )
2071 DWORD result;
2073 TRACE("%d %p %ld\n", handle, buffer, count );
2075 if (!count)
2077 /* Expand or truncate at current position */
2078 if (!SetEndOfFile( handle )) return HFILE_ERROR;
2079 return 0;
2081 if (!WriteFile( handle, buffer, count, &result, NULL ))
2082 return HFILE_ERROR;
2083 return result;
2087 /***********************************************************************
2088 * SetHandleCount (KERNEL.199)
2090 UINT16 WINAPI SetHandleCount16( UINT16 count )
2092 return SetHandleCount( count );
2096 /*************************************************************************
2097 * SetHandleCount (KERNEL32.@)
2099 UINT WINAPI SetHandleCount( UINT count )
2101 return min( 256, count );
2105 /***********************************************************************
2106 * FlushFileBuffers (KERNEL32.@)
2108 BOOL WINAPI FlushFileBuffers( HANDLE hFile )
2110 BOOL ret;
2111 SERVER_START_REQ( flush_file )
2113 req->handle = hFile;
2114 ret = !wine_server_call_err( req );
2116 SERVER_END_REQ;
2117 return ret;
2121 /**************************************************************************
2122 * SetEndOfFile (KERNEL32.@)
2124 BOOL WINAPI SetEndOfFile( HANDLE hFile )
2126 BOOL ret;
2127 SERVER_START_REQ( truncate_file )
2129 req->handle = hFile;
2130 ret = !wine_server_call_err( req );
2132 SERVER_END_REQ;
2133 return ret;
2137 /***********************************************************************
2138 * DeleteFile (KERNEL.146)
2140 BOOL16 WINAPI DeleteFile16( LPCSTR path )
2142 return DeleteFileA( path );
2146 /***********************************************************************
2147 * DeleteFileA (KERNEL32.@)
2149 BOOL WINAPI DeleteFileA( LPCSTR path )
2151 DOS_FULL_NAME full_name;
2153 if (!path)
2155 SetLastError(ERROR_INVALID_PARAMETER);
2156 return FALSE;
2158 TRACE("'%s'\n", path );
2160 if (!*path)
2162 ERR("Empty path passed\n");
2163 return FALSE;
2165 if (DOSFS_GetDevice( path ))
2167 WARN("cannot remove DOS device '%s'!\n", path);
2168 SetLastError( ERROR_FILE_NOT_FOUND );
2169 return FALSE;
2172 if (!DOSFS_GetFullName( path, TRUE, &full_name )) return FALSE;
2173 if (unlink( full_name.long_name ) == -1)
2175 FILE_SetDosError();
2176 return FALSE;
2178 return TRUE;
2182 /***********************************************************************
2183 * DeleteFileW (KERNEL32.@)
2185 BOOL WINAPI DeleteFileW( LPCWSTR path )
2187 LPSTR xpath = HEAP_strdupWtoA( GetProcessHeap(), 0, path );
2188 BOOL ret = DeleteFileA( xpath );
2189 HeapFree( GetProcessHeap(), 0, xpath );
2190 return ret;
2194 /***********************************************************************
2195 * GetFileType (KERNEL32.@)
2197 DWORD WINAPI GetFileType( HANDLE hFile )
2199 DWORD ret = FILE_TYPE_UNKNOWN;
2200 SERVER_START_REQ( get_file_info )
2202 req->handle = hFile;
2203 if (!wine_server_call_err( req )) ret = reply->type;
2205 SERVER_END_REQ;
2206 return ret;
2210 /* check if a file name is for an executable file (.exe or .com) */
2211 inline static BOOL is_executable( const char *name )
2213 int len = strlen(name);
2215 if (len < 4) return FALSE;
2216 return (!strcasecmp( name + len - 4, ".exe" ) ||
2217 !strcasecmp( name + len - 4, ".com" ));
2221 /***********************************************************************
2222 * FILE_AddBootRenameEntry
2224 * Adds an entry to the registry that is loaded when windows boots and
2225 * checks if there are some files to be removed or renamed/moved.
2226 * <fn1> has to be valid and <fn2> may be NULL. If both pointers are
2227 * non-NULL then the file is moved, otherwise it is deleted. The
2228 * entry of the registrykey is always appended with two zero
2229 * terminated strings. If <fn2> is NULL then the second entry is
2230 * simply a single 0-byte. Otherwise the second filename goes
2231 * there. The entries are prepended with \??\ before the path and the
2232 * second filename gets also a '!' as the first character if
2233 * MOVEFILE_REPLACE_EXISTING is set. After the final string another
2234 * 0-byte follows to indicate the end of the strings.
2235 * i.e.:
2236 * \??\D:\test\file1[0]
2237 * !\??\D:\test\file1_renamed[0]
2238 * \??\D:\Test|delete[0]
2239 * [0] <- file is to be deleted, second string empty
2240 * \??\D:\test\file2[0]
2241 * !\??\D:\test\file2_renamed[0]
2242 * [0] <- indicates end of strings
2244 * or:
2245 * \??\D:\test\file1[0]
2246 * !\??\D:\test\file1_renamed[0]
2247 * \??\D:\Test|delete[0]
2248 * [0] <- file is to be deleted, second string empty
2249 * [0] <- indicates end of strings
2252 static BOOL FILE_AddBootRenameEntry( const char *fn1, const char *fn2, DWORD flags )
2254 static const char PreString[] = "\\??\\";
2255 static const char ValueName[] = "PendingFileRenameOperations";
2257 BOOL rc = FALSE;
2258 HKEY Reboot = 0;
2259 DWORD Type, len1, len2, l;
2260 DWORD DataSize = 0;
2261 BYTE *Buffer = NULL;
2263 if(RegCreateKeyA(HKEY_LOCAL_MACHINE, "SYSTEM\\CurrentControlSet\\Control\\Session Manager",
2264 &Reboot) != ERROR_SUCCESS)
2266 WARN("Error creating key for reboot managment [%s]\n",
2267 "SYSTEM\\CurrentControlSet\\Control\\Session Manager");
2268 return FALSE;
2271 l = strlen(PreString);
2272 len1 = strlen(fn1) + l + 1;
2273 if (fn2)
2275 len2 = strlen(fn2) + l + 1;
2276 if (flags & MOVEFILE_REPLACE_EXISTING) len2++; /* Plus 1 because of the leading '!' */
2278 else len2 = 1; /* minimum is the 0 byte for the empty second string */
2280 /* First we check if the key exists and if so how many bytes it already contains. */
2281 if (RegQueryValueExA(Reboot, ValueName, NULL, &Type, NULL, &DataSize) == ERROR_SUCCESS)
2283 if (Type != REG_MULTI_SZ) goto Quit;
2284 if (!(Buffer = HeapAlloc( GetProcessHeap(), 0, DataSize + len1 + len2 + 1 ))) goto Quit;
2285 if (RegQueryValueExA(Reboot, ValueName, NULL, &Type, Buffer, &DataSize) != ERROR_SUCCESS)
2286 goto Quit;
2287 if (DataSize) DataSize--; /* remove terminating null (will be added back later) */
2289 else
2291 if (!(Buffer = HeapAlloc( GetProcessHeap(), 0, len1 + len2 + 1 ))) goto Quit;
2292 DataSize = 0;
2294 sprintf( Buffer + DataSize, "%s%s", PreString, fn1 );
2295 DataSize += len1;
2296 if (fn2)
2298 sprintf( Buffer + DataSize, "%s%s%s",
2299 (flags & MOVEFILE_REPLACE_EXISTING) ? "!" : "", PreString, fn2 );
2300 DataSize += len2;
2302 else Buffer[DataSize++] = 0;
2304 Buffer[DataSize++] = 0; /* add final null */
2305 rc = !RegSetValueExA( Reboot, ValueName, 0, REG_MULTI_SZ, Buffer, DataSize );
2307 Quit:
2308 if (Reboot) RegCloseKey(Reboot);
2309 if (Buffer) HeapFree( GetProcessHeap(), 0, Buffer );
2310 return(rc);
2314 /**************************************************************************
2315 * MoveFileExA (KERNEL32.@)
2317 BOOL WINAPI MoveFileExA( LPCSTR fn1, LPCSTR fn2, DWORD flag )
2319 DOS_FULL_NAME full_name1, full_name2;
2321 TRACE("(%s,%s,%04lx)\n", fn1, fn2, flag);
2323 /* FIXME: <Gerhard W. Gruber>sparhawk@gmx.at
2324 In case of W9x and lesser this function should return 120 (ERROR_CALL_NOT_IMPLEMENTED)
2325 to be really compatible. Most programs wont have any problems though. In case
2326 you encounter one, this is what you should return here. I don't know what's up
2327 with NT 3.5. Is this function available there or not?
2328 Does anybody really care about 3.5? :)
2331 /* Filename1 has to be always set to a valid path. Filename2 may be NULL
2332 if the source file has to be deleted.
2334 if (!fn1) {
2335 SetLastError(ERROR_INVALID_PARAMETER);
2336 return FALSE;
2339 /* This function has to be run through in order to process the name properly.
2340 If the BOOTDELAY flag is set, the file doesn't need to exist though. At least
2341 that is the behaviour on NT 4.0. The operation accepts the filenames as
2342 they are given but it can't reply with a reasonable returncode. Success
2343 means in that case success for entering the values into the registry.
2345 if(!DOSFS_GetFullName( fn1, TRUE, &full_name1 ))
2347 if(!(flag & MOVEFILE_DELAY_UNTIL_REBOOT))
2348 return FALSE;
2351 if (fn2) /* !fn2 means delete fn1 */
2353 if (DOSFS_GetFullName( fn2, TRUE, &full_name2 ))
2355 if(!(flag & MOVEFILE_DELAY_UNTIL_REBOOT))
2357 /* target exists, check if we may overwrite */
2358 if (!(flag & MOVEFILE_REPLACE_EXISTING))
2360 /* FIXME: Use right error code */
2361 SetLastError( ERROR_ACCESS_DENIED );
2362 return FALSE;
2366 else
2368 if (!DOSFS_GetFullName( fn2, FALSE, &full_name2 ))
2370 if(!(flag & MOVEFILE_DELAY_UNTIL_REBOOT))
2371 return FALSE;
2375 /* Source name and target path are valid */
2377 if (flag & MOVEFILE_DELAY_UNTIL_REBOOT)
2379 /* FIXME: (bon@elektron.ikp.physik.th-darmstadt.de 970706)
2380 Perhaps we should queue these command and execute it
2381 when exiting... What about using on_exit(2)
2383 FIXME("Please move existing file '%s' to file '%s' when Wine has finished\n",
2384 fn1, fn2);
2385 return FILE_AddBootRenameEntry( fn1, fn2, flag );
2388 if (full_name1.drive != full_name2.drive)
2390 /* use copy, if allowed */
2391 if (!(flag & MOVEFILE_COPY_ALLOWED))
2393 /* FIXME: Use right error code */
2394 SetLastError( ERROR_FILE_EXISTS );
2395 return FALSE;
2397 return CopyFileA( fn1, fn2, !(flag & MOVEFILE_REPLACE_EXISTING) );
2399 if (rename( full_name1.long_name, full_name2.long_name ) == -1)
2401 FILE_SetDosError();
2402 return FALSE;
2404 if (is_executable( full_name1.long_name ) != is_executable( full_name2.long_name ))
2406 struct stat fstat;
2407 if (stat( full_name2.long_name, &fstat ) != -1)
2409 if (is_executable( full_name2.long_name ))
2410 /* set executable bit where read bit is set */
2411 fstat.st_mode |= (fstat.st_mode & 0444) >> 2;
2412 else
2413 fstat.st_mode &= ~0111;
2414 chmod( full_name2.long_name, fstat.st_mode );
2417 return TRUE;
2419 else /* fn2 == NULL means delete source */
2421 if (flag & MOVEFILE_DELAY_UNTIL_REBOOT)
2423 if (flag & MOVEFILE_COPY_ALLOWED) {
2424 WARN("Illegal flag\n");
2425 SetLastError( ERROR_GEN_FAILURE );
2426 return FALSE;
2428 /* FIXME: (bon@elektron.ikp.physik.th-darmstadt.de 970706)
2429 Perhaps we should queue these command and execute it
2430 when exiting... What about using on_exit(2)
2432 FIXME("Please delete file '%s' when Wine has finished\n", fn1);
2433 return FILE_AddBootRenameEntry( fn1, NULL, flag );
2436 if (unlink( full_name1.long_name ) == -1)
2438 FILE_SetDosError();
2439 return FALSE;
2441 return TRUE; /* successfully deleted */
2445 /**************************************************************************
2446 * MoveFileExW (KERNEL32.@)
2448 BOOL WINAPI MoveFileExW( LPCWSTR fn1, LPCWSTR fn2, DWORD flag )
2450 LPSTR afn1 = HEAP_strdupWtoA( GetProcessHeap(), 0, fn1 );
2451 LPSTR afn2 = HEAP_strdupWtoA( GetProcessHeap(), 0, fn2 );
2452 BOOL res = MoveFileExA( afn1, afn2, flag );
2453 HeapFree( GetProcessHeap(), 0, afn1 );
2454 HeapFree( GetProcessHeap(), 0, afn2 );
2455 return res;
2459 /**************************************************************************
2460 * MoveFileA (KERNEL32.@)
2462 * Move file or directory
2464 BOOL WINAPI MoveFileA( LPCSTR fn1, LPCSTR fn2 )
2466 DOS_FULL_NAME full_name1, full_name2;
2467 struct stat fstat;
2469 TRACE("(%s,%s)\n", fn1, fn2 );
2471 if (!DOSFS_GetFullName( fn1, TRUE, &full_name1 )) return FALSE;
2472 if (DOSFS_GetFullName( fn2, TRUE, &full_name2 )) {
2473 /* The new name must not already exist */
2474 SetLastError(ERROR_ALREADY_EXISTS);
2475 return FALSE;
2477 if (!DOSFS_GetFullName( fn2, FALSE, &full_name2 )) return FALSE;
2479 if (full_name1.drive == full_name2.drive) /* move */
2480 return MoveFileExA( fn1, fn2, MOVEFILE_COPY_ALLOWED );
2482 /* copy */
2483 if (stat( full_name1.long_name, &fstat ))
2485 WARN("Invalid source file %s\n",
2486 full_name1.long_name);
2487 FILE_SetDosError();
2488 return FALSE;
2490 if (S_ISDIR(fstat.st_mode)) {
2491 /* No Move for directories across file systems */
2492 /* FIXME: Use right error code */
2493 SetLastError( ERROR_GEN_FAILURE );
2494 return FALSE;
2496 return CopyFileA(fn1, fn2, TRUE); /*fail, if exist */
2500 /**************************************************************************
2501 * MoveFileW (KERNEL32.@)
2503 BOOL WINAPI MoveFileW( LPCWSTR fn1, LPCWSTR fn2 )
2505 LPSTR afn1 = HEAP_strdupWtoA( GetProcessHeap(), 0, fn1 );
2506 LPSTR afn2 = HEAP_strdupWtoA( GetProcessHeap(), 0, fn2 );
2507 BOOL res = MoveFileA( afn1, afn2 );
2508 HeapFree( GetProcessHeap(), 0, afn1 );
2509 HeapFree( GetProcessHeap(), 0, afn2 );
2510 return res;
2514 /**************************************************************************
2515 * CopyFileA (KERNEL32.@)
2517 BOOL WINAPI CopyFileA( LPCSTR source, LPCSTR dest, BOOL fail_if_exists )
2519 HFILE h1, h2;
2520 BY_HANDLE_FILE_INFORMATION info;
2521 UINT count;
2522 BOOL ret = FALSE;
2523 int mode;
2524 char buffer[2048];
2526 if ((h1 = _lopen( source, OF_READ )) == HFILE_ERROR) return FALSE;
2527 if (!GetFileInformationByHandle( h1, &info ))
2529 CloseHandle( h1 );
2530 return FALSE;
2532 mode = (info.dwFileAttributes & FILE_ATTRIBUTE_READONLY) ? 0444 : 0666;
2533 if ((h2 = CreateFileA( dest, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
2534 fail_if_exists ? CREATE_NEW : CREATE_ALWAYS,
2535 info.dwFileAttributes, h1 )) == INVALID_HANDLE_VALUE)
2537 CloseHandle( h1 );
2538 return FALSE;
2540 while ((count = _lread( h1, buffer, sizeof(buffer) )) > 0)
2542 char *p = buffer;
2543 while (count > 0)
2545 INT res = _lwrite( h2, p, count );
2546 if (res <= 0) goto done;
2547 p += res;
2548 count -= res;
2551 ret = TRUE;
2552 done:
2553 CloseHandle( h1 );
2554 CloseHandle( h2 );
2555 return ret;
2559 /**************************************************************************
2560 * CopyFileW (KERNEL32.@)
2562 BOOL WINAPI CopyFileW( LPCWSTR source, LPCWSTR dest, BOOL fail_if_exists)
2564 LPSTR sourceA = HEAP_strdupWtoA( GetProcessHeap(), 0, source );
2565 LPSTR destA = HEAP_strdupWtoA( GetProcessHeap(), 0, dest );
2566 BOOL ret = CopyFileA( sourceA, destA, fail_if_exists );
2567 HeapFree( GetProcessHeap(), 0, sourceA );
2568 HeapFree( GetProcessHeap(), 0, destA );
2569 return ret;
2573 /**************************************************************************
2574 * CopyFileExA (KERNEL32.@)
2576 * This implementation ignores most of the extra parameters passed-in into
2577 * the "ex" version of the method and calls the CopyFile method.
2578 * It will have to be fixed eventually.
2580 BOOL WINAPI CopyFileExA(LPCSTR sourceFilename,
2581 LPCSTR destFilename,
2582 LPPROGRESS_ROUTINE progressRoutine,
2583 LPVOID appData,
2584 LPBOOL cancelFlagPointer,
2585 DWORD copyFlags)
2587 BOOL failIfExists = FALSE;
2590 * Interpret the only flag that CopyFile can interpret.
2592 if ( (copyFlags & COPY_FILE_FAIL_IF_EXISTS) != 0)
2594 failIfExists = TRUE;
2597 return CopyFileA(sourceFilename, destFilename, failIfExists);
2600 /**************************************************************************
2601 * CopyFileExW (KERNEL32.@)
2603 BOOL WINAPI CopyFileExW(LPCWSTR sourceFilename,
2604 LPCWSTR destFilename,
2605 LPPROGRESS_ROUTINE progressRoutine,
2606 LPVOID appData,
2607 LPBOOL cancelFlagPointer,
2608 DWORD copyFlags)
2610 LPSTR sourceA = HEAP_strdupWtoA( GetProcessHeap(), 0, sourceFilename );
2611 LPSTR destA = HEAP_strdupWtoA( GetProcessHeap(), 0, destFilename );
2613 BOOL ret = CopyFileExA(sourceA,
2614 destA,
2615 progressRoutine,
2616 appData,
2617 cancelFlagPointer,
2618 copyFlags);
2620 HeapFree( GetProcessHeap(), 0, sourceA );
2621 HeapFree( GetProcessHeap(), 0, destA );
2623 return ret;
2627 /***********************************************************************
2628 * SetFileTime (KERNEL32.@)
2630 BOOL WINAPI SetFileTime( HANDLE hFile,
2631 const FILETIME *lpCreationTime,
2632 const FILETIME *lpLastAccessTime,
2633 const FILETIME *lpLastWriteTime )
2635 BOOL ret;
2636 SERVER_START_REQ( set_file_time )
2638 req->handle = hFile;
2639 if (lpLastAccessTime)
2640 RtlTimeToSecondsSince1970( lpLastAccessTime, (DWORD *)&req->access_time );
2641 else
2642 req->access_time = 0; /* FIXME */
2643 if (lpLastWriteTime)
2644 RtlTimeToSecondsSince1970( lpLastWriteTime, (DWORD *)&req->write_time );
2645 else
2646 req->write_time = 0; /* FIXME */
2647 ret = !wine_server_call_err( req );
2649 SERVER_END_REQ;
2650 return ret;
2654 /**************************************************************************
2655 * LockFile (KERNEL32.@)
2657 BOOL WINAPI LockFile( HANDLE hFile, DWORD dwFileOffsetLow, DWORD dwFileOffsetHigh,
2658 DWORD nNumberOfBytesToLockLow, DWORD nNumberOfBytesToLockHigh )
2660 BOOL ret;
2661 SERVER_START_REQ( lock_file )
2663 req->handle = hFile;
2664 req->offset_low = dwFileOffsetLow;
2665 req->offset_high = dwFileOffsetHigh;
2666 req->count_low = nNumberOfBytesToLockLow;
2667 req->count_high = nNumberOfBytesToLockHigh;
2668 ret = !wine_server_call_err( req );
2670 SERVER_END_REQ;
2671 return ret;
2674 /**************************************************************************
2675 * LockFileEx [KERNEL32.@]
2677 * Locks a byte range within an open file for shared or exclusive access.
2679 * RETURNS
2680 * success: TRUE
2681 * failure: FALSE
2683 * NOTES
2684 * Per Microsoft docs, the third parameter (reserved) must be set to 0.
2686 BOOL WINAPI LockFileEx( HANDLE hFile, DWORD flags, DWORD reserved,
2687 DWORD nNumberOfBytesToLockLow, DWORD nNumberOfBytesToLockHigh,
2688 LPOVERLAPPED pOverlapped )
2690 FIXME("hFile=%d,flags=%ld,reserved=%ld,lowbytes=%ld,highbytes=%ld,overlapped=%p: stub.\n",
2691 hFile, flags, reserved, nNumberOfBytesToLockLow, nNumberOfBytesToLockHigh,
2692 pOverlapped);
2693 if (reserved == 0)
2694 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
2695 else
2697 ERR("reserved == %ld: Supposed to be 0??\n", reserved);
2698 SetLastError(ERROR_INVALID_PARAMETER);
2701 return FALSE;
2705 /**************************************************************************
2706 * UnlockFile (KERNEL32.@)
2708 BOOL WINAPI UnlockFile( HANDLE hFile, DWORD dwFileOffsetLow, DWORD dwFileOffsetHigh,
2709 DWORD nNumberOfBytesToUnlockLow, DWORD nNumberOfBytesToUnlockHigh )
2711 BOOL ret;
2712 SERVER_START_REQ( unlock_file )
2714 req->handle = hFile;
2715 req->offset_low = dwFileOffsetLow;
2716 req->offset_high = dwFileOffsetHigh;
2717 req->count_low = nNumberOfBytesToUnlockLow;
2718 req->count_high = nNumberOfBytesToUnlockHigh;
2719 ret = !wine_server_call_err( req );
2721 SERVER_END_REQ;
2722 return ret;
2726 /**************************************************************************
2727 * UnlockFileEx (KERNEL32.@)
2729 BOOL WINAPI UnlockFileEx(
2730 HFILE hFile,
2731 DWORD dwReserved,
2732 DWORD nNumberOfBytesToUnlockLow,
2733 DWORD nNumberOfBytesToUnlockHigh,
2734 LPOVERLAPPED lpOverlapped
2737 FIXME("hFile=%d,reserved=%ld,lowbytes=%ld,highbytes=%ld,overlapped=%p: stub.\n",
2738 hFile, dwReserved, nNumberOfBytesToUnlockLow, nNumberOfBytesToUnlockHigh,
2739 lpOverlapped);
2740 if (dwReserved == 0)
2741 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
2742 else
2744 ERR("reserved == %ld: Supposed to be 0??\n", dwReserved);
2745 SetLastError(ERROR_INVALID_PARAMETER);
2748 return FALSE;
2752 #if 0
2754 struct DOS_FILE_LOCK {
2755 struct DOS_FILE_LOCK * next;
2756 DWORD base;
2757 DWORD len;
2758 DWORD processId;
2759 FILE_OBJECT * dos_file;
2760 /* char * unix_name;*/
2763 typedef struct DOS_FILE_LOCK DOS_FILE_LOCK;
2765 static DOS_FILE_LOCK *locks = NULL;
2766 static void DOS_RemoveFileLocks(FILE_OBJECT *file);
2769 /* Locks need to be mirrored because unix file locking is based
2770 * on the pid. Inside of wine there can be multiple WINE processes
2771 * that share the same unix pid.
2772 * Read's and writes should check these locks also - not sure
2773 * how critical that is at this point (FIXME).
2776 static BOOL DOS_AddLock(FILE_OBJECT *file, struct flock *f)
2778 DOS_FILE_LOCK *curr;
2779 DWORD processId;
2781 processId = GetCurrentProcessId();
2783 /* check if lock overlaps a current lock for the same file */
2784 #if 0
2785 for (curr = locks; curr; curr = curr->next) {
2786 if (strcmp(curr->unix_name, file->unix_name) == 0) {
2787 if ((f->l_start == curr->base) && (f->l_len == curr->len))
2788 return TRUE;/* region is identic */
2789 if ((f->l_start < (curr->base + curr->len)) &&
2790 ((f->l_start + f->l_len) > curr->base)) {
2791 /* region overlaps */
2792 return FALSE;
2796 #endif
2798 curr = HeapAlloc( GetProcessHeap(), 0, sizeof(DOS_FILE_LOCK) );
2799 curr->processId = GetCurrentProcessId();
2800 curr->base = f->l_start;
2801 curr->len = f->l_len;
2802 /* curr->unix_name = HEAP_strdupA( GetProcessHeap(), 0, file->unix_name);*/
2803 curr->next = locks;
2804 curr->dos_file = file;
2805 locks = curr;
2806 return TRUE;
2809 static void DOS_RemoveFileLocks(FILE_OBJECT *file)
2811 DWORD processId;
2812 DOS_FILE_LOCK **curr;
2813 DOS_FILE_LOCK *rem;
2815 processId = GetCurrentProcessId();
2816 curr = &locks;
2817 while (*curr) {
2818 if ((*curr)->dos_file == file) {
2819 rem = *curr;
2820 *curr = (*curr)->next;
2821 /* HeapFree( GetProcessHeap(), 0, rem->unix_name );*/
2822 HeapFree( GetProcessHeap(), 0, rem );
2824 else
2825 curr = &(*curr)->next;
2829 static BOOL DOS_RemoveLock(FILE_OBJECT *file, struct flock *f)
2831 DWORD processId;
2832 DOS_FILE_LOCK **curr;
2833 DOS_FILE_LOCK *rem;
2835 processId = GetCurrentProcessId();
2836 for (curr = &locks; *curr; curr = &(*curr)->next) {
2837 if ((*curr)->processId == processId &&
2838 (*curr)->dos_file == file &&
2839 (*curr)->base == f->l_start &&
2840 (*curr)->len == f->l_len) {
2841 /* this is the same lock */
2842 rem = *curr;
2843 *curr = (*curr)->next;
2844 /* HeapFree( GetProcessHeap(), 0, rem->unix_name );*/
2845 HeapFree( GetProcessHeap(), 0, rem );
2846 return TRUE;
2849 /* no matching lock found */
2850 return FALSE;
2854 /**************************************************************************
2855 * LockFile (KERNEL32.@)
2857 BOOL WINAPI LockFile(
2858 HFILE hFile,DWORD dwFileOffsetLow,DWORD dwFileOffsetHigh,
2859 DWORD nNumberOfBytesToLockLow,DWORD nNumberOfBytesToLockHigh )
2861 struct flock f;
2862 FILE_OBJECT *file;
2864 TRACE("handle %d offsetlow=%ld offsethigh=%ld nbyteslow=%ld nbyteshigh=%ld\n",
2865 hFile, dwFileOffsetLow, dwFileOffsetHigh,
2866 nNumberOfBytesToLockLow, nNumberOfBytesToLockHigh);
2868 if (dwFileOffsetHigh || nNumberOfBytesToLockHigh) {
2869 FIXME("Unimplemented bytes > 32bits\n");
2870 return FALSE;
2873 f.l_start = dwFileOffsetLow;
2874 f.l_len = nNumberOfBytesToLockLow;
2875 f.l_whence = SEEK_SET;
2876 f.l_pid = 0;
2877 f.l_type = F_WRLCK;
2879 if (!(file = FILE_GetFile(hFile,0,NULL))) return FALSE;
2881 /* shadow locks internally */
2882 if (!DOS_AddLock(file, &f)) {
2883 SetLastError( ERROR_LOCK_VIOLATION );
2884 return FALSE;
2887 /* FIXME: Unix locking commented out for now, doesn't work with Excel */
2888 #ifdef USE_UNIX_LOCKS
2889 if (fcntl(file->unix_handle, F_SETLK, &f) == -1) {
2890 if (errno == EACCES || errno == EAGAIN) {
2891 SetLastError( ERROR_LOCK_VIOLATION );
2893 else {
2894 FILE_SetDosError();
2896 /* remove our internal copy of the lock */
2897 DOS_RemoveLock(file, &f);
2898 return FALSE;
2900 #endif
2901 return TRUE;
2905 /**************************************************************************
2906 * UnlockFile (KERNEL32.@)
2908 BOOL WINAPI UnlockFile(
2909 HFILE hFile,DWORD dwFileOffsetLow,DWORD dwFileOffsetHigh,
2910 DWORD nNumberOfBytesToUnlockLow,DWORD nNumberOfBytesToUnlockHigh )
2912 FILE_OBJECT *file;
2913 struct flock f;
2915 TRACE("handle %d offsetlow=%ld offsethigh=%ld nbyteslow=%ld nbyteshigh=%ld\n",
2916 hFile, dwFileOffsetLow, dwFileOffsetHigh,
2917 nNumberOfBytesToUnlockLow, nNumberOfBytesToUnlockHigh);
2919 if (dwFileOffsetHigh || nNumberOfBytesToUnlockHigh) {
2920 WARN("Unimplemented bytes > 32bits\n");
2921 return FALSE;
2924 f.l_start = dwFileOffsetLow;
2925 f.l_len = nNumberOfBytesToUnlockLow;
2926 f.l_whence = SEEK_SET;
2927 f.l_pid = 0;
2928 f.l_type = F_UNLCK;
2930 if (!(file = FILE_GetFile(hFile,0,NULL))) return FALSE;
2932 DOS_RemoveLock(file, &f); /* ok if fails - may be another wine */
2934 /* FIXME: Unix locking commented out for now, doesn't work with Excel */
2935 #ifdef USE_UNIX_LOCKS
2936 if (fcntl(file->unix_handle, F_SETLK, &f) == -1) {
2937 FILE_SetDosError();
2938 return FALSE;
2940 #endif
2941 return TRUE;
2943 #endif
2945 /**************************************************************************
2946 * GetFileAttributesExA [KERNEL32.@]
2948 BOOL WINAPI GetFileAttributesExA(
2949 LPCSTR lpFileName, GET_FILEEX_INFO_LEVELS fInfoLevelId,
2950 LPVOID lpFileInformation)
2952 DOS_FULL_NAME full_name;
2953 BY_HANDLE_FILE_INFORMATION info;
2955 if (lpFileName == NULL) return FALSE;
2956 if (lpFileInformation == NULL) return FALSE;
2958 if (fInfoLevelId == GetFileExInfoStandard) {
2959 LPWIN32_FILE_ATTRIBUTE_DATA lpFad =
2960 (LPWIN32_FILE_ATTRIBUTE_DATA) lpFileInformation;
2961 if (!DOSFS_GetFullName( lpFileName, TRUE, &full_name )) return FALSE;
2962 if (!FILE_Stat( full_name.long_name, &info )) return FALSE;
2964 lpFad->dwFileAttributes = info.dwFileAttributes;
2965 lpFad->ftCreationTime = info.ftCreationTime;
2966 lpFad->ftLastAccessTime = info.ftLastAccessTime;
2967 lpFad->ftLastWriteTime = info.ftLastWriteTime;
2968 lpFad->nFileSizeHigh = info.nFileSizeHigh;
2969 lpFad->nFileSizeLow = info.nFileSizeLow;
2971 else {
2972 FIXME("invalid info level %d!\n", fInfoLevelId);
2973 return FALSE;
2976 return TRUE;
2980 /**************************************************************************
2981 * GetFileAttributesExW [KERNEL32.@]
2983 BOOL WINAPI GetFileAttributesExW(
2984 LPCWSTR lpFileName, GET_FILEEX_INFO_LEVELS fInfoLevelId,
2985 LPVOID lpFileInformation)
2987 LPSTR nameA = HEAP_strdupWtoA( GetProcessHeap(), 0, lpFileName );
2988 BOOL res =
2989 GetFileAttributesExA( nameA, fInfoLevelId, lpFileInformation);
2990 HeapFree( GetProcessHeap(), 0, nameA );
2991 return res;