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