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