Fix stupid clone of broken macro, found by Marcus.
[wine/multimedia.git] / files / file.c
blobc04b33de1731c752ee6428d95402b5f977781b2f
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 "winternl.h"
62 #include "wine/winbase16.h"
63 #include "wine/server.h"
65 #include "drive.h"
66 #include "file.h"
67 #include "async.h"
68 #include "heap.h"
69 #include "msdos.h"
70 #include "wincon.h"
72 #include "smb.h"
73 #include "wine/unicode.h"
74 #include "wine/debug.h"
76 WINE_DEFAULT_DEBUG_CHANNEL(file);
78 #if defined(MAP_ANONYMOUS) && !defined(MAP_ANON)
79 #define MAP_ANON MAP_ANONYMOUS
80 #endif
82 /* Size of per-process table of DOS handles */
83 #define DOS_TABLE_SIZE 256
85 /* Macro to derive file offset from OVERLAPPED struct */
86 #define OVERLAPPED_OFFSET(overlapped) ((off_t) (overlapped)->Offset + ((off_t) (overlapped)->OffsetHigh << 32))
88 static HANDLE dos_handles[DOS_TABLE_SIZE];
90 mode_t FILE_umask;
92 extern HANDLE WINAPI FILE_SmbOpen(LPCSTR name);
94 /***********************************************************************
95 * Asynchronous file I/O *
97 static DWORD fileio_get_async_status (const async_private *ovp);
98 static DWORD fileio_get_async_count (const async_private *ovp);
99 static void fileio_set_async_status (async_private *ovp, const DWORD status);
100 static void CALLBACK fileio_call_completion_func (ULONG_PTR data);
101 static void fileio_async_cleanup (async_private *ovp);
103 static async_ops fileio_async_ops =
105 fileio_get_async_status, /* get_status */
106 fileio_set_async_status, /* set_status */
107 fileio_get_async_count, /* get_count */
108 fileio_call_completion_func, /* call_completion */
109 fileio_async_cleanup /* cleanup */
112 static async_ops fileio_nocomp_async_ops =
114 fileio_get_async_status, /* get_status */
115 fileio_set_async_status, /* set_status */
116 fileio_get_async_count, /* get_count */
117 NULL, /* call_completion */
118 fileio_async_cleanup /* cleanup */
121 typedef struct async_fileio
123 struct async_private async;
124 LPOVERLAPPED lpOverlapped;
125 LPOVERLAPPED_COMPLETION_ROUTINE completion_func;
126 char *buffer;
127 unsigned int count;
128 enum fd_type fd_type;
129 } async_fileio;
131 static DWORD fileio_get_async_status (const struct async_private *ovp)
133 return ((async_fileio*) ovp)->lpOverlapped->Internal;
136 static void fileio_set_async_status (async_private *ovp, const DWORD status)
138 ((async_fileio*) ovp)->lpOverlapped->Internal = status;
141 static DWORD fileio_get_async_count (const struct async_private *ovp)
143 async_fileio *fileio = (async_fileio*) ovp;
145 if (fileio->count < fileio->lpOverlapped->InternalHigh)
146 return 0;
147 return fileio->count - fileio->lpOverlapped->InternalHigh;
150 static void CALLBACK fileio_call_completion_func (ULONG_PTR data)
152 async_fileio *ovp = (async_fileio*) data;
153 TRACE ("data: %p\n", ovp);
155 ovp->completion_func( ovp->lpOverlapped->Internal,
156 ovp->lpOverlapped->InternalHigh,
157 ovp->lpOverlapped );
159 fileio_async_cleanup ( &ovp->async );
162 static void fileio_async_cleanup ( struct async_private *ovp )
164 HeapFree ( GetProcessHeap(), 0, ovp );
167 /***********************************************************************
168 * FILE_ConvertOFMode
170 * Convert OF_* mode into flags for CreateFile.
172 static void FILE_ConvertOFMode( INT mode, DWORD *access, DWORD *sharing )
174 switch(mode & 0x03)
176 case OF_READ: *access = GENERIC_READ; break;
177 case OF_WRITE: *access = GENERIC_WRITE; break;
178 case OF_READWRITE: *access = GENERIC_READ | GENERIC_WRITE; break;
179 default: *access = 0; break;
181 switch(mode & 0x70)
183 case OF_SHARE_EXCLUSIVE: *sharing = 0; break;
184 case OF_SHARE_DENY_WRITE: *sharing = FILE_SHARE_READ; break;
185 case OF_SHARE_DENY_READ: *sharing = FILE_SHARE_WRITE; break;
186 case OF_SHARE_DENY_NONE:
187 case OF_SHARE_COMPAT:
188 default: *sharing = FILE_SHARE_READ | FILE_SHARE_WRITE; break;
193 /***********************************************************************
194 * FILE_strcasecmp
196 * locale-independent case conversion for file I/O
198 int FILE_strcasecmp( const char *str1, const char *str2 )
200 int ret = 0;
201 for ( ; ; str1++, str2++)
202 if ((ret = FILE_toupper(*str1) - FILE_toupper(*str2)) || !*str1) break;
203 return ret;
207 /***********************************************************************
208 * FILE_strncasecmp
210 * locale-independent case conversion for file I/O
212 int FILE_strncasecmp( const char *str1, const char *str2, int len )
214 int ret = 0;
215 for ( ; len > 0; len--, str1++, str2++)
216 if ((ret = FILE_toupper(*str1) - FILE_toupper(*str2)) || !*str1) break;
217 return ret;
221 /***********************************************************************
222 * FILE_GetNtStatus(void)
224 * Retrieve the Nt Status code from errno.
225 * Try to be consistent with FILE_SetDosError().
227 DWORD FILE_GetNtStatus(void)
229 int err = errno;
230 DWORD nt;
231 TRACE ( "errno = %d\n", errno );
232 switch ( err )
234 case EAGAIN: nt = STATUS_SHARING_VIOLATION; break;
235 case EBADF: nt = STATUS_INVALID_HANDLE; break;
236 case ENOSPC: nt = STATUS_DISK_FULL; break;
237 case EPERM:
238 case EROFS:
239 case EACCES: nt = STATUS_ACCESS_DENIED; break;
240 case ENOENT: nt = STATUS_SHARING_VIOLATION; break;
241 case EISDIR: nt = STATUS_FILE_IS_A_DIRECTORY; break;
242 case EMFILE:
243 case ENFILE: nt = STATUS_NO_MORE_FILES; break;
244 case EINVAL:
245 case ENOTEMPTY: nt = STATUS_DIRECTORY_NOT_EMPTY; break;
246 case EPIPE: nt = STATUS_PIPE_BROKEN; break;
247 case ENOEXEC: /* ?? */
248 case ESPIPE: /* ?? */
249 case EEXIST: /* ?? */
250 default:
251 FIXME ( "Converting errno %d to STATUS_UNSUCCESSFUL\n", err );
252 nt = STATUS_UNSUCCESSFUL;
254 return nt;
257 /***********************************************************************
258 * FILE_SetDosError
260 * Set the DOS error code from errno.
262 void FILE_SetDosError(void)
264 int save_errno = errno; /* errno gets overwritten by printf */
266 TRACE("errno = %d %s\n", errno, strerror(errno));
267 switch (save_errno)
269 case EAGAIN:
270 SetLastError( ERROR_SHARING_VIOLATION );
271 break;
272 case EBADF:
273 SetLastError( ERROR_INVALID_HANDLE );
274 break;
275 case ENOSPC:
276 SetLastError( ERROR_HANDLE_DISK_FULL );
277 break;
278 case EACCES:
279 case EPERM:
280 case EROFS:
281 SetLastError( ERROR_ACCESS_DENIED );
282 break;
283 case EBUSY:
284 SetLastError( ERROR_LOCK_VIOLATION );
285 break;
286 case ENOENT:
287 SetLastError( ERROR_FILE_NOT_FOUND );
288 break;
289 case EISDIR:
290 SetLastError( ERROR_CANNOT_MAKE );
291 break;
292 case ENFILE:
293 case EMFILE:
294 SetLastError( ERROR_NO_MORE_FILES );
295 break;
296 case EEXIST:
297 SetLastError( ERROR_FILE_EXISTS );
298 break;
299 case EINVAL:
300 case ESPIPE:
301 SetLastError( ERROR_SEEK );
302 break;
303 case ENOTEMPTY:
304 SetLastError( ERROR_DIR_NOT_EMPTY );
305 break;
306 case ENOEXEC:
307 SetLastError( ERROR_BAD_FORMAT );
308 break;
309 default:
310 WARN("unknown file error: %s\n", strerror(save_errno) );
311 SetLastError( ERROR_GEN_FAILURE );
312 break;
314 errno = save_errno;
318 /***********************************************************************
319 * FILE_GetUnixHandleType
321 * Retrieve the Unix handle corresponding to a file handle.
322 * Returns -1 on failure.
324 static int FILE_GetUnixHandleType( HANDLE handle, DWORD access, enum fd_type *type, int *flags_ptr )
326 int ret, flags, fd = -1;
328 ret = wine_server_handle_to_fd( handle, access, &fd, type, &flags );
329 if (flags_ptr) *flags_ptr = flags;
330 if (ret) SetLastError( RtlNtStatusToDosError(ret) );
331 else if (((access & GENERIC_READ) && (flags & FD_FLAG_RECV_SHUTDOWN)) ||
332 ((access & GENERIC_WRITE) && (flags & FD_FLAG_SEND_SHUTDOWN)))
334 close (fd);
335 SetLastError ( ERROR_PIPE_NOT_CONNECTED );
336 return -1;
338 return fd;
341 /***********************************************************************
342 * FILE_GetUnixHandle
344 * Retrieve the Unix handle corresponding to a file handle.
345 * Returns -1 on failure.
347 int FILE_GetUnixHandle( HANDLE handle, DWORD access )
349 return FILE_GetUnixHandleType( handle, access, NULL, NULL );
352 /*************************************************************************
353 * FILE_OpenConsole
355 * Open a handle to the current process console.
356 * Returns 0 on failure.
358 static HANDLE FILE_OpenConsole( BOOL output, DWORD access, DWORD sharing, LPSECURITY_ATTRIBUTES sa )
360 HANDLE ret;
362 SERVER_START_REQ( open_console )
364 req->from = output;
365 req->access = access;
366 req->share = sharing;
367 req->inherit = (sa && (sa->nLength>=sizeof(*sa)) && sa->bInheritHandle);
368 SetLastError(0);
369 wine_server_call_err( req );
370 ret = reply->handle;
372 SERVER_END_REQ;
373 return ret;
376 /* FIXME: those routines defined as pointers are needed, because this file is
377 * currently compiled into NTDLL whereas it belongs to kernel32.
378 * this shall go away once all the DLL separation process is done
380 typedef BOOL (WINAPI* pRW)(HANDLE, const void*, DWORD, DWORD*, void*);
382 static BOOL FILE_ReadConsole(HANDLE hCon, void* buf, DWORD nb, DWORD* nr, void* p)
384 static HANDLE hKernel /* = 0 */;
385 static pRW pReadConsole /* = 0 */;
387 if ((!hKernel && !(hKernel = LoadLibraryA("kernel32"))) ||
388 (!pReadConsole &&
389 !(pReadConsole = GetProcAddress(hKernel, "ReadConsoleA"))))
391 *nr = 0;
392 return 0;
394 return (pReadConsole)(hCon, buf, nb, nr, p);
397 static BOOL FILE_WriteConsole(HANDLE hCon, const void* buf, DWORD nb, DWORD* nr, void* p)
399 static HANDLE hKernel /* = 0 */;
400 static pRW pWriteConsole /* = 0 */;
402 if ((!hKernel && !(hKernel = LoadLibraryA("kernel32"))) ||
403 (!pWriteConsole &&
404 !(pWriteConsole = GetProcAddress(hKernel, "WriteConsoleA"))))
406 *nr = 0;
407 return 0;
409 return (pWriteConsole)(hCon, buf, nb, nr, p);
411 /* end of FIXME */
413 /***********************************************************************
414 * FILE_CreateFile
416 * Implementation of CreateFile. Takes a Unix path name.
417 * Returns 0 on failure.
419 HANDLE FILE_CreateFile( LPCSTR filename, DWORD access, DWORD sharing,
420 LPSECURITY_ATTRIBUTES sa, DWORD creation,
421 DWORD attributes, HANDLE template, BOOL fail_read_only,
422 UINT drive_type )
424 unsigned int err;
425 HANDLE ret;
427 for (;;)
429 SERVER_START_REQ( create_file )
431 req->access = access;
432 req->inherit = (sa && (sa->nLength>=sizeof(*sa)) && sa->bInheritHandle);
433 req->sharing = sharing;
434 req->create = creation;
435 req->attrs = attributes;
436 req->drive_type = drive_type;
437 wine_server_add_data( req, filename, strlen(filename) );
438 SetLastError(0);
439 err = wine_server_call( req );
440 ret = reply->handle;
442 SERVER_END_REQ;
444 /* If write access failed, retry without GENERIC_WRITE */
446 if (!ret && !fail_read_only && (access & GENERIC_WRITE))
448 if ((err == STATUS_MEDIA_WRITE_PROTECTED) || (err == STATUS_ACCESS_DENIED))
450 TRACE("Write access failed for file '%s', trying without "
451 "write access\n", filename);
452 access &= ~GENERIC_WRITE;
453 continue;
457 if (err)
459 /* In the case file creation was rejected due to CREATE_NEW flag
460 * was specified and file with that name already exists, correct
461 * last error is ERROR_FILE_EXISTS and not ERROR_ALREADY_EXISTS.
462 * Note: RtlNtStatusToDosError is not the subject to blame here.
464 if (err == STATUS_OBJECT_NAME_COLLISION)
465 SetLastError( ERROR_FILE_EXISTS );
466 else
467 SetLastError( RtlNtStatusToDosError(err) );
470 if (!ret) WARN("Unable to create file '%s' (GLE %ld)\n", filename, GetLastError());
471 return ret;
476 /***********************************************************************
477 * FILE_CreateDevice
479 * Same as FILE_CreateFile but for a device
480 * Returns 0 on failure.
482 HANDLE FILE_CreateDevice( int client_id, DWORD access, LPSECURITY_ATTRIBUTES sa )
484 HANDLE ret;
485 SERVER_START_REQ( create_device )
487 req->access = access;
488 req->inherit = (sa && (sa->nLength>=sizeof(*sa)) && sa->bInheritHandle);
489 req->id = client_id;
490 SetLastError(0);
491 wine_server_call_err( req );
492 ret = reply->handle;
494 SERVER_END_REQ;
495 return ret;
498 static HANDLE FILE_OpenPipe(LPCWSTR name, DWORD access)
500 HANDLE ret;
501 DWORD len = 0;
503 if (name && (len = strlenW(name)) > MAX_PATH)
505 SetLastError( ERROR_FILENAME_EXCED_RANGE );
506 return 0;
508 SERVER_START_REQ( open_named_pipe )
510 req->access = access;
511 SetLastError(0);
512 wine_server_add_data( req, name, len * sizeof(WCHAR) );
513 wine_server_call_err( req );
514 ret = reply->handle;
516 SERVER_END_REQ;
517 TRACE("Returned %d\n",ret);
518 return ret;
521 /*************************************************************************
522 * CreateFileW [KERNEL32.@] Creates or opens a file or other object
524 * Creates or opens an object, and returns a handle that can be used to
525 * access that object.
527 * PARAMS
529 * filename [in] pointer to filename to be accessed
530 * access [in] access mode requested
531 * sharing [in] share mode
532 * sa [in] pointer to security attributes
533 * creation [in] how to create the file
534 * attributes [in] attributes for newly created file
535 * template [in] handle to file with extended attributes to copy
537 * RETURNS
538 * Success: Open handle to specified file
539 * Failure: INVALID_HANDLE_VALUE
541 * NOTES
542 * Should call SetLastError() on failure.
544 * BUGS
546 * Doesn't support character devices, template files, or a
547 * lot of the 'attributes' flags yet.
549 HANDLE WINAPI CreateFileW( LPCWSTR filename, DWORD access, DWORD sharing,
550 LPSECURITY_ATTRIBUTES sa, DWORD creation,
551 DWORD attributes, HANDLE template )
553 DOS_FULL_NAME full_name;
554 HANDLE ret;
555 static const WCHAR bkslashes_with_question_markW[] = {'\\','\\','?','\\',0};
556 static const WCHAR bkslashes_with_dotW[] = {'\\','\\','.','\\',0};
557 static const WCHAR bkslashesW[] = {'\\','\\',0};
558 static const WCHAR coninW[] = {'C','O','N','I','N','$',0};
559 static const WCHAR conoutW[] = {'C','O','N','O','U','T','$',0};
561 if (!filename)
563 SetLastError( ERROR_INVALID_PARAMETER );
564 return INVALID_HANDLE_VALUE;
566 TRACE("%s %s%s%s%s%s%s%s attributes 0x%lx\n", debugstr_w(filename),
567 ((access & GENERIC_READ)==GENERIC_READ)?"GENERIC_READ ":"",
568 ((access & GENERIC_WRITE)==GENERIC_WRITE)?"GENERIC_WRITE ":"",
569 (!access)?"QUERY_ACCESS ":"",
570 ((sharing & FILE_SHARE_READ)==FILE_SHARE_READ)?"FILE_SHARE_READ ":"",
571 ((sharing & FILE_SHARE_WRITE)==FILE_SHARE_WRITE)?"FILE_SHARE_WRITE ":"",
572 ((sharing & FILE_SHARE_DELETE)==FILE_SHARE_DELETE)?"FILE_SHARE_DELETE ":"",
573 (creation ==CREATE_NEW)?"CREATE_NEW":
574 (creation ==CREATE_ALWAYS)?"CREATE_ALWAYS ":
575 (creation ==OPEN_EXISTING)?"OPEN_EXISTING ":
576 (creation ==OPEN_ALWAYS)?"OPEN_ALWAYS ":
577 (creation ==TRUNCATE_EXISTING)?"TRUNCATE_EXISTING ":"", attributes);
579 /* If the name starts with '\\?\', ignore the first 4 chars. */
580 if (!strncmpW(filename, bkslashes_with_question_markW, 4))
582 static const WCHAR uncW[] = {'U','N','C','\\',0};
583 filename += 4;
584 if (!strncmpiW(filename, uncW, 4))
586 FIXME("UNC name (%s) not supported.\n", debugstr_w(filename) );
587 SetLastError( ERROR_PATH_NOT_FOUND );
588 return INVALID_HANDLE_VALUE;
592 if (!strncmpW(filename, bkslashes_with_dotW, 4))
594 static const WCHAR pipeW[] = {'P','I','P','E','\\',0};
595 if(!strncmpiW(filename + 4, pipeW, 5))
597 TRACE("Opening a pipe: %s\n", debugstr_w(filename));
598 ret = FILE_OpenPipe(filename,access);
599 goto done;
601 else if (isalphaW(filename[4]) && filename[5] == ':' && filename[6] == '\0')
603 ret = FILE_CreateDevice( (toupperW(filename[4]) - 'A') | 0x20000, access, sa );
604 goto done;
606 else if (!DOSFS_GetDevice( filename ))
608 ret = DEVICE_Open( filename+4, access, sa );
609 goto done;
611 else
612 filename+=4; /* fall into DOSFS_Device case below */
615 /* If the name still starts with '\\', it's a UNC name. */
616 if (!strncmpW(filename, bkslashesW, 2))
618 ret = SMB_CreateFileW(filename, access, sharing, sa, creation, attributes, template );
619 goto done;
622 /* If the name contains a DOS wild card (* or ?), do no create a file */
623 if(strchrW(filename, '*') || strchrW(filename, '?'))
624 return INVALID_HANDLE_VALUE;
626 /* Open a console for CONIN$ or CONOUT$ */
627 if (!strcmpiW(filename, coninW))
629 ret = FILE_OpenConsole( FALSE, access, sharing, sa );
630 goto done;
632 if (!strcmpiW(filename, conoutW))
634 ret = FILE_OpenConsole( TRUE, access, sharing, sa );
635 goto done;
638 if (DOSFS_GetDevice( filename ))
640 TRACE("opening device %s\n", debugstr_w(filename) );
642 if (!(ret = DOSFS_OpenDevice( filename, access, attributes, sa )))
644 /* Do not silence this please. It is a critical error. -MM */
645 ERR("Couldn't open device %s!\n", debugstr_w(filename));
646 SetLastError( ERROR_FILE_NOT_FOUND );
648 goto done;
651 /* check for filename, don't check for last entry if creating */
652 if (!DOSFS_GetFullName( filename,
653 (creation == OPEN_EXISTING) ||
654 (creation == TRUNCATE_EXISTING),
655 &full_name )) {
656 WARN("Unable to get full filename from %s (GLE %ld)\n",
657 debugstr_w(filename), GetLastError());
658 return INVALID_HANDLE_VALUE;
661 ret = FILE_CreateFile( full_name.long_name, access, sharing,
662 sa, creation, attributes, template,
663 DRIVE_GetFlags(full_name.drive) & DRIVE_FAIL_READ_ONLY,
664 GetDriveTypeW( full_name.short_name ) );
665 done:
666 if (!ret) ret = INVALID_HANDLE_VALUE;
667 TRACE("returning %08x\n", ret);
668 return ret;
673 /*************************************************************************
674 * CreateFileA (KERNEL32.@)
676 HANDLE WINAPI CreateFileA( LPCSTR filename, DWORD access, DWORD sharing,
677 LPSECURITY_ATTRIBUTES sa, DWORD creation,
678 DWORD attributes, HANDLE template)
680 UNICODE_STRING filenameW;
681 HANDLE ret = INVALID_HANDLE_VALUE;
683 if (!filename)
685 SetLastError( ERROR_INVALID_PARAMETER );
686 return INVALID_HANDLE_VALUE;
689 if (RtlCreateUnicodeStringFromAsciiz(&filenameW, filename))
691 ret = CreateFileW(filenameW.Buffer, access, sharing, sa, creation,
692 attributes, template);
693 RtlFreeUnicodeString(&filenameW);
695 else
696 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
697 return ret;
701 /***********************************************************************
702 * FILE_FillInfo
704 * Fill a file information from a struct stat.
706 static void FILE_FillInfo( struct stat *st, BY_HANDLE_FILE_INFORMATION *info )
708 if (S_ISDIR(st->st_mode))
709 info->dwFileAttributes = FILE_ATTRIBUTE_DIRECTORY;
710 else
711 info->dwFileAttributes = FILE_ATTRIBUTE_ARCHIVE;
712 if (!(st->st_mode & S_IWUSR))
713 info->dwFileAttributes |= FILE_ATTRIBUTE_READONLY;
715 RtlSecondsSince1970ToTime( st->st_mtime, (LARGE_INTEGER *)&info->ftCreationTime );
716 RtlSecondsSince1970ToTime( st->st_mtime, (LARGE_INTEGER *)&info->ftLastWriteTime );
717 RtlSecondsSince1970ToTime( st->st_atime, (LARGE_INTEGER *)&info->ftLastAccessTime );
719 info->dwVolumeSerialNumber = 0; /* FIXME */
720 info->nFileSizeHigh = 0;
721 info->nFileSizeLow = 0;
722 if (!S_ISDIR(st->st_mode)) {
723 info->nFileSizeHigh = st->st_size >> 32;
724 info->nFileSizeLow = st->st_size & 0xffffffff;
726 info->nNumberOfLinks = st->st_nlink;
727 info->nFileIndexHigh = 0;
728 info->nFileIndexLow = st->st_ino;
732 /***********************************************************************
733 * FILE_Stat
735 * Stat a Unix path name. Return TRUE if OK.
737 BOOL FILE_Stat( LPCSTR unixName, BY_HANDLE_FILE_INFORMATION *info, BOOL *is_symlink_ptr )
739 struct stat st;
740 int is_symlink;
741 LPCSTR p;
743 if (lstat( unixName, &st ) == -1)
745 FILE_SetDosError();
746 return FALSE;
748 is_symlink = S_ISLNK(st.st_mode);
749 if (is_symlink)
751 /* do a "real" stat to find out
752 about the type of the symlink destination */
753 if (stat( unixName, &st ) == -1)
755 FILE_SetDosError();
756 return FALSE;
760 /* fill in the information we gathered so far */
761 FILE_FillInfo( &st, info );
763 /* and now see if this is a hidden file, based on the name */
764 p = strrchr( unixName, '/');
765 p = p ? p + 1 : unixName;
766 if (*p == '.' && *(p+1) && (*(p+1) != '.' || *(p+2)))
768 static const WCHAR wineW[] = {'w','i','n','e',0};
769 static const WCHAR ShowDotFilesW[] = {'S','h','o','w','D','o','t','F','i','l','e','s',0};
770 static int show_dot_files = -1;
771 if (show_dot_files == -1)
772 show_dot_files = PROFILE_GetWineIniBool(wineW, ShowDotFilesW, 0);
773 if (!show_dot_files)
774 info->dwFileAttributes |= FILE_ATTRIBUTE_HIDDEN;
776 if (is_symlink_ptr) *is_symlink_ptr = is_symlink;
777 return TRUE;
781 /***********************************************************************
782 * GetFileInformationByHandle (KERNEL32.@)
784 DWORD WINAPI GetFileInformationByHandle( HANDLE hFile,
785 BY_HANDLE_FILE_INFORMATION *info )
787 DWORD ret;
788 if (!info) return 0;
790 TRACE("%08x\n", hFile);
792 SERVER_START_REQ( get_file_info )
794 req->handle = hFile;
795 if ((ret = !wine_server_call_err( req )))
797 /* FIXME: which file types are supported ?
798 * Serial ports (FILE_TYPE_CHAR) are not,
799 * and MSDN also says that pipes are not supported.
800 * FILE_TYPE_REMOTE seems to be supported according to
801 * MSDN q234741.txt */
802 if ((reply->type == FILE_TYPE_DISK) || (reply->type == FILE_TYPE_REMOTE))
804 RtlSecondsSince1970ToTime( reply->write_time, (LARGE_INTEGER *)&info->ftCreationTime );
805 RtlSecondsSince1970ToTime( reply->write_time, (LARGE_INTEGER *)&info->ftLastWriteTime );
806 RtlSecondsSince1970ToTime( reply->access_time, (LARGE_INTEGER *)&info->ftLastAccessTime );
807 info->dwFileAttributes = reply->attr;
808 info->dwVolumeSerialNumber = reply->serial;
809 info->nFileSizeHigh = reply->size_high;
810 info->nFileSizeLow = reply->size_low;
811 info->nNumberOfLinks = reply->links;
812 info->nFileIndexHigh = reply->index_high;
813 info->nFileIndexLow = reply->index_low;
815 else
817 SetLastError(ERROR_NOT_SUPPORTED);
818 ret = 0;
822 SERVER_END_REQ;
823 return ret;
827 /**************************************************************************
828 * GetFileAttributes (KERNEL.420)
830 DWORD WINAPI GetFileAttributes16( LPCSTR name )
832 return GetFileAttributesA( name );
836 /**************************************************************************
837 * GetFileAttributesW (KERNEL32.@)
839 DWORD WINAPI GetFileAttributesW( LPCWSTR name )
841 DOS_FULL_NAME full_name;
842 BY_HANDLE_FILE_INFORMATION info;
844 if (name == NULL)
846 SetLastError( ERROR_INVALID_PARAMETER );
847 return -1;
849 if (!DOSFS_GetFullName( name, TRUE, &full_name) )
850 return -1;
851 if (!FILE_Stat( full_name.long_name, &info, NULL )) return -1;
852 return info.dwFileAttributes;
856 /**************************************************************************
857 * GetFileAttributesA (KERNEL32.@)
859 DWORD WINAPI GetFileAttributesA( LPCSTR name )
861 UNICODE_STRING nameW;
862 DWORD ret = (DWORD)-1;
864 if (!name)
866 SetLastError( ERROR_INVALID_PARAMETER );
867 return (DWORD)-1;
870 if (RtlCreateUnicodeStringFromAsciiz(&nameW, name))
872 ret = GetFileAttributesW(nameW.Buffer);
873 RtlFreeUnicodeString(&nameW);
875 else
876 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
877 return ret;
881 /**************************************************************************
882 * SetFileAttributes (KERNEL.421)
884 BOOL16 WINAPI SetFileAttributes16( LPCSTR lpFileName, DWORD attributes )
886 return SetFileAttributesA( lpFileName, attributes );
890 /**************************************************************************
891 * SetFileAttributesW (KERNEL32.@)
893 BOOL WINAPI SetFileAttributesW(LPCWSTR lpFileName, DWORD attributes)
895 struct stat buf;
896 DOS_FULL_NAME full_name;
898 if (!lpFileName)
900 SetLastError( ERROR_INVALID_PARAMETER );
901 return FALSE;
904 TRACE("(%s,%lx)\n", debugstr_w(lpFileName), attributes);
906 if (!DOSFS_GetFullName( lpFileName, TRUE, &full_name ))
907 return FALSE;
909 if(stat(full_name.long_name,&buf)==-1)
911 FILE_SetDosError();
912 return FALSE;
914 if (attributes & FILE_ATTRIBUTE_READONLY)
916 if(S_ISDIR(buf.st_mode))
917 /* FIXME */
918 WARN("FILE_ATTRIBUTE_READONLY ignored for directory.\n");
919 else
920 buf.st_mode &= ~0222; /* octal!, clear write permission bits */
921 attributes &= ~FILE_ATTRIBUTE_READONLY;
923 else
925 /* add write permission */
926 buf.st_mode |= (0600 | ((buf.st_mode & 044) >> 1)) & (~FILE_umask);
928 if (attributes & FILE_ATTRIBUTE_DIRECTORY)
930 if (!S_ISDIR(buf.st_mode))
931 FIXME("SetFileAttributes expected the file %s to be a directory\n",
932 debugstr_w(lpFileName));
933 attributes &= ~FILE_ATTRIBUTE_DIRECTORY;
935 attributes &= ~(FILE_ATTRIBUTE_NORMAL|FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_HIDDEN|FILE_ATTRIBUTE_SYSTEM);
936 if (attributes)
937 FIXME("(%s):%lx attribute(s) not implemented.\n", debugstr_w(lpFileName), attributes);
938 if (-1==chmod(full_name.long_name,buf.st_mode))
940 if (GetDriveTypeW(lpFileName) == DRIVE_CDROM)
942 SetLastError( ERROR_ACCESS_DENIED );
943 return FALSE;
947 * FIXME: We don't return FALSE here because of differences between
948 * Linux and Windows privileges. Under Linux only the owner of
949 * the file is allowed to change file attributes. Under Windows,
950 * applications expect that if you can write to a file, you can also
951 * change its attributes (see GENERIC_WRITE). We could try to be
952 * clever here but that would break multi-user installations where
953 * users share read-only DLLs. This is because some installers like
954 * to change attributes of already installed DLLs.
956 FIXME("Couldn't set file attributes for existing file \"%s\".\n"
957 "Check permissions or set VFAT \"quiet\" mount flag\n", full_name.long_name);
959 return TRUE;
963 /**************************************************************************
964 * SetFileAttributesA (KERNEL32.@)
966 BOOL WINAPI SetFileAttributesA(LPCSTR lpFileName, DWORD attributes)
968 UNICODE_STRING filenameW;
969 BOOL ret = FALSE;
971 if (!lpFileName)
973 SetLastError( ERROR_INVALID_PARAMETER );
974 return FALSE;
977 if (RtlCreateUnicodeStringFromAsciiz(&filenameW, lpFileName))
979 ret = SetFileAttributesW(filenameW.Buffer, attributes);
980 RtlFreeUnicodeString(&filenameW);
982 else
983 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
984 return ret;
988 /***********************************************************************
989 * GetFileSize (KERNEL32.@)
991 DWORD WINAPI GetFileSize( HANDLE hFile, LPDWORD filesizehigh )
993 BY_HANDLE_FILE_INFORMATION info;
994 if (!GetFileInformationByHandle( hFile, &info )) return -1;
995 if (filesizehigh) *filesizehigh = info.nFileSizeHigh;
996 return info.nFileSizeLow;
1000 /***********************************************************************
1001 * GetFileTime (KERNEL32.@)
1003 BOOL WINAPI GetFileTime( HANDLE hFile, FILETIME *lpCreationTime,
1004 FILETIME *lpLastAccessTime,
1005 FILETIME *lpLastWriteTime )
1007 BY_HANDLE_FILE_INFORMATION info;
1008 if (!GetFileInformationByHandle( hFile, &info )) return FALSE;
1009 if (lpCreationTime) *lpCreationTime = info.ftCreationTime;
1010 if (lpLastAccessTime) *lpLastAccessTime = info.ftLastAccessTime;
1011 if (lpLastWriteTime) *lpLastWriteTime = info.ftLastWriteTime;
1012 return TRUE;
1015 /***********************************************************************
1016 * CompareFileTime (KERNEL32.@)
1018 INT WINAPI CompareFileTime( LPFILETIME x, LPFILETIME y )
1020 if (!x || !y) return -1;
1022 if (x->dwHighDateTime > y->dwHighDateTime)
1023 return 1;
1024 if (x->dwHighDateTime < y->dwHighDateTime)
1025 return -1;
1026 if (x->dwLowDateTime > y->dwLowDateTime)
1027 return 1;
1028 if (x->dwLowDateTime < y->dwLowDateTime)
1029 return -1;
1030 return 0;
1033 /***********************************************************************
1034 * FILE_GetTempFileName : utility for GetTempFileName
1036 static UINT FILE_GetTempFileName( LPCWSTR path, LPCWSTR prefix, UINT unique,
1037 LPWSTR buffer )
1039 static UINT unique_temp;
1040 DOS_FULL_NAME full_name;
1041 int i;
1042 LPWSTR p;
1043 UINT num;
1044 char buf[20];
1046 if ( !path || !prefix || !buffer )
1048 SetLastError( ERROR_INVALID_PARAMETER );
1049 return 0;
1052 if (!unique_temp) unique_temp = time(NULL) & 0xffff;
1053 num = unique ? (unique & 0xffff) : (unique_temp++ & 0xffff);
1055 strcpyW( buffer, path );
1056 p = buffer + strlenW(buffer);
1058 /* add a \, if there isn't one and path is more than just the drive letter ... */
1059 if ( !((strlenW(buffer) == 2) && (buffer[1] == ':'))
1060 && ((p == buffer) || (p[-1] != '\\'))) *p++ = '\\';
1062 for (i = 3; (i > 0) && (*prefix); i--) *p++ = *prefix++;
1064 sprintf( buf, "%04x.tmp", num );
1065 MultiByteToWideChar(CP_ACP, 0, buf, -1, p, 20);
1067 /* Now try to create it */
1069 if (!unique)
1073 HANDLE handle = CreateFileW( buffer, GENERIC_WRITE, 0, NULL,
1074 CREATE_NEW, FILE_ATTRIBUTE_NORMAL, 0 );
1075 if (handle != INVALID_HANDLE_VALUE)
1076 { /* We created it */
1077 TRACE("created %s\n", debugstr_w(buffer) );
1078 CloseHandle( handle );
1079 break;
1081 if (GetLastError() != ERROR_FILE_EXISTS)
1082 break; /* No need to go on */
1083 num++;
1084 sprintf( buf, "%04x.tmp", num );
1085 MultiByteToWideChar(CP_ACP, 0, buf, -1, p, 20);
1086 } while (num != (unique & 0xffff));
1089 /* Get the full path name */
1091 if (DOSFS_GetFullName( buffer, FALSE, &full_name ))
1093 char *slash;
1094 /* Check if we have write access in the directory */
1095 if ((slash = strrchr( full_name.long_name, '/' ))) *slash = '\0';
1096 if (access( full_name.long_name, W_OK ) == -1)
1097 WARN("returns %s, which doesn't seem to be writeable.\n",
1098 debugstr_w(buffer) );
1100 TRACE("returning %s\n", debugstr_w(buffer) );
1101 return unique ? unique : num;
1105 /***********************************************************************
1106 * GetTempFileNameA (KERNEL32.@)
1108 UINT WINAPI GetTempFileNameA( LPCSTR path, LPCSTR prefix, UINT unique,
1109 LPSTR buffer)
1111 UNICODE_STRING pathW, prefixW;
1112 WCHAR bufferW[MAX_PATH];
1113 UINT ret;
1115 if ( !path || !prefix || !buffer )
1117 SetLastError( ERROR_INVALID_PARAMETER );
1118 return 0;
1121 RtlCreateUnicodeStringFromAsciiz(&pathW, path);
1122 RtlCreateUnicodeStringFromAsciiz(&prefixW, prefix);
1124 ret = GetTempFileNameW(pathW.Buffer, prefixW.Buffer, unique, bufferW);
1125 if (ret)
1126 WideCharToMultiByte(CP_ACP, 0, bufferW, -1, buffer, MAX_PATH, NULL, NULL);
1128 RtlFreeUnicodeString(&pathW);
1129 RtlFreeUnicodeString(&prefixW);
1130 return ret;
1133 /***********************************************************************
1134 * GetTempFileNameW (KERNEL32.@)
1136 UINT WINAPI GetTempFileNameW( LPCWSTR path, LPCWSTR prefix, UINT unique,
1137 LPWSTR buffer )
1139 return FILE_GetTempFileName( path, prefix, unique, buffer );
1143 /***********************************************************************
1144 * GetTempFileName (KERNEL.97)
1146 UINT16 WINAPI GetTempFileName16( BYTE drive, LPCSTR prefix, UINT16 unique,
1147 LPSTR buffer )
1149 char temppath[MAX_PATH];
1150 char *prefix16 = NULL;
1151 UINT16 ret;
1153 if (!(drive & ~TF_FORCEDRIVE)) /* drive 0 means current default drive */
1154 drive |= DRIVE_GetCurrentDrive() + 'A';
1156 if ((drive & TF_FORCEDRIVE) &&
1157 !DRIVE_IsValid( toupper(drive & ~TF_FORCEDRIVE) - 'A' ))
1159 drive &= ~TF_FORCEDRIVE;
1160 WARN("invalid drive %d specified\n", drive );
1163 if (drive & TF_FORCEDRIVE)
1164 sprintf(temppath,"%c:", drive & ~TF_FORCEDRIVE );
1165 else
1166 GetTempPathA( MAX_PATH, temppath );
1168 if (prefix)
1170 prefix16 = HeapAlloc(GetProcessHeap(), 0, strlen(prefix) + 2);
1171 *prefix16 = '~';
1172 strcpy(prefix16 + 1, prefix);
1175 ret = GetTempFileNameA( temppath, prefix16, unique, buffer );
1177 if (prefix16) HeapFree(GetProcessHeap(), 0, prefix16);
1178 return ret;
1181 /***********************************************************************
1182 * FILE_DoOpenFile
1184 * Implementation of OpenFile16() and OpenFile32().
1186 static HFILE FILE_DoOpenFile( LPCSTR name, OFSTRUCT *ofs, UINT mode,
1187 BOOL win32 )
1189 HFILE hFileRet;
1190 HANDLE handle;
1191 FILETIME filetime;
1192 WORD filedatetime[2];
1193 DOS_FULL_NAME full_name;
1194 DWORD access, sharing;
1195 WCHAR *p;
1196 WCHAR buffer[MAX_PATH];
1197 LPWSTR nameW;
1199 if (!ofs) return HFILE_ERROR;
1201 TRACE("%s %s %s %s%s%s%s%s%s%s%s%s\n",name,
1202 ((mode & 0x3 )==OF_READ)?"OF_READ":
1203 ((mode & 0x3 )==OF_WRITE)?"OF_WRITE":
1204 ((mode & 0x3 )==OF_READWRITE)?"OF_READWRITE":"unknown",
1205 ((mode & 0x70 )==OF_SHARE_COMPAT)?"OF_SHARE_COMPAT":
1206 ((mode & 0x70 )==OF_SHARE_DENY_NONE)?"OF_SHARE_DENY_NONE":
1207 ((mode & 0x70 )==OF_SHARE_DENY_READ)?"OF_SHARE_DENY_READ":
1208 ((mode & 0x70 )==OF_SHARE_DENY_WRITE)?"OF_SHARE_DENY_WRITE":
1209 ((mode & 0x70 )==OF_SHARE_EXCLUSIVE)?"OF_SHARE_EXCLUSIVE":"unknown",
1210 ((mode & OF_PARSE )==OF_PARSE)?"OF_PARSE ":"",
1211 ((mode & OF_DELETE )==OF_DELETE)?"OF_DELETE ":"",
1212 ((mode & OF_VERIFY )==OF_VERIFY)?"OF_VERIFY ":"",
1213 ((mode & OF_SEARCH )==OF_SEARCH)?"OF_SEARCH ":"",
1214 ((mode & OF_CANCEL )==OF_CANCEL)?"OF_CANCEL ":"",
1215 ((mode & OF_CREATE )==OF_CREATE)?"OF_CREATE ":"",
1216 ((mode & OF_PROMPT )==OF_PROMPT)?"OF_PROMPT ":"",
1217 ((mode & OF_EXIST )==OF_EXIST)?"OF_EXIST ":"",
1218 ((mode & OF_REOPEN )==OF_REOPEN)?"OF_REOPEN ":""
1222 ofs->cBytes = sizeof(OFSTRUCT);
1223 ofs->nErrCode = 0;
1224 if (mode & OF_REOPEN) name = ofs->szPathName;
1226 if (!name) {
1227 ERR("called with `name' set to NULL ! Please debug.\n");
1228 return HFILE_ERROR;
1231 TRACE("%s %04x\n", name, mode );
1233 /* the watcom 10.6 IDE relies on a valid path returned in ofs->szPathName
1234 Are there any cases where getting the path here is wrong?
1235 Uwe Bonnes 1997 Apr 2 */
1236 if (!GetFullPathNameA( name, sizeof(ofs->szPathName),
1237 ofs->szPathName, NULL )) goto error;
1238 FILE_ConvertOFMode( mode, &access, &sharing );
1240 /* OF_PARSE simply fills the structure */
1242 if (mode & OF_PARSE)
1244 ofs->fFixedDisk = (GetDriveType16( ofs->szPathName[0]-'A' )
1245 != DRIVE_REMOVABLE);
1246 TRACE("(%s): OF_PARSE, res = '%s'\n",
1247 name, ofs->szPathName );
1248 return 0;
1251 /* OF_CREATE is completely different from all other options, so
1252 handle it first */
1254 if (mode & OF_CREATE)
1256 if ((handle = CreateFileA( name, GENERIC_READ | GENERIC_WRITE,
1257 sharing, NULL, CREATE_ALWAYS,
1258 FILE_ATTRIBUTE_NORMAL, 0 ))== INVALID_HANDLE_VALUE)
1259 goto error;
1260 goto success;
1263 MultiByteToWideChar(CP_ACP, 0, name, -1, buffer, MAX_PATH);
1264 nameW = buffer;
1266 /* If OF_SEARCH is set, ignore the given path */
1268 if ((mode & OF_SEARCH) && !(mode & OF_REOPEN))
1270 /* First try the file name as is */
1271 if (DOSFS_GetFullName( nameW, TRUE, &full_name )) goto found;
1272 /* Now remove the path */
1273 if (nameW[0] && (nameW[1] == ':')) nameW += 2;
1274 if ((p = strrchrW( nameW, '\\' ))) nameW = p + 1;
1275 if ((p = strrchrW( nameW, '/' ))) nameW = p + 1;
1276 if (!nameW[0]) goto not_found;
1279 /* Now look for the file */
1281 if (!DIR_SearchPath( NULL, nameW, NULL, &full_name, win32 )) goto not_found;
1283 found:
1284 TRACE("found %s = %s\n",
1285 full_name.long_name, debugstr_w(full_name.short_name) );
1286 WideCharToMultiByte(CP_ACP, 0, full_name.short_name, -1,
1287 ofs->szPathName, sizeof(ofs->szPathName), NULL, NULL);
1289 if (mode & OF_SHARE_EXCLUSIVE)
1290 /* Some InstallShield version uses OF_SHARE_EXCLUSIVE
1291 on the file <tempdir>/_ins0432._mp to determine how
1292 far installation has proceeded.
1293 _ins0432._mp is an executable and while running the
1294 application expects the open with OF_SHARE_ to fail*/
1295 /* Probable FIXME:
1296 As our loader closes the files after loading the executable,
1297 we can't find the running executable with FILE_InUse.
1298 The loader should keep the file open, as Windows does that, too.
1301 char *last = strrchr(full_name.long_name,'/');
1302 if (!last)
1303 last = full_name.long_name - 1;
1304 if (GetModuleHandle16(last+1))
1306 TRACE("Denying shared open for %s\n",full_name.long_name);
1307 return HFILE_ERROR;
1311 if (mode & OF_DELETE)
1313 if (unlink( full_name.long_name ) == -1) goto not_found;
1314 TRACE("(%s): OF_DELETE return = OK\n", name);
1315 return 1;
1318 handle = FILE_CreateFile( full_name.long_name, access, sharing,
1319 NULL, OPEN_EXISTING, 0, 0,
1320 DRIVE_GetFlags(full_name.drive) & DRIVE_FAIL_READ_ONLY,
1321 GetDriveTypeW( full_name.short_name ) );
1322 if (!handle) goto not_found;
1324 GetFileTime( handle, NULL, NULL, &filetime );
1325 FileTimeToDosDateTime( &filetime, &filedatetime[0], &filedatetime[1] );
1326 if ((mode & OF_VERIFY) && (mode & OF_REOPEN))
1328 if (ofs->Reserved1 != filedatetime[0] || ofs->Reserved2 != filedatetime[1] )
1330 CloseHandle( handle );
1331 WARN("(%s): OF_VERIFY failed\n", name );
1332 /* FIXME: what error here? */
1333 SetLastError( ERROR_FILE_NOT_FOUND );
1334 goto error;
1337 ofs->Reserved1 = filedatetime[0];
1338 ofs->Reserved2 = filedatetime[1];
1340 success: /* We get here if the open was successful */
1341 TRACE("(%s): OK, return = %x\n", name, handle );
1342 if (win32)
1344 hFileRet = (HFILE)handle;
1345 if (mode & OF_EXIST) /* Return the handle, but close it first */
1346 CloseHandle( handle );
1348 else
1350 hFileRet = Win32HandleToDosFileHandle( handle );
1351 if (hFileRet == HFILE_ERROR16) goto error;
1352 if (mode & OF_EXIST) /* Return the handle, but close it first */
1353 _lclose16( hFileRet );
1355 return hFileRet;
1357 not_found: /* We get here if the file does not exist */
1358 WARN("'%s' not found or sharing violation\n", name );
1359 SetLastError( ERROR_FILE_NOT_FOUND );
1360 /* fall through */
1362 error: /* We get here if there was an error opening the file */
1363 ofs->nErrCode = GetLastError();
1364 WARN("(%s): return = HFILE_ERROR error= %d\n",
1365 name,ofs->nErrCode );
1366 return HFILE_ERROR;
1370 /***********************************************************************
1371 * OpenFile (KERNEL.74)
1372 * OpenFileEx (KERNEL.360)
1374 HFILE16 WINAPI OpenFile16( LPCSTR name, OFSTRUCT *ofs, UINT16 mode )
1376 return FILE_DoOpenFile( name, ofs, mode, FALSE );
1380 /***********************************************************************
1381 * OpenFile (KERNEL32.@)
1383 HFILE WINAPI OpenFile( LPCSTR name, OFSTRUCT *ofs, UINT mode )
1385 return FILE_DoOpenFile( name, ofs, mode, TRUE );
1389 /***********************************************************************
1390 * FILE_InitProcessDosHandles
1392 * Allocates the default DOS handles for a process. Called either by
1393 * Win32HandleToDosFileHandle below or by the DOSVM stuff.
1395 static void FILE_InitProcessDosHandles( void )
1397 HANDLE cp = GetCurrentProcess();
1398 DuplicateHandle(cp, GetStdHandle(STD_INPUT_HANDLE), cp, &dos_handles[0],
1399 0, TRUE, DUPLICATE_SAME_ACCESS);
1400 DuplicateHandle(cp, GetStdHandle(STD_OUTPUT_HANDLE), cp, &dos_handles[1],
1401 0, TRUE, DUPLICATE_SAME_ACCESS);
1402 DuplicateHandle(cp, GetStdHandle(STD_ERROR_HANDLE), cp, &dos_handles[2],
1403 0, TRUE, DUPLICATE_SAME_ACCESS);
1404 DuplicateHandle(cp, GetStdHandle(STD_ERROR_HANDLE), cp, &dos_handles[3],
1405 0, TRUE, DUPLICATE_SAME_ACCESS);
1406 DuplicateHandle(cp, GetStdHandle(STD_ERROR_HANDLE), cp, &dos_handles[4],
1407 0, TRUE, DUPLICATE_SAME_ACCESS);
1410 /***********************************************************************
1411 * Win32HandleToDosFileHandle (KERNEL32.21)
1413 * Allocate a DOS handle for a Win32 handle. The Win32 handle is no
1414 * longer valid after this function (even on failure).
1416 * Note: this is not exactly right, since on Win95 the Win32 handles
1417 * are on top of DOS handles and we do it the other way
1418 * around. Should be good enough though.
1420 HFILE WINAPI Win32HandleToDosFileHandle( HANDLE handle )
1422 int i;
1424 if (!handle || (handle == INVALID_HANDLE_VALUE))
1425 return HFILE_ERROR;
1427 for (i = 5; i < DOS_TABLE_SIZE; i++)
1428 if (!dos_handles[i])
1430 dos_handles[i] = handle;
1431 TRACE("Got %d for h32 %d\n", i, handle );
1432 return (HFILE)i;
1434 CloseHandle( handle );
1435 SetLastError( ERROR_TOO_MANY_OPEN_FILES );
1436 return HFILE_ERROR;
1440 /***********************************************************************
1441 * DosFileHandleToWin32Handle (KERNEL32.20)
1443 * Return the Win32 handle for a DOS handle.
1445 * Note: this is not exactly right, since on Win95 the Win32 handles
1446 * are on top of DOS handles and we do it the other way
1447 * around. Should be good enough though.
1449 HANDLE WINAPI DosFileHandleToWin32Handle( HFILE handle )
1451 HFILE16 hfile = (HFILE16)handle;
1452 if (hfile < 5 && !dos_handles[hfile]) FILE_InitProcessDosHandles();
1453 if ((hfile >= DOS_TABLE_SIZE) || !dos_handles[hfile])
1455 SetLastError( ERROR_INVALID_HANDLE );
1456 return INVALID_HANDLE_VALUE;
1458 return dos_handles[hfile];
1462 /***********************************************************************
1463 * DisposeLZ32Handle (KERNEL32.22)
1465 * Note: this is not entirely correct, we should only close the
1466 * 32-bit handle and not the 16-bit one, but we cannot do
1467 * this because of the way our DOS handles are implemented.
1468 * It shouldn't break anything though.
1470 void WINAPI DisposeLZ32Handle( HANDLE handle )
1472 int i;
1474 if (!handle || (handle == INVALID_HANDLE_VALUE)) return;
1476 for (i = 5; i < DOS_TABLE_SIZE; i++)
1477 if (dos_handles[i] == handle)
1479 dos_handles[i] = 0;
1480 CloseHandle( handle );
1481 break;
1486 /***********************************************************************
1487 * FILE_Dup2
1489 * dup2() function for DOS handles.
1491 HFILE16 FILE_Dup2( HFILE16 hFile1, HFILE16 hFile2 )
1493 HANDLE new_handle;
1495 if (hFile1 < 5 && !dos_handles[hFile1]) FILE_InitProcessDosHandles();
1497 if ((hFile1 >= DOS_TABLE_SIZE) || (hFile2 >= DOS_TABLE_SIZE) || !dos_handles[hFile1])
1499 SetLastError( ERROR_INVALID_HANDLE );
1500 return HFILE_ERROR16;
1502 if (!DuplicateHandle( GetCurrentProcess(), dos_handles[hFile1],
1503 GetCurrentProcess(), &new_handle,
1504 0, FALSE, DUPLICATE_SAME_ACCESS ))
1505 return HFILE_ERROR16;
1506 if (dos_handles[hFile2]) CloseHandle( dos_handles[hFile2] );
1507 dos_handles[hFile2] = new_handle;
1508 return hFile2;
1512 /***********************************************************************
1513 * _lclose (KERNEL.81)
1515 HFILE16 WINAPI _lclose16( HFILE16 hFile )
1517 if ((hFile >= DOS_TABLE_SIZE) || !dos_handles[hFile])
1519 SetLastError( ERROR_INVALID_HANDLE );
1520 return HFILE_ERROR16;
1522 TRACE("%d (handle32=%d)\n", hFile, dos_handles[hFile] );
1523 CloseHandle( dos_handles[hFile] );
1524 dos_handles[hFile] = 0;
1525 return 0;
1529 /***********************************************************************
1530 * _lclose (KERNEL32.@)
1532 HFILE WINAPI _lclose( HFILE hFile )
1534 TRACE("handle %d\n", hFile );
1535 return CloseHandle( (HANDLE)hFile ) ? 0 : HFILE_ERROR;
1538 /***********************************************************************
1539 * GetOverlappedResult (KERNEL32.@)
1541 * Check the result of an Asynchronous data transfer from a file.
1543 * RETURNS
1544 * TRUE on success
1545 * FALSE on failure
1547 * If successful (and relevant) lpTransferred will hold the number of
1548 * bytes transferred during the async operation.
1550 * BUGS
1552 * Currently only works for WaitCommEvent, ReadFile, WriteFile
1553 * with communications ports.
1556 BOOL WINAPI GetOverlappedResult(
1557 HANDLE hFile, /* [in] handle of file to check on */
1558 LPOVERLAPPED lpOverlapped, /* [in/out] pointer to overlapped */
1559 LPDWORD lpTransferred, /* [in/out] number of bytes transferred */
1560 BOOL bWait /* [in] wait for the transfer to complete ? */
1562 DWORD r;
1564 TRACE("(%d %p %p %x)\n", hFile, lpOverlapped, lpTransferred, bWait);
1566 if(lpOverlapped==NULL)
1568 ERR("lpOverlapped was null\n");
1569 return FALSE;
1571 if(!lpOverlapped->hEvent)
1573 ERR("lpOverlapped->hEvent was null\n");
1574 return FALSE;
1577 if ( bWait )
1579 do {
1580 TRACE("waiting on %p\n",lpOverlapped);
1581 r = WaitForSingleObjectEx(lpOverlapped->hEvent, INFINITE, TRUE);
1582 TRACE("wait on %p returned %ld\n",lpOverlapped,r);
1583 } while (r==STATUS_USER_APC);
1585 else if ( lpOverlapped->Internal == STATUS_PENDING )
1587 /* Wait in order to give APCs a chance to run. */
1588 /* This is cheating, so we must set the event again in case of success -
1589 it may be a non-manual reset event. */
1590 do {
1591 TRACE("waiting on %p\n",lpOverlapped);
1592 r = WaitForSingleObjectEx(lpOverlapped->hEvent, 0, TRUE);
1593 TRACE("wait on %p returned %ld\n",lpOverlapped,r);
1594 } while (r==STATUS_USER_APC);
1595 if ( r == WAIT_OBJECT_0 )
1596 NtSetEvent ( lpOverlapped->hEvent, NULL );
1599 if(lpTransferred)
1600 *lpTransferred = lpOverlapped->InternalHigh;
1602 switch ( lpOverlapped->Internal )
1604 case STATUS_SUCCESS:
1605 return TRUE;
1606 case STATUS_PENDING:
1607 SetLastError ( ERROR_IO_INCOMPLETE );
1608 if ( bWait ) ERR ("PENDING status after waiting!\n");
1609 return FALSE;
1610 default:
1611 SetLastError ( RtlNtStatusToDosError ( lpOverlapped->Internal ) );
1612 return FALSE;
1616 /***********************************************************************
1617 * CancelIo (KERNEL32.@)
1619 BOOL WINAPI CancelIo(HANDLE handle)
1621 async_private *ovp,*t;
1623 TRACE("handle = %x\n",handle);
1625 for (ovp = NtCurrentTeb()->pending_list; ovp; ovp = t)
1627 t = ovp->next;
1628 if ( ovp->handle == handle )
1629 cancel_async ( ovp );
1631 WaitForMultipleObjectsEx(0,NULL,FALSE,1,TRUE);
1632 return TRUE;
1635 /***********************************************************************
1636 * FILE_AsyncReadService (INTERNAL)
1638 * This function is called while the client is waiting on the
1639 * server, so we can't make any server calls here.
1641 static void FILE_AsyncReadService(async_private *ovp)
1643 async_fileio *fileio = (async_fileio*) ovp;
1644 LPOVERLAPPED lpOverlapped = fileio->lpOverlapped;
1645 int result, r;
1646 int already = lpOverlapped->InternalHigh;
1648 TRACE("%p %p\n", lpOverlapped, fileio->buffer );
1650 /* check to see if the data is ready (non-blocking) */
1652 if ( fileio->fd_type == FD_TYPE_SOCKET )
1653 result = read (ovp->fd, &fileio->buffer[already], fileio->count - already);
1654 else
1656 result = pread (ovp->fd, &fileio->buffer[already], fileio->count - already,
1657 OVERLAPPED_OFFSET (lpOverlapped) + already);
1658 if ((result < 0) && (errno == ESPIPE))
1659 result = read (ovp->fd, &fileio->buffer[already], fileio->count - already);
1662 if ( (result<0) && ((errno == EAGAIN) || (errno == EINTR)))
1664 TRACE("Deferred read %d\n",errno);
1665 r = STATUS_PENDING;
1666 goto async_end;
1669 /* check to see if the transfer is complete */
1670 if(result<0)
1672 r = FILE_GetNtStatus ();
1673 goto async_end;
1676 lpOverlapped->InternalHigh += result;
1677 TRACE("read %d more bytes %ld/%d so far\n",result,lpOverlapped->InternalHigh,fileio->count);
1679 if(lpOverlapped->InternalHigh >= fileio->count || fileio->fd_type == FD_TYPE_SOCKET )
1680 r = STATUS_SUCCESS;
1681 else
1682 r = STATUS_PENDING;
1684 async_end:
1685 lpOverlapped->Internal = r;
1688 /***********************************************************************
1689 * FILE_ReadFileEx (INTERNAL)
1691 static BOOL FILE_ReadFileEx(HANDLE hFile, LPVOID buffer, DWORD bytesToRead,
1692 LPOVERLAPPED overlapped,
1693 LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine,
1694 HANDLE hEvent)
1696 async_fileio *ovp;
1697 int fd;
1698 int flags;
1699 enum fd_type type;
1701 TRACE("file %d to buf %p num %ld %p func %p\n",
1702 hFile, buffer, bytesToRead, overlapped, lpCompletionRoutine);
1704 /* check that there is an overlapped struct */
1705 if (overlapped==NULL)
1707 SetLastError(ERROR_INVALID_PARAMETER);
1708 return FALSE;
1711 fd = FILE_GetUnixHandleType ( hFile, GENERIC_READ, &type, &flags);
1712 if ( fd < 0 )
1714 WARN ( "Couldn't get FD\n" );
1715 return FALSE;
1718 ovp = (async_fileio*) HeapAlloc(GetProcessHeap(), 0, sizeof (async_fileio));
1719 if(!ovp)
1721 TRACE("HeapAlloc Failed\n");
1722 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1723 goto error;
1726 ovp->async.ops = ( lpCompletionRoutine ? &fileio_async_ops : &fileio_nocomp_async_ops );
1727 ovp->async.handle = hFile;
1728 ovp->async.fd = fd;
1729 ovp->async.type = ASYNC_TYPE_READ;
1730 ovp->async.func = FILE_AsyncReadService;
1731 ovp->async.event = hEvent;
1732 ovp->lpOverlapped = overlapped;
1733 ovp->count = bytesToRead;
1734 ovp->completion_func = lpCompletionRoutine;
1735 ovp->buffer = buffer;
1736 ovp->fd_type = type;
1738 return !register_new_async (&ovp->async);
1740 error:
1741 close (fd);
1742 return FALSE;
1746 /***********************************************************************
1747 * ReadFileEx (KERNEL32.@)
1749 BOOL WINAPI ReadFileEx(HANDLE hFile, LPVOID buffer, DWORD bytesToRead,
1750 LPOVERLAPPED overlapped,
1751 LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine)
1753 overlapped->InternalHigh = 0;
1754 return FILE_ReadFileEx(hFile,buffer,bytesToRead,overlapped,lpCompletionRoutine, INVALID_HANDLE_VALUE);
1757 static BOOL FILE_TimeoutRead(HANDLE hFile, LPVOID buffer, DWORD bytesToRead, LPDWORD bytesRead)
1759 OVERLAPPED ov;
1760 BOOL r = FALSE;
1762 TRACE("%d %p %ld %p\n", hFile, buffer, bytesToRead, bytesRead );
1764 ZeroMemory(&ov, sizeof (OVERLAPPED));
1765 if(STATUS_SUCCESS==NtCreateEvent(&ov.hEvent, SYNCHRONIZE, NULL, 0, 0))
1767 if(FILE_ReadFileEx(hFile, buffer, bytesToRead, &ov, NULL, ov.hEvent))
1769 r = GetOverlappedResult(hFile, &ov, bytesRead, TRUE);
1772 CloseHandle(ov.hEvent);
1773 return r;
1776 /***********************************************************************
1777 * ReadFile (KERNEL32.@)
1779 BOOL WINAPI ReadFile( HANDLE hFile, LPVOID buffer, DWORD bytesToRead,
1780 LPDWORD bytesRead, LPOVERLAPPED overlapped )
1782 int unix_handle, result, flags;
1783 enum fd_type type;
1785 TRACE("%d %p %ld %p %p\n", hFile, buffer, bytesToRead,
1786 bytesRead, overlapped );
1788 if (bytesRead) *bytesRead = 0; /* Do this before anything else */
1789 if (!bytesToRead) return TRUE;
1791 unix_handle = FILE_GetUnixHandleType( hFile, GENERIC_READ, &type, &flags );
1793 if (flags & FD_FLAG_OVERLAPPED)
1795 if (unix_handle == -1) return FALSE;
1796 if ( (overlapped==NULL) || NtResetEvent( overlapped->hEvent, NULL ) )
1798 TRACE("Overlapped not specified or invalid event flag\n");
1799 close(unix_handle);
1800 SetLastError(ERROR_INVALID_PARAMETER);
1801 return FALSE;
1804 close(unix_handle);
1805 overlapped->InternalHigh = 0;
1807 if(!FILE_ReadFileEx(hFile, buffer, bytesToRead, overlapped, NULL, overlapped->hEvent))
1808 return FALSE;
1810 if ( !GetOverlappedResult (hFile, overlapped, bytesRead, FALSE) )
1812 if ( GetLastError() == ERROR_IO_INCOMPLETE )
1813 SetLastError ( ERROR_IO_PENDING );
1814 return FALSE;
1817 return TRUE;
1819 if (flags & FD_FLAG_TIMEOUT)
1821 close(unix_handle);
1822 return FILE_TimeoutRead(hFile, buffer, bytesToRead, bytesRead);
1824 switch(type)
1826 case FD_TYPE_SMB:
1827 return SMB_ReadFile(hFile, buffer, bytesToRead, bytesRead, NULL);
1829 case FD_TYPE_CONSOLE:
1830 return FILE_ReadConsole(hFile, buffer, bytesToRead, bytesRead, NULL);
1832 case FD_TYPE_DEFAULT:
1833 /* normal unix files */
1834 if (unix_handle == -1) return FALSE;
1835 if (overlapped)
1837 DWORD highOffset = overlapped->OffsetHigh;
1838 if ( (INVALID_SET_FILE_POINTER == SetFilePointer(hFile, overlapped->Offset,
1839 &highOffset, FILE_BEGIN)) &&
1840 (GetLastError() != NO_ERROR) )
1842 close(unix_handle);
1843 return FALSE;
1846 break;
1848 default:
1849 if (unix_handle == -1)
1850 return FALSE;
1853 if(overlapped)
1855 off_t offset = OVERLAPPED_OFFSET(overlapped);
1856 if(lseek(unix_handle, offset, SEEK_SET) == -1)
1858 close(unix_handle);
1859 SetLastError(ERROR_INVALID_PARAMETER);
1860 return FALSE;
1864 /* code for synchronous reads */
1865 while ((result = read( unix_handle, buffer, bytesToRead )) == -1)
1867 if ((errno == EAGAIN) || (errno == EINTR)) continue;
1868 if ((errno == EFAULT) && !IsBadWritePtr( buffer, bytesToRead )) continue;
1869 FILE_SetDosError();
1870 break;
1872 close( unix_handle );
1873 if (result == -1) return FALSE;
1874 if (bytesRead) *bytesRead = result;
1875 return TRUE;
1879 /***********************************************************************
1880 * FILE_AsyncWriteService (INTERNAL)
1882 * This function is called while the client is waiting on the
1883 * server, so we can't make any server calls here.
1885 static void FILE_AsyncWriteService(struct async_private *ovp)
1887 async_fileio *fileio = (async_fileio *) ovp;
1888 LPOVERLAPPED lpOverlapped = fileio->lpOverlapped;
1889 int result, r;
1890 int already = lpOverlapped->InternalHigh;
1892 TRACE("(%p %p)\n",lpOverlapped,fileio->buffer);
1894 /* write some data (non-blocking) */
1896 if ( fileio->fd_type == FD_TYPE_SOCKET )
1897 result = write(ovp->fd, &fileio->buffer[already], fileio->count - already);
1898 else
1900 result = pwrite(ovp->fd, &fileio->buffer[already], fileio->count - already,
1901 OVERLAPPED_OFFSET (lpOverlapped) + already);
1902 if ((result < 0) && (errno == ESPIPE))
1903 result = write(ovp->fd, &fileio->buffer[already], fileio->count - already);
1906 if ( (result<0) && ((errno == EAGAIN) || (errno == EINTR)))
1908 r = STATUS_PENDING;
1909 goto async_end;
1912 /* check to see if the transfer is complete */
1913 if(result<0)
1915 r = FILE_GetNtStatus ();
1916 goto async_end;
1919 lpOverlapped->InternalHigh += result;
1921 TRACE("wrote %d more bytes %ld/%d so far\n",result,lpOverlapped->InternalHigh,fileio->count);
1923 if(lpOverlapped->InternalHigh < fileio->count)
1924 r = STATUS_PENDING;
1925 else
1926 r = STATUS_SUCCESS;
1928 async_end:
1929 lpOverlapped->Internal = r;
1932 /***********************************************************************
1933 * FILE_WriteFileEx
1935 static BOOL FILE_WriteFileEx(HANDLE hFile, LPCVOID buffer, DWORD bytesToWrite,
1936 LPOVERLAPPED overlapped,
1937 LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine,
1938 HANDLE hEvent)
1940 async_fileio *ovp;
1941 int fd;
1942 int flags;
1943 enum fd_type type;
1945 TRACE("file %d to buf %p num %ld %p func %p handle %d\n",
1946 hFile, buffer, bytesToWrite, overlapped, lpCompletionRoutine, hEvent);
1948 if (overlapped == NULL)
1950 SetLastError(ERROR_INVALID_PARAMETER);
1951 return FALSE;
1954 fd = FILE_GetUnixHandleType ( hFile, GENERIC_WRITE, &type, &flags );
1955 if ( fd < 0 )
1957 TRACE( "Couldn't get FD\n" );
1958 return FALSE;
1961 ovp = (async_fileio*) HeapAlloc(GetProcessHeap(), 0, sizeof (async_fileio));
1962 if(!ovp)
1964 TRACE("HeapAlloc Failed\n");
1965 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1966 goto error;
1969 ovp->async.ops = ( lpCompletionRoutine ? &fileio_async_ops : &fileio_nocomp_async_ops );
1970 ovp->async.handle = hFile;
1971 ovp->async.fd = fd;
1972 ovp->async.type = ASYNC_TYPE_WRITE;
1973 ovp->async.func = FILE_AsyncWriteService;
1974 ovp->lpOverlapped = overlapped;
1975 ovp->async.event = hEvent;
1976 ovp->buffer = (LPVOID) buffer;
1977 ovp->count = bytesToWrite;
1978 ovp->completion_func = lpCompletionRoutine;
1979 ovp->fd_type = type;
1981 return !register_new_async (&ovp->async);
1983 error:
1984 close (fd);
1985 return FALSE;
1988 /***********************************************************************
1989 * WriteFileEx (KERNEL32.@)
1991 BOOL WINAPI WriteFileEx(HANDLE hFile, LPCVOID buffer, DWORD bytesToWrite,
1992 LPOVERLAPPED overlapped,
1993 LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine)
1995 overlapped->InternalHigh = 0;
1997 return FILE_WriteFileEx(hFile, buffer, bytesToWrite, overlapped, lpCompletionRoutine, INVALID_HANDLE_VALUE);
2000 /***********************************************************************
2001 * WriteFile (KERNEL32.@)
2003 BOOL WINAPI WriteFile( HANDLE hFile, LPCVOID buffer, DWORD bytesToWrite,
2004 LPDWORD bytesWritten, LPOVERLAPPED overlapped )
2006 int unix_handle, result, flags;
2007 enum fd_type type;
2009 TRACE("%d %p %ld %p %p\n", hFile, buffer, bytesToWrite,
2010 bytesWritten, overlapped );
2012 if (bytesWritten) *bytesWritten = 0; /* Do this before anything else */
2013 if (!bytesToWrite) return TRUE;
2015 unix_handle = FILE_GetUnixHandleType( hFile, GENERIC_WRITE, &type, &flags );
2017 if (flags & FD_FLAG_OVERLAPPED)
2019 if (unix_handle == -1) return FALSE;
2020 if ( (overlapped==NULL) || NtResetEvent( overlapped->hEvent, NULL ) )
2022 TRACE("Overlapped not specified or invalid event flag\n");
2023 close(unix_handle);
2024 SetLastError(ERROR_INVALID_PARAMETER);
2025 return FALSE;
2028 close(unix_handle);
2029 overlapped->InternalHigh = 0;
2031 if(!FILE_WriteFileEx(hFile, buffer, bytesToWrite, overlapped, NULL, overlapped->hEvent))
2032 return FALSE;
2034 if ( !GetOverlappedResult (hFile, overlapped, bytesWritten, FALSE) )
2036 if ( GetLastError() == ERROR_IO_INCOMPLETE )
2037 SetLastError ( ERROR_IO_PENDING );
2038 return FALSE;
2041 return TRUE;
2044 switch(type)
2046 case FD_TYPE_CONSOLE:
2047 TRACE("%d %s %ld %p %p\n", hFile, debugstr_an(buffer, bytesToWrite), bytesToWrite,
2048 bytesWritten, overlapped );
2049 return FILE_WriteConsole(hFile, buffer, bytesToWrite, bytesWritten, NULL);
2051 case FD_TYPE_DEFAULT:
2052 if (unix_handle == -1) return FALSE;
2054 if(overlapped)
2056 DWORD highOffset = overlapped->OffsetHigh;
2057 if ( (INVALID_SET_FILE_POINTER == SetFilePointer(hFile, overlapped->Offset,
2058 &highOffset, FILE_BEGIN)) &&
2059 (GetLastError() != NO_ERROR) )
2061 close(unix_handle);
2062 return FALSE;
2065 break;
2067 default:
2068 if (unix_handle == -1)
2069 return FALSE;
2070 if (overlapped)
2072 close(unix_handle);
2073 SetLastError(ERROR_INVALID_PARAMETER);
2074 return FALSE;
2076 break;
2079 if(overlapped)
2081 off_t offset = OVERLAPPED_OFFSET(overlapped);
2082 if(lseek(unix_handle, offset, SEEK_SET) == -1)
2084 close(unix_handle);
2085 SetLastError(ERROR_INVALID_PARAMETER);
2086 return FALSE;
2090 /* synchronous file write */
2091 while ((result = write( unix_handle, buffer, bytesToWrite )) == -1)
2093 if ((errno == EAGAIN) || (errno == EINTR)) continue;
2094 if ((errno == EFAULT) && !IsBadReadPtr( buffer, bytesToWrite )) continue;
2095 if (errno == ENOSPC)
2096 SetLastError( ERROR_DISK_FULL );
2097 else
2098 FILE_SetDosError();
2099 break;
2101 close( unix_handle );
2102 if (result == -1) return FALSE;
2103 if (bytesWritten) *bytesWritten = result;
2104 return TRUE;
2108 /***********************************************************************
2109 * _hread (KERNEL.349)
2111 LONG WINAPI WIN16_hread( HFILE16 hFile, SEGPTR buffer, LONG count )
2113 LONG maxlen;
2115 TRACE("%d %08lx %ld\n",
2116 hFile, (DWORD)buffer, count );
2118 /* Some programs pass a count larger than the allocated buffer */
2119 maxlen = GetSelectorLimit16( SELECTOROF(buffer) ) - OFFSETOF(buffer) + 1;
2120 if (count > maxlen) count = maxlen;
2121 return _lread((HFILE)DosFileHandleToWin32Handle(hFile), MapSL(buffer), count );
2125 /***********************************************************************
2126 * _lread (KERNEL.82)
2128 UINT16 WINAPI WIN16_lread( HFILE16 hFile, SEGPTR buffer, UINT16 count )
2130 return (UINT16)WIN16_hread( hFile, buffer, (LONG)count );
2134 /***********************************************************************
2135 * _lread (KERNEL32.@)
2137 UINT WINAPI _lread( HFILE handle, LPVOID buffer, UINT count )
2139 DWORD result;
2140 if (!ReadFile( (HANDLE)handle, buffer, count, &result, NULL )) return -1;
2141 return result;
2145 /***********************************************************************
2146 * _lread16 (KERNEL.82)
2148 UINT16 WINAPI _lread16( HFILE16 hFile, LPVOID buffer, UINT16 count )
2150 return (UINT16)_lread((HFILE)DosFileHandleToWin32Handle(hFile), buffer, (LONG)count );
2154 /***********************************************************************
2155 * _lcreat (KERNEL.83)
2157 HFILE16 WINAPI _lcreat16( LPCSTR path, INT16 attr )
2159 return Win32HandleToDosFileHandle( (HANDLE)_lcreat( path, attr ) );
2163 /***********************************************************************
2164 * _lcreat (KERNEL32.@)
2166 HFILE WINAPI _lcreat( LPCSTR path, INT attr )
2168 /* Mask off all flags not explicitly allowed by the doc */
2169 attr &= FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM;
2170 TRACE("%s %02x\n", path, attr );
2171 return (HFILE)CreateFileA( path, GENERIC_READ | GENERIC_WRITE,
2172 FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
2173 CREATE_ALWAYS, attr, 0 );
2177 /***********************************************************************
2178 * SetFilePointer (KERNEL32.@)
2180 DWORD WINAPI SetFilePointer( HANDLE hFile, LONG distance, LONG *highword,
2181 DWORD method )
2183 DWORD ret = INVALID_SET_FILE_POINTER;
2185 TRACE("handle %d offset %ld high %ld origin %ld\n",
2186 hFile, distance, highword?*highword:0, method );
2188 SERVER_START_REQ( set_file_pointer )
2190 req->handle = hFile;
2191 req->low = distance;
2192 req->high = highword ? *highword : (distance >= 0) ? 0 : -1;
2193 /* FIXME: assumes 1:1 mapping between Windows and Unix seek constants */
2194 req->whence = method;
2195 SetLastError( 0 );
2196 if (!wine_server_call_err( req ))
2198 ret = reply->new_low;
2199 if (highword) *highword = reply->new_high;
2202 SERVER_END_REQ;
2203 return ret;
2207 /***********************************************************************
2208 * _llseek (KERNEL.84)
2210 * FIXME:
2211 * Seeking before the start of the file should be allowed for _llseek16,
2212 * but cause subsequent I/O operations to fail (cf. interrupt list)
2215 LONG WINAPI _llseek16( HFILE16 hFile, LONG lOffset, INT16 nOrigin )
2217 return SetFilePointer( DosFileHandleToWin32Handle(hFile), lOffset, NULL, nOrigin );
2221 /***********************************************************************
2222 * _llseek (KERNEL32.@)
2224 LONG WINAPI _llseek( HFILE hFile, LONG lOffset, INT nOrigin )
2226 return SetFilePointer( (HANDLE)hFile, lOffset, NULL, nOrigin );
2230 /***********************************************************************
2231 * _lopen (KERNEL.85)
2233 HFILE16 WINAPI _lopen16( LPCSTR path, INT16 mode )
2235 return Win32HandleToDosFileHandle( (HANDLE)_lopen( path, mode ) );
2239 /***********************************************************************
2240 * _lopen (KERNEL32.@)
2242 HFILE WINAPI _lopen( LPCSTR path, INT mode )
2244 DWORD access, sharing;
2246 TRACE("('%s',%04x)\n", path, mode );
2247 FILE_ConvertOFMode( mode, &access, &sharing );
2248 return (HFILE)CreateFileA( path, access, sharing, NULL, OPEN_EXISTING, 0, 0 );
2252 /***********************************************************************
2253 * _lwrite (KERNEL.86)
2255 UINT16 WINAPI _lwrite16( HFILE16 hFile, LPCSTR buffer, UINT16 count )
2257 return (UINT16)_hwrite( (HFILE)DosFileHandleToWin32Handle(hFile), buffer, (LONG)count );
2260 /***********************************************************************
2261 * _lwrite (KERNEL32.@)
2263 UINT WINAPI _lwrite( HFILE hFile, LPCSTR buffer, UINT count )
2265 return (UINT)_hwrite( hFile, buffer, (LONG)count );
2269 /***********************************************************************
2270 * _hread16 (KERNEL.349)
2272 LONG WINAPI _hread16( HFILE16 hFile, LPVOID buffer, LONG count)
2274 return _lread( (HFILE)DosFileHandleToWin32Handle(hFile), buffer, count );
2278 /***********************************************************************
2279 * _hread (KERNEL32.@)
2281 LONG WINAPI _hread( HFILE hFile, LPVOID buffer, LONG count)
2283 return _lread( hFile, buffer, count );
2287 /***********************************************************************
2288 * _hwrite (KERNEL.350)
2290 LONG WINAPI _hwrite16( HFILE16 hFile, LPCSTR buffer, LONG count )
2292 return _hwrite( (HFILE)DosFileHandleToWin32Handle(hFile), buffer, count );
2296 /***********************************************************************
2297 * _hwrite (KERNEL32.@)
2299 * experimentation yields that _lwrite:
2300 * o truncates the file at the current position with
2301 * a 0 len write
2302 * o returns 0 on a 0 length write
2303 * o works with console handles
2306 LONG WINAPI _hwrite( HFILE handle, LPCSTR buffer, LONG count )
2308 DWORD result;
2310 TRACE("%d %p %ld\n", handle, buffer, count );
2312 if (!count)
2314 /* Expand or truncate at current position */
2315 if (!SetEndOfFile( (HANDLE)handle )) return HFILE_ERROR;
2316 return 0;
2318 if (!WriteFile( (HANDLE)handle, buffer, count, &result, NULL ))
2319 return HFILE_ERROR;
2320 return result;
2324 /***********************************************************************
2325 * SetHandleCount (KERNEL.199)
2327 UINT16 WINAPI SetHandleCount16( UINT16 count )
2329 return SetHandleCount( count );
2333 /*************************************************************************
2334 * SetHandleCount (KERNEL32.@)
2336 UINT WINAPI SetHandleCount( UINT count )
2338 return min( 256, count );
2342 /***********************************************************************
2343 * FlushFileBuffers (KERNEL32.@)
2345 BOOL WINAPI FlushFileBuffers( HANDLE hFile )
2347 BOOL ret;
2348 SERVER_START_REQ( flush_file )
2350 req->handle = hFile;
2351 ret = !wine_server_call_err( req );
2353 SERVER_END_REQ;
2354 return ret;
2358 /**************************************************************************
2359 * SetEndOfFile (KERNEL32.@)
2361 BOOL WINAPI SetEndOfFile( HANDLE hFile )
2363 BOOL ret;
2364 SERVER_START_REQ( truncate_file )
2366 req->handle = hFile;
2367 ret = !wine_server_call_err( req );
2369 SERVER_END_REQ;
2370 return ret;
2374 /***********************************************************************
2375 * DeleteFile (KERNEL.146)
2377 BOOL16 WINAPI DeleteFile16( LPCSTR path )
2379 return DeleteFileA( path );
2383 /***********************************************************************
2384 * DeleteFileW (KERNEL32.@)
2386 BOOL WINAPI DeleteFileW( LPCWSTR path )
2388 DOS_FULL_NAME full_name;
2389 HANDLE hFile;
2391 if (!path)
2393 SetLastError(ERROR_INVALID_PARAMETER);
2394 return FALSE;
2396 TRACE("%s\n", debugstr_w(path) );
2398 if (!*path)
2400 ERR("Empty path passed\n");
2401 return FALSE;
2403 if (DOSFS_GetDevice( path ))
2405 WARN("cannot remove DOS device %s!\n", debugstr_w(path));
2406 SetLastError( ERROR_FILE_NOT_FOUND );
2407 return FALSE;
2410 if (!DOSFS_GetFullName( path, TRUE, &full_name )) return FALSE;
2412 /* check if we are allowed to delete the source */
2413 hFile = FILE_CreateFile( full_name.long_name, GENERIC_READ|GENERIC_WRITE, 0,
2414 NULL, OPEN_EXISTING, 0, 0, TRUE,
2415 GetDriveTypeW( full_name.short_name ) );
2416 if (!hFile) return FALSE;
2418 if (unlink( full_name.long_name ) == -1)
2420 FILE_SetDosError();
2421 CloseHandle(hFile);
2422 return FALSE;
2424 CloseHandle(hFile);
2425 return TRUE;
2429 /***********************************************************************
2430 * DeleteFileA (KERNEL32.@)
2432 BOOL WINAPI DeleteFileA( LPCSTR path )
2434 UNICODE_STRING pathW;
2435 BOOL ret = FALSE;
2437 if (!path)
2439 SetLastError(ERROR_INVALID_PARAMETER);
2440 return FALSE;
2443 if (RtlCreateUnicodeStringFromAsciiz(&pathW, path))
2445 ret = DeleteFileW(pathW.Buffer);
2446 RtlFreeUnicodeString(&pathW);
2448 else
2449 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
2450 return ret;
2454 /***********************************************************************
2455 * GetFileType (KERNEL32.@)
2457 DWORD WINAPI GetFileType( HANDLE hFile )
2459 DWORD ret = FILE_TYPE_UNKNOWN;
2460 SERVER_START_REQ( get_file_info )
2462 req->handle = hFile;
2463 if (!wine_server_call_err( req )) ret = reply->type;
2465 SERVER_END_REQ;
2466 return ret;
2470 /* check if a file name is for an executable file (.exe or .com) */
2471 inline static BOOL is_executable( const char *name )
2473 int len = strlen(name);
2475 if (len < 4) return FALSE;
2476 return (!strcasecmp( name + len - 4, ".exe" ) ||
2477 !strcasecmp( name + len - 4, ".com" ));
2481 /***********************************************************************
2482 * FILE_AddBootRenameEntry
2484 * Adds an entry to the registry that is loaded when windows boots and
2485 * checks if there are some files to be removed or renamed/moved.
2486 * <fn1> has to be valid and <fn2> may be NULL. If both pointers are
2487 * non-NULL then the file is moved, otherwise it is deleted. The
2488 * entry of the registrykey is always appended with two zero
2489 * terminated strings. If <fn2> is NULL then the second entry is
2490 * simply a single 0-byte. Otherwise the second filename goes
2491 * there. The entries are prepended with \??\ before the path and the
2492 * second filename gets also a '!' as the first character if
2493 * MOVEFILE_REPLACE_EXISTING is set. After the final string another
2494 * 0-byte follows to indicate the end of the strings.
2495 * i.e.:
2496 * \??\D:\test\file1[0]
2497 * !\??\D:\test\file1_renamed[0]
2498 * \??\D:\Test|delete[0]
2499 * [0] <- file is to be deleted, second string empty
2500 * \??\D:\test\file2[0]
2501 * !\??\D:\test\file2_renamed[0]
2502 * [0] <- indicates end of strings
2504 * or:
2505 * \??\D:\test\file1[0]
2506 * !\??\D:\test\file1_renamed[0]
2507 * \??\D:\Test|delete[0]
2508 * [0] <- file is to be deleted, second string empty
2509 * [0] <- indicates end of strings
2512 static BOOL FILE_AddBootRenameEntry( LPCWSTR fn1, LPCWSTR fn2, DWORD flags )
2514 static const WCHAR PreString[] = {'\\','?','?','\\',0};
2515 static const WCHAR ValueName[] = {'P','e','n','d','i','n','g',
2516 'F','i','l','e','R','e','n','a','m','e',
2517 'O','p','e','r','a','t','i','o','n','s',0};
2518 static const WCHAR SessionW[] = {'M','a','c','h','i','n','e','\\',
2519 'S','y','s','t','e','m','\\',
2520 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
2521 'C','o','n','t','r','o','l','\\',
2522 'S','e','s','s','i','o','n',' ','M','a','n','a','g','e','r',0};
2523 static const int info_size = FIELD_OFFSET( KEY_VALUE_PARTIAL_INFORMATION, Data );
2525 OBJECT_ATTRIBUTES attr;
2526 UNICODE_STRING nameW;
2527 KEY_VALUE_PARTIAL_INFORMATION *info;
2528 BOOL rc = FALSE;
2529 HKEY Reboot = 0;
2530 DWORD len0, len1, len2;
2531 DWORD DataSize = 0;
2532 BYTE *Buffer = NULL;
2533 WCHAR *p;
2535 attr.Length = sizeof(attr);
2536 attr.RootDirectory = 0;
2537 attr.ObjectName = &nameW;
2538 attr.Attributes = 0;
2539 attr.SecurityDescriptor = NULL;
2540 attr.SecurityQualityOfService = NULL;
2541 RtlInitUnicodeString( &nameW, SessionW );
2543 if (NtCreateKey( &Reboot, KEY_ALL_ACCESS, &attr, 0, NULL, 0, NULL ) != STATUS_SUCCESS)
2545 WARN("Error creating key for reboot managment [%s]\n",
2546 "SYSTEM\\CurrentControlSet\\Control\\Session Manager");
2547 return FALSE;
2550 len0 = strlenW(PreString);
2551 len1 = strlenW(fn1) + len0 + 1;
2552 if (fn2)
2554 len2 = strlenW(fn2) + len0 + 1;
2555 if (flags & MOVEFILE_REPLACE_EXISTING) len2++; /* Plus 1 because of the leading '!' */
2557 else len2 = 1; /* minimum is the 0 characters for the empty second string */
2559 /* convert characters to bytes */
2560 len0 *= sizeof(WCHAR);
2561 len1 *= sizeof(WCHAR);
2562 len2 *= sizeof(WCHAR);
2564 RtlInitUnicodeString( &nameW, ValueName );
2566 /* First we check if the key exists and if so how many bytes it already contains. */
2567 if (NtQueryValueKey( Reboot, &nameW, KeyValuePartialInformation,
2568 NULL, 0, &DataSize ) == STATUS_BUFFER_OVERFLOW)
2570 if (!(Buffer = HeapAlloc( GetProcessHeap(), 0, DataSize + len1 + len2 + sizeof(WCHAR) )))
2571 goto Quit;
2572 if (NtQueryValueKey( Reboot, &nameW, KeyValuePartialInformation,
2573 Buffer, DataSize, &DataSize )) goto Quit;
2574 info = (KEY_VALUE_PARTIAL_INFORMATION *)Buffer;
2575 if (info->Type != REG_MULTI_SZ) goto Quit;
2576 if (DataSize > sizeof(info)) DataSize -= sizeof(WCHAR); /* remove terminating null (will be added back later) */
2578 else
2580 DataSize = info_size;
2581 if (!(Buffer = HeapAlloc( GetProcessHeap(), 0, DataSize + len1 + len2 + sizeof(WCHAR) )))
2582 goto Quit;
2585 p = (WCHAR *)(Buffer + DataSize);
2586 strcpyW( p, PreString );
2587 strcatW( p, fn1 );
2588 DataSize += len1;
2589 if (fn2)
2591 p = (WCHAR *)(Buffer + DataSize);
2592 if (flags & MOVEFILE_REPLACE_EXISTING)
2593 *p++ = '!';
2594 strcpyW( p, PreString );
2595 strcatW( p, fn2 );
2596 DataSize += len2;
2598 else
2600 p = (WCHAR *)(Buffer + DataSize);
2601 *p = 0;
2602 DataSize += sizeof(WCHAR);
2605 /* add final null */
2606 p = (WCHAR *)(Buffer + DataSize);
2607 *p = 0;
2608 DataSize += sizeof(WCHAR);
2610 rc = !NtSetValueKey(Reboot, &nameW, 0, REG_MULTI_SZ, Buffer + info_size, DataSize - info_size);
2612 Quit:
2613 if (Reboot) NtClose(Reboot);
2614 if (Buffer) HeapFree( GetProcessHeap(), 0, Buffer );
2615 return(rc);
2619 /**************************************************************************
2620 * MoveFileExW (KERNEL32.@)
2622 BOOL WINAPI MoveFileExW( LPCWSTR fn1, LPCWSTR fn2, DWORD flag )
2624 DOS_FULL_NAME full_name1, full_name2;
2625 HANDLE hFile;
2626 DWORD attr = INVALID_FILE_ATTRIBUTES;
2628 TRACE("(%s,%s,%04lx)\n", debugstr_w(fn1), debugstr_w(fn2), flag);
2630 /* FIXME: <Gerhard W. Gruber>sparhawk@gmx.at
2631 In case of W9x and lesser this function should return 120 (ERROR_CALL_NOT_IMPLEMENTED)
2632 to be really compatible. Most programs wont have any problems though. In case
2633 you encounter one, this is what you should return here. I don't know what's up
2634 with NT 3.5. Is this function available there or not?
2635 Does anybody really care about 3.5? :)
2638 /* Filename1 has to be always set to a valid path. Filename2 may be NULL
2639 if the source file has to be deleted.
2641 if (!fn1) {
2642 SetLastError(ERROR_INVALID_PARAMETER);
2643 return FALSE;
2646 /* This function has to be run through in order to process the name properly.
2647 If the BOOTDELAY flag is set, the file doesn't need to exist though. At least
2648 that is the behaviour on NT 4.0. The operation accepts the filenames as
2649 they are given but it can't reply with a reasonable returncode. Success
2650 means in that case success for entering the values into the registry.
2652 if(!DOSFS_GetFullName( fn1, TRUE, &full_name1 ))
2654 if(!(flag & MOVEFILE_DELAY_UNTIL_REBOOT))
2655 return FALSE;
2658 if (fn2) /* !fn2 means delete fn1 */
2660 if (DOSFS_GetFullName( fn2, TRUE, &full_name2 ))
2662 if(!(flag & MOVEFILE_DELAY_UNTIL_REBOOT))
2664 /* target exists, check if we may overwrite */
2665 if (!(flag & MOVEFILE_REPLACE_EXISTING))
2667 SetLastError( ERROR_FILE_EXISTS );
2668 return FALSE;
2672 else
2674 if (!DOSFS_GetFullName( fn2, FALSE, &full_name2 ))
2676 if(!(flag & MOVEFILE_DELAY_UNTIL_REBOOT))
2677 return FALSE;
2681 /* Source name and target path are valid */
2683 if (flag & MOVEFILE_DELAY_UNTIL_REBOOT)
2685 /* FIXME: (bon@elektron.ikp.physik.th-darmstadt.de 970706)
2686 Perhaps we should queue these command and execute it
2687 when exiting... What about using on_exit(2)
2689 FIXME("Please move existing file %s to file %s when Wine has finished\n",
2690 debugstr_w(fn1), debugstr_w(fn2));
2691 return FILE_AddBootRenameEntry( fn1, fn2, flag );
2694 attr = GetFileAttributesW( fn1 );
2695 if ( attr == INVALID_FILE_ATTRIBUTES ) return FALSE;
2697 /* check if we are allowed to rename the source */
2698 hFile = FILE_CreateFile( full_name1.long_name, 0, 0,
2699 NULL, OPEN_EXISTING, 0, 0, TRUE,
2700 GetDriveTypeW( full_name1.short_name ) );
2701 if (!hFile)
2703 if (GetLastError() != ERROR_ACCESS_DENIED) return FALSE;
2704 if ( !(attr & FILE_ATTRIBUTE_DIRECTORY) ) return FALSE;
2705 /* if it's a directory we can continue */
2707 else CloseHandle(hFile);
2709 /* check, if we are allowed to delete the destination,
2710 ** (but the file not being there is fine) */
2711 hFile = FILE_CreateFile( full_name2.long_name, GENERIC_READ|GENERIC_WRITE, 0,
2712 NULL, OPEN_EXISTING, 0, 0, TRUE,
2713 GetDriveTypeW( full_name2.short_name ) );
2714 if(!hFile && GetLastError() != ERROR_FILE_NOT_FOUND) return FALSE;
2715 CloseHandle(hFile);
2717 if (full_name1.drive != full_name2.drive)
2719 if (!(flag & MOVEFILE_COPY_ALLOWED))
2721 SetLastError( ERROR_NOT_SAME_DEVICE );
2722 return FALSE;
2724 else if ( attr & FILE_ATTRIBUTE_DIRECTORY )
2726 /* Strange, but that's what Windows returns */
2727 SetLastError ( ERROR_ACCESS_DENIED );
2728 return FALSE;
2731 if (rename( full_name1.long_name, full_name2.long_name ) == -1)
2732 /* Try copy/delete unless it's a directory. */
2733 /* FIXME: This does not handle the (unlikely) case that the two locations
2734 are on the same Wine drive, but on different Unix file systems. */
2736 if ( attr & FILE_ATTRIBUTE_DIRECTORY )
2738 FILE_SetDosError();
2739 return FALSE;
2741 else
2743 if ( ! CopyFileW( fn1, fn2, !(flag & MOVEFILE_REPLACE_EXISTING) ))
2744 return FALSE;
2745 if ( ! DeleteFileW ( fn1 ) )
2746 return FALSE;
2749 if (is_executable( full_name1.long_name ) != is_executable( full_name2.long_name ))
2751 struct stat fstat;
2752 if (stat( full_name2.long_name, &fstat ) != -1)
2754 if (is_executable( full_name2.long_name ))
2755 /* set executable bit where read bit is set */
2756 fstat.st_mode |= (fstat.st_mode & 0444) >> 2;
2757 else
2758 fstat.st_mode &= ~0111;
2759 chmod( full_name2.long_name, fstat.st_mode );
2762 return TRUE;
2764 else /* fn2 == NULL means delete source */
2766 if (flag & MOVEFILE_DELAY_UNTIL_REBOOT)
2768 if (flag & MOVEFILE_COPY_ALLOWED) {
2769 WARN("Illegal flag\n");
2770 SetLastError( ERROR_GEN_FAILURE );
2771 return FALSE;
2773 /* FIXME: (bon@elektron.ikp.physik.th-darmstadt.de 970706)
2774 Perhaps we should queue these command and execute it
2775 when exiting... What about using on_exit(2)
2777 FIXME("Please delete file %s when Wine has finished\n", debugstr_w(fn1));
2778 return FILE_AddBootRenameEntry( fn1, NULL, flag );
2781 if (unlink( full_name1.long_name ) == -1)
2783 FILE_SetDosError();
2784 return FALSE;
2786 return TRUE; /* successfully deleted */
2790 /**************************************************************************
2791 * MoveFileExA (KERNEL32.@)
2793 BOOL WINAPI MoveFileExA( LPCSTR fn1, LPCSTR fn2, DWORD flag )
2795 UNICODE_STRING fn1W, fn2W;
2796 BOOL ret;
2798 if (!fn1)
2800 SetLastError(ERROR_INVALID_PARAMETER);
2801 return FALSE;
2804 RtlCreateUnicodeStringFromAsciiz(&fn1W, fn1);
2805 if (fn2) RtlCreateUnicodeStringFromAsciiz(&fn2W, fn2);
2806 else fn2W.Buffer = NULL;
2808 ret = MoveFileExW( fn1W.Buffer, fn2W.Buffer, flag );
2810 RtlFreeUnicodeString(&fn1W);
2811 RtlFreeUnicodeString(&fn2W);
2812 return ret;
2816 /**************************************************************************
2817 * MoveFileW (KERNEL32.@)
2819 * Move file or directory
2821 BOOL WINAPI MoveFileW( LPCWSTR fn1, LPCWSTR fn2 )
2823 DOS_FULL_NAME full_name1, full_name2;
2824 struct stat fstat;
2826 if (!fn1 || !fn2)
2828 SetLastError(ERROR_INVALID_PARAMETER);
2829 return FALSE;
2832 TRACE("(%s,%s)\n", debugstr_w(fn1), debugstr_w(fn2) );
2834 if (!DOSFS_GetFullName( fn1, TRUE, &full_name1 )) return FALSE;
2835 if (DOSFS_GetFullName( fn2, TRUE, &full_name2 )) {
2836 /* The new name must not already exist */
2837 SetLastError(ERROR_ALREADY_EXISTS);
2838 return FALSE;
2840 if (!DOSFS_GetFullName( fn2, FALSE, &full_name2 )) return FALSE;
2842 if (full_name1.drive == full_name2.drive) /* move */
2843 return MoveFileExW( fn1, fn2, MOVEFILE_COPY_ALLOWED );
2845 /* copy */
2846 if (stat( full_name1.long_name, &fstat ))
2848 WARN("Invalid source file %s\n",
2849 full_name1.long_name);
2850 FILE_SetDosError();
2851 return FALSE;
2853 if (S_ISDIR(fstat.st_mode)) {
2854 /* No Move for directories across file systems */
2855 /* FIXME: Use right error code */
2856 SetLastError( ERROR_GEN_FAILURE );
2857 return FALSE;
2859 return CopyFileW(fn1, fn2, TRUE); /*fail, if exist */
2863 /**************************************************************************
2864 * MoveFileA (KERNEL32.@)
2866 BOOL WINAPI MoveFileA( LPCSTR fn1, LPCSTR fn2 )
2868 UNICODE_STRING fn1W, fn2W;
2869 BOOL ret;
2871 if (!fn1 || !fn2)
2873 SetLastError(ERROR_INVALID_PARAMETER);
2874 return FALSE;
2877 RtlCreateUnicodeStringFromAsciiz(&fn1W, fn1);
2878 RtlCreateUnicodeStringFromAsciiz(&fn2W, fn2);
2880 ret = MoveFileW( fn1W.Buffer, fn2W.Buffer );
2882 RtlFreeUnicodeString(&fn1W);
2883 RtlFreeUnicodeString(&fn2W);
2884 return ret;
2888 /**************************************************************************
2889 * CopyFileW (KERNEL32.@)
2891 BOOL WINAPI CopyFileW( LPCWSTR source, LPCWSTR dest, BOOL fail_if_exists )
2893 HANDLE h1, h2;
2894 BY_HANDLE_FILE_INFORMATION info;
2895 DWORD count;
2896 BOOL ret = FALSE;
2897 char buffer[2048];
2899 if (!source || !dest)
2901 SetLastError(ERROR_INVALID_PARAMETER);
2902 return FALSE;
2905 TRACE("%s -> %s\n", debugstr_w(source), debugstr_w(dest));
2907 if ((h1 = CreateFileW(source, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE,
2908 NULL, OPEN_EXISTING, 0, 0)) == INVALID_HANDLE_VALUE)
2910 WARN("Unable to open source %s\n", debugstr_w(source));
2911 return FALSE;
2914 if (!GetFileInformationByHandle( h1, &info ))
2916 WARN("GetFileInformationByHandle returned error for %s\n", debugstr_w(source));
2917 CloseHandle( h1 );
2918 return FALSE;
2921 if ((h2 = CreateFileW( dest, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
2922 fail_if_exists ? CREATE_NEW : CREATE_ALWAYS,
2923 info.dwFileAttributes, h1 )) == INVALID_HANDLE_VALUE)
2925 WARN("Unable to open dest %s\n", debugstr_w(dest));
2926 CloseHandle( h1 );
2927 return FALSE;
2930 while (ReadFile( h1, buffer, sizeof(buffer), &count, NULL ) && count)
2932 char *p = buffer;
2933 while (count != 0)
2935 DWORD res;
2936 if (!WriteFile( h2, p, count, &res, NULL ) || !res) goto done;
2937 p += res;
2938 count -= res;
2941 ret = TRUE;
2942 done:
2943 CloseHandle( h1 );
2944 CloseHandle( h2 );
2945 return ret;
2949 /**************************************************************************
2950 * CopyFileA (KERNEL32.@)
2952 BOOL WINAPI CopyFileA( LPCSTR source, LPCSTR dest, BOOL fail_if_exists)
2954 UNICODE_STRING sourceW, destW;
2955 BOOL ret;
2957 if (!source || !dest)
2959 SetLastError(ERROR_INVALID_PARAMETER);
2960 return FALSE;
2963 RtlCreateUnicodeStringFromAsciiz(&sourceW, source);
2964 RtlCreateUnicodeStringFromAsciiz(&destW, dest);
2966 ret = CopyFileW(sourceW.Buffer, destW.Buffer, fail_if_exists);
2968 RtlFreeUnicodeString(&sourceW);
2969 RtlFreeUnicodeString(&destW);
2970 return ret;
2974 /**************************************************************************
2975 * CopyFileExW (KERNEL32.@)
2977 * This implementation ignores most of the extra parameters passed-in into
2978 * the "ex" version of the method and calls the CopyFile method.
2979 * It will have to be fixed eventually.
2981 BOOL WINAPI CopyFileExW(LPCWSTR sourceFilename, LPCWSTR destFilename,
2982 LPPROGRESS_ROUTINE progressRoutine, LPVOID appData,
2983 LPBOOL cancelFlagPointer, DWORD copyFlags)
2986 * Interpret the only flag that CopyFile can interpret.
2988 return CopyFileW(sourceFilename, destFilename, (copyFlags & COPY_FILE_FAIL_IF_EXISTS) != 0);
2991 /**************************************************************************
2992 * CopyFileExA (KERNEL32.@)
2994 BOOL WINAPI CopyFileExA(LPCSTR sourceFilename, LPCSTR destFilename,
2995 LPPROGRESS_ROUTINE progressRoutine, LPVOID appData,
2996 LPBOOL cancelFlagPointer, DWORD copyFlags)
2998 UNICODE_STRING sourceW, destW;
2999 BOOL ret;
3001 if (!sourceFilename || !destFilename)
3003 SetLastError(ERROR_INVALID_PARAMETER);
3004 return FALSE;
3007 RtlCreateUnicodeStringFromAsciiz(&sourceW, sourceFilename);
3008 RtlCreateUnicodeStringFromAsciiz(&destW, destFilename);
3010 ret = CopyFileExW(sourceW.Buffer, destW.Buffer, progressRoutine, appData,
3011 cancelFlagPointer, copyFlags);
3013 RtlFreeUnicodeString(&sourceW);
3014 RtlFreeUnicodeString(&destW);
3015 return ret;
3019 /***********************************************************************
3020 * SetFileTime (KERNEL32.@)
3022 BOOL WINAPI SetFileTime( HANDLE hFile,
3023 const FILETIME *lpCreationTime,
3024 const FILETIME *lpLastAccessTime,
3025 const FILETIME *lpLastWriteTime )
3027 BOOL ret;
3028 SERVER_START_REQ( set_file_time )
3030 req->handle = hFile;
3031 if (lpLastAccessTime)
3032 RtlTimeToSecondsSince1970( (PLARGE_INTEGER) lpLastAccessTime, (DWORD *)&req->access_time );
3033 else
3034 req->access_time = 0; /* FIXME */
3035 if (lpLastWriteTime)
3036 RtlTimeToSecondsSince1970( (PLARGE_INTEGER) lpLastWriteTime, (DWORD *)&req->write_time );
3037 else
3038 req->write_time = 0; /* FIXME */
3039 ret = !wine_server_call_err( req );
3041 SERVER_END_REQ;
3042 return ret;
3046 /**************************************************************************
3047 * LockFile (KERNEL32.@)
3049 BOOL WINAPI LockFile( HANDLE hFile, DWORD dwFileOffsetLow, DWORD dwFileOffsetHigh,
3050 DWORD nNumberOfBytesToLockLow, DWORD nNumberOfBytesToLockHigh )
3052 BOOL ret;
3054 FIXME("not implemented in server\n");
3056 SERVER_START_REQ( lock_file )
3058 req->handle = hFile;
3059 req->offset_low = dwFileOffsetLow;
3060 req->offset_high = dwFileOffsetHigh;
3061 req->count_low = nNumberOfBytesToLockLow;
3062 req->count_high = nNumberOfBytesToLockHigh;
3063 ret = !wine_server_call_err( req );
3065 SERVER_END_REQ;
3066 return ret;
3069 /**************************************************************************
3070 * LockFileEx [KERNEL32.@]
3072 * Locks a byte range within an open file for shared or exclusive access.
3074 * RETURNS
3075 * success: TRUE
3076 * failure: FALSE
3078 * NOTES
3079 * Per Microsoft docs, the third parameter (reserved) must be set to 0.
3081 BOOL WINAPI LockFileEx( HANDLE hFile, DWORD flags, DWORD reserved,
3082 DWORD nNumberOfBytesToLockLow, DWORD nNumberOfBytesToLockHigh,
3083 LPOVERLAPPED pOverlapped )
3085 FIXME("hFile=%d,flags=%ld,reserved=%ld,lowbytes=%ld,highbytes=%ld,overlapped=%p: stub.\n",
3086 hFile, flags, reserved, nNumberOfBytesToLockLow, nNumberOfBytesToLockHigh,
3087 pOverlapped);
3088 if (reserved == 0)
3089 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
3090 else
3092 ERR("reserved == %ld: Supposed to be 0??\n", reserved);
3093 SetLastError(ERROR_INVALID_PARAMETER);
3096 return FALSE;
3100 /**************************************************************************
3101 * UnlockFile (KERNEL32.@)
3103 BOOL WINAPI UnlockFile( HANDLE hFile, DWORD dwFileOffsetLow, DWORD dwFileOffsetHigh,
3104 DWORD nNumberOfBytesToUnlockLow, DWORD nNumberOfBytesToUnlockHigh )
3106 BOOL ret;
3108 FIXME("not implemented in server\n");
3110 SERVER_START_REQ( unlock_file )
3112 req->handle = hFile;
3113 req->offset_low = dwFileOffsetLow;
3114 req->offset_high = dwFileOffsetHigh;
3115 req->count_low = nNumberOfBytesToUnlockLow;
3116 req->count_high = nNumberOfBytesToUnlockHigh;
3117 ret = !wine_server_call_err( req );
3119 SERVER_END_REQ;
3120 return ret;
3124 /**************************************************************************
3125 * UnlockFileEx (KERNEL32.@)
3127 BOOL WINAPI UnlockFileEx(
3128 HANDLE hFile,
3129 DWORD dwReserved,
3130 DWORD nNumberOfBytesToUnlockLow,
3131 DWORD nNumberOfBytesToUnlockHigh,
3132 LPOVERLAPPED lpOverlapped
3135 FIXME("hFile=%d,reserved=%ld,lowbytes=%ld,highbytes=%ld,overlapped=%p: stub.\n",
3136 hFile, dwReserved, nNumberOfBytesToUnlockLow, nNumberOfBytesToUnlockHigh,
3137 lpOverlapped);
3138 if (dwReserved == 0)
3139 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
3140 else
3142 ERR("reserved == %ld: Supposed to be 0??\n", dwReserved);
3143 SetLastError(ERROR_INVALID_PARAMETER);
3146 return FALSE;
3150 #if 0
3152 struct DOS_FILE_LOCK {
3153 struct DOS_FILE_LOCK * next;
3154 DWORD base;
3155 DWORD len;
3156 DWORD processId;
3157 FILE_OBJECT * dos_file;
3158 /* char * unix_name;*/
3161 typedef struct DOS_FILE_LOCK DOS_FILE_LOCK;
3163 static DOS_FILE_LOCK *locks = NULL;
3164 static void DOS_RemoveFileLocks(FILE_OBJECT *file);
3167 /* Locks need to be mirrored because unix file locking is based
3168 * on the pid. Inside of wine there can be multiple WINE processes
3169 * that share the same unix pid.
3170 * Read's and writes should check these locks also - not sure
3171 * how critical that is at this point (FIXME).
3174 static BOOL DOS_AddLock(FILE_OBJECT *file, struct flock *f)
3176 DOS_FILE_LOCK *curr;
3177 DWORD processId;
3179 processId = GetCurrentProcessId();
3181 /* check if lock overlaps a current lock for the same file */
3182 #if 0
3183 for (curr = locks; curr; curr = curr->next) {
3184 if (strcmp(curr->unix_name, file->unix_name) == 0) {
3185 if ((f->l_start == curr->base) && (f->l_len == curr->len))
3186 return TRUE;/* region is identic */
3187 if ((f->l_start < (curr->base + curr->len)) &&
3188 ((f->l_start + f->l_len) > curr->base)) {
3189 /* region overlaps */
3190 return FALSE;
3194 #endif
3196 curr = HeapAlloc( GetProcessHeap(), 0, sizeof(DOS_FILE_LOCK) );
3197 curr->processId = GetCurrentProcessId();
3198 curr->base = f->l_start;
3199 curr->len = f->l_len;
3200 /* curr->unix_name = HEAP_strdupA( GetProcessHeap(), 0, file->unix_name);*/
3201 curr->next = locks;
3202 curr->dos_file = file;
3203 locks = curr;
3204 return TRUE;
3207 static void DOS_RemoveFileLocks(FILE_OBJECT *file)
3209 DWORD processId;
3210 DOS_FILE_LOCK **curr;
3211 DOS_FILE_LOCK *rem;
3213 processId = GetCurrentProcessId();
3214 curr = &locks;
3215 while (*curr) {
3216 if ((*curr)->dos_file == file) {
3217 rem = *curr;
3218 *curr = (*curr)->next;
3219 /* HeapFree( GetProcessHeap(), 0, rem->unix_name );*/
3220 HeapFree( GetProcessHeap(), 0, rem );
3222 else
3223 curr = &(*curr)->next;
3227 static BOOL DOS_RemoveLock(FILE_OBJECT *file, struct flock *f)
3229 DWORD processId;
3230 DOS_FILE_LOCK **curr;
3231 DOS_FILE_LOCK *rem;
3233 processId = GetCurrentProcessId();
3234 for (curr = &locks; *curr; curr = &(*curr)->next) {
3235 if ((*curr)->processId == processId &&
3236 (*curr)->dos_file == file &&
3237 (*curr)->base == f->l_start &&
3238 (*curr)->len == f->l_len) {
3239 /* this is the same lock */
3240 rem = *curr;
3241 *curr = (*curr)->next;
3242 /* HeapFree( GetProcessHeap(), 0, rem->unix_name );*/
3243 HeapFree( GetProcessHeap(), 0, rem );
3244 return TRUE;
3247 /* no matching lock found */
3248 return FALSE;
3252 /**************************************************************************
3253 * LockFile (KERNEL32.@)
3255 BOOL WINAPI LockFile(
3256 HANDLE hFile,DWORD dwFileOffsetLow,DWORD dwFileOffsetHigh,
3257 DWORD nNumberOfBytesToLockLow,DWORD nNumberOfBytesToLockHigh )
3259 struct flock f;
3260 FILE_OBJECT *file;
3262 TRACE("handle %d offsetlow=%ld offsethigh=%ld nbyteslow=%ld nbyteshigh=%ld\n",
3263 hFile, dwFileOffsetLow, dwFileOffsetHigh,
3264 nNumberOfBytesToLockLow, nNumberOfBytesToLockHigh);
3266 if (dwFileOffsetHigh || nNumberOfBytesToLockHigh) {
3267 FIXME("Unimplemented bytes > 32bits\n");
3268 return FALSE;
3271 f.l_start = dwFileOffsetLow;
3272 f.l_len = nNumberOfBytesToLockLow;
3273 f.l_whence = SEEK_SET;
3274 f.l_pid = 0;
3275 f.l_type = F_WRLCK;
3277 if (!(file = FILE_GetFile(hFile,0,NULL))) return FALSE;
3279 /* shadow locks internally */
3280 if (!DOS_AddLock(file, &f)) {
3281 SetLastError( ERROR_LOCK_VIOLATION );
3282 return FALSE;
3285 /* FIXME: Unix locking commented out for now, doesn't work with Excel */
3286 #ifdef USE_UNIX_LOCKS
3287 if (fcntl(file->unix_handle, F_SETLK, &f) == -1) {
3288 if (errno == EACCES || errno == EAGAIN) {
3289 SetLastError( ERROR_LOCK_VIOLATION );
3291 else {
3292 FILE_SetDosError();
3294 /* remove our internal copy of the lock */
3295 DOS_RemoveLock(file, &f);
3296 return FALSE;
3298 #endif
3299 return TRUE;
3303 /**************************************************************************
3304 * UnlockFile (KERNEL32.@)
3306 BOOL WINAPI UnlockFile(
3307 HANDLE hFile,DWORD dwFileOffsetLow,DWORD dwFileOffsetHigh,
3308 DWORD nNumberOfBytesToUnlockLow,DWORD nNumberOfBytesToUnlockHigh )
3310 FILE_OBJECT *file;
3311 struct flock f;
3313 TRACE("handle %d offsetlow=%ld offsethigh=%ld nbyteslow=%ld nbyteshigh=%ld\n",
3314 hFile, dwFileOffsetLow, dwFileOffsetHigh,
3315 nNumberOfBytesToUnlockLow, nNumberOfBytesToUnlockHigh);
3317 if (dwFileOffsetHigh || nNumberOfBytesToUnlockHigh) {
3318 WARN("Unimplemented bytes > 32bits\n");
3319 return FALSE;
3322 f.l_start = dwFileOffsetLow;
3323 f.l_len = nNumberOfBytesToUnlockLow;
3324 f.l_whence = SEEK_SET;
3325 f.l_pid = 0;
3326 f.l_type = F_UNLCK;
3328 if (!(file = FILE_GetFile(hFile,0,NULL))) return FALSE;
3330 DOS_RemoveLock(file, &f); /* ok if fails - may be another wine */
3332 /* FIXME: Unix locking commented out for now, doesn't work with Excel */
3333 #ifdef USE_UNIX_LOCKS
3334 if (fcntl(file->unix_handle, F_SETLK, &f) == -1) {
3335 FILE_SetDosError();
3336 return FALSE;
3338 #endif
3339 return TRUE;
3341 #endif
3343 /**************************************************************************
3344 * GetFileAttributesExW (KERNEL32.@)
3346 BOOL WINAPI GetFileAttributesExW(
3347 LPCWSTR lpFileName, GET_FILEEX_INFO_LEVELS fInfoLevelId,
3348 LPVOID lpFileInformation)
3350 DOS_FULL_NAME full_name;
3351 BY_HANDLE_FILE_INFORMATION info;
3353 if (!lpFileName || !lpFileInformation)
3355 SetLastError(ERROR_INVALID_PARAMETER);
3356 return FALSE;
3359 if (fInfoLevelId == GetFileExInfoStandard) {
3360 LPWIN32_FILE_ATTRIBUTE_DATA lpFad =
3361 (LPWIN32_FILE_ATTRIBUTE_DATA) lpFileInformation;
3362 if (!DOSFS_GetFullName( lpFileName, TRUE, &full_name )) return FALSE;
3363 if (!FILE_Stat( full_name.long_name, &info, NULL )) return FALSE;
3365 lpFad->dwFileAttributes = info.dwFileAttributes;
3366 lpFad->ftCreationTime = info.ftCreationTime;
3367 lpFad->ftLastAccessTime = info.ftLastAccessTime;
3368 lpFad->ftLastWriteTime = info.ftLastWriteTime;
3369 lpFad->nFileSizeHigh = info.nFileSizeHigh;
3370 lpFad->nFileSizeLow = info.nFileSizeLow;
3372 else {
3373 FIXME("invalid info level %d!\n", fInfoLevelId);
3374 return FALSE;
3377 return TRUE;
3381 /**************************************************************************
3382 * GetFileAttributesExA (KERNEL32.@)
3384 BOOL WINAPI GetFileAttributesExA(
3385 LPCSTR filename, GET_FILEEX_INFO_LEVELS fInfoLevelId,
3386 LPVOID lpFileInformation)
3388 UNICODE_STRING filenameW;
3389 BOOL ret = FALSE;
3391 if (!filename || !lpFileInformation)
3393 SetLastError(ERROR_INVALID_PARAMETER);
3394 return FALSE;
3397 if (RtlCreateUnicodeStringFromAsciiz(&filenameW, filename))
3399 ret = GetFileAttributesExW(filenameW.Buffer, fInfoLevelId, lpFileInformation);
3400 RtlFreeUnicodeString(&filenameW);
3402 else
3403 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
3404 return ret;