Roll loop back up to avoid code duplication.
[wine.git] / files / file.c
blob42db9ee30432979bb7b98cd9552ffc20474e9aaa
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 #define NONAMELESSUNION
59 #define NONAMELESSSTRUCT
60 #include "winerror.h"
61 #include "windef.h"
62 #include "winbase.h"
63 #include "winternl.h"
64 #include "wine/winbase16.h"
65 #include "wine/server.h"
67 #include "drive.h"
68 #include "file.h"
69 #include "async.h"
70 #include "heap.h"
71 #include "msdos.h"
72 #include "wincon.h"
74 #include "smb.h"
75 #include "wine/unicode.h"
76 #include "wine/debug.h"
78 WINE_DEFAULT_DEBUG_CHANNEL(file);
80 #if defined(MAP_ANONYMOUS) && !defined(MAP_ANON)
81 #define MAP_ANON MAP_ANONYMOUS
82 #endif
84 /* Size of per-process table of DOS handles */
85 #define DOS_TABLE_SIZE 256
87 /* Macro to derive file offset from OVERLAPPED struct */
88 #define OVERLAPPED_OFFSET(overlapped) ((off_t) (overlapped)->Offset + ((off_t) (overlapped)->OffsetHigh << 32))
90 static HANDLE dos_handles[DOS_TABLE_SIZE];
92 mode_t FILE_umask;
94 extern HANDLE WINAPI FILE_SmbOpen(LPCSTR name);
96 /***********************************************************************
97 * Asynchronous file I/O *
99 static DWORD fileio_get_async_status (const async_private *ovp);
100 static DWORD fileio_get_async_count (const async_private *ovp);
101 static void fileio_set_async_status (async_private *ovp, const DWORD status);
102 static void CALLBACK fileio_call_completion_func (ULONG_PTR data);
103 static void fileio_async_cleanup (async_private *ovp);
105 static async_ops fileio_async_ops =
107 fileio_get_async_status, /* get_status */
108 fileio_set_async_status, /* set_status */
109 fileio_get_async_count, /* get_count */
110 fileio_call_completion_func, /* call_completion */
111 fileio_async_cleanup /* cleanup */
114 static async_ops fileio_nocomp_async_ops =
116 fileio_get_async_status, /* get_status */
117 fileio_set_async_status, /* set_status */
118 fileio_get_async_count, /* get_count */
119 NULL, /* call_completion */
120 fileio_async_cleanup /* cleanup */
123 typedef struct async_fileio
125 struct async_private async;
126 LPOVERLAPPED lpOverlapped;
127 LPOVERLAPPED_COMPLETION_ROUTINE completion_func;
128 char *buffer;
129 unsigned int count;
130 enum fd_type fd_type;
131 } async_fileio;
133 static DWORD fileio_get_async_status (const struct async_private *ovp)
135 return ((async_fileio*) ovp)->lpOverlapped->Internal;
138 static void fileio_set_async_status (async_private *ovp, const DWORD status)
140 ((async_fileio*) ovp)->lpOverlapped->Internal = status;
143 static DWORD fileio_get_async_count (const struct async_private *ovp)
145 async_fileio *fileio = (async_fileio*) ovp;
147 if (fileio->count < fileio->lpOverlapped->InternalHigh)
148 return 0;
149 return fileio->count - fileio->lpOverlapped->InternalHigh;
152 static void CALLBACK fileio_call_completion_func (ULONG_PTR data)
154 async_fileio *ovp = (async_fileio*) data;
155 TRACE ("data: %p\n", ovp);
157 ovp->completion_func( RtlNtStatusToDosError ( ovp->lpOverlapped->Internal ),
158 ovp->lpOverlapped->InternalHigh,
159 ovp->lpOverlapped );
161 fileio_async_cleanup ( &ovp->async );
164 static void fileio_async_cleanup ( struct async_private *ovp )
166 HeapFree ( GetProcessHeap(), 0, ovp );
169 /***********************************************************************
170 * FILE_ConvertOFMode
172 * Convert OF_* mode into flags for CreateFile.
174 static void FILE_ConvertOFMode( INT mode, DWORD *access, DWORD *sharing )
176 switch(mode & 0x03)
178 case OF_READ: *access = GENERIC_READ; break;
179 case OF_WRITE: *access = GENERIC_WRITE; break;
180 case OF_READWRITE: *access = GENERIC_READ | GENERIC_WRITE; break;
181 default: *access = 0; break;
183 switch(mode & 0x70)
185 case OF_SHARE_EXCLUSIVE: *sharing = 0; break;
186 case OF_SHARE_DENY_WRITE: *sharing = FILE_SHARE_READ; break;
187 case OF_SHARE_DENY_READ: *sharing = FILE_SHARE_WRITE; break;
188 case OF_SHARE_DENY_NONE:
189 case OF_SHARE_COMPAT:
190 default: *sharing = FILE_SHARE_READ | FILE_SHARE_WRITE; break;
195 /***********************************************************************
196 * FILE_strcasecmp
198 * locale-independent case conversion for file I/O
200 int FILE_strcasecmp( const char *str1, const char *str2 )
202 int ret = 0;
203 for ( ; ; str1++, str2++)
204 if ((ret = FILE_toupper(*str1) - FILE_toupper(*str2)) || !*str1) break;
205 return ret;
209 /***********************************************************************
210 * FILE_strncasecmp
212 * locale-independent case conversion for file I/O
214 int FILE_strncasecmp( const char *str1, const char *str2, int len )
216 int ret = 0;
217 for ( ; len > 0; len--, str1++, str2++)
218 if ((ret = FILE_toupper(*str1) - FILE_toupper(*str2)) || !*str1) break;
219 return ret;
223 /***********************************************************************
224 * FILE_GetNtStatus(void)
226 * Retrieve the Nt Status code from errno.
227 * Try to be consistent with FILE_SetDosError().
229 DWORD FILE_GetNtStatus(void)
231 int err = errno;
232 DWORD nt;
233 TRACE ( "errno = %d\n", errno );
234 switch ( err )
236 case EAGAIN: nt = STATUS_SHARING_VIOLATION; break;
237 case EBADF: nt = STATUS_INVALID_HANDLE; break;
238 case ENOSPC: nt = STATUS_DISK_FULL; break;
239 case EPERM:
240 case EROFS:
241 case EACCES: nt = STATUS_ACCESS_DENIED; break;
242 case ENOENT: nt = STATUS_SHARING_VIOLATION; break;
243 case EISDIR: nt = STATUS_FILE_IS_A_DIRECTORY; break;
244 case EMFILE:
245 case ENFILE: nt = STATUS_NO_MORE_FILES; break;
246 case EINVAL:
247 case ENOTEMPTY: nt = STATUS_DIRECTORY_NOT_EMPTY; break;
248 case EPIPE: nt = STATUS_PIPE_BROKEN; break;
249 case ENOEXEC: /* ?? */
250 case ESPIPE: /* ?? */
251 case EEXIST: /* ?? */
252 default:
253 FIXME ( "Converting errno %d to STATUS_UNSUCCESSFUL\n", err );
254 nt = STATUS_UNSUCCESSFUL;
256 return nt;
259 /***********************************************************************
260 * FILE_SetDosError
262 * Set the DOS error code from errno.
264 void FILE_SetDosError(void)
266 int save_errno = errno; /* errno gets overwritten by printf */
268 TRACE("errno = %d %s\n", errno, strerror(errno));
269 switch (save_errno)
271 case EAGAIN:
272 SetLastError( ERROR_SHARING_VIOLATION );
273 break;
274 case EBADF:
275 SetLastError( ERROR_INVALID_HANDLE );
276 break;
277 case ENOSPC:
278 SetLastError( ERROR_HANDLE_DISK_FULL );
279 break;
280 case EACCES:
281 case EPERM:
282 case EROFS:
283 SetLastError( ERROR_ACCESS_DENIED );
284 break;
285 case EBUSY:
286 SetLastError( ERROR_LOCK_VIOLATION );
287 break;
288 case ENOENT:
289 SetLastError( ERROR_FILE_NOT_FOUND );
290 break;
291 case EISDIR:
292 SetLastError( ERROR_CANNOT_MAKE );
293 break;
294 case ENFILE:
295 case EMFILE:
296 SetLastError( ERROR_NO_MORE_FILES );
297 break;
298 case EEXIST:
299 SetLastError( ERROR_FILE_EXISTS );
300 break;
301 case EINVAL:
302 case ESPIPE:
303 SetLastError( ERROR_SEEK );
304 break;
305 case ENOTEMPTY:
306 SetLastError( ERROR_DIR_NOT_EMPTY );
307 break;
308 case ENOEXEC:
309 SetLastError( ERROR_BAD_FORMAT );
310 break;
311 default:
312 WARN("unknown file error: %s\n", strerror(save_errno) );
313 SetLastError( ERROR_GEN_FAILURE );
314 break;
316 errno = save_errno;
320 /***********************************************************************
321 * FILE_GetUnixHandleType
323 * Retrieve the Unix handle corresponding to a file handle.
324 * Returns -1 on failure.
326 static int FILE_GetUnixHandleType( HANDLE handle, DWORD access, enum fd_type *type, int *flags_ptr )
328 int ret, flags, fd = -1;
330 ret = wine_server_handle_to_fd( handle, access, &fd, type, &flags );
331 if (flags_ptr) *flags_ptr = flags;
332 if (ret) SetLastError( RtlNtStatusToDosError(ret) );
333 else if (((access & GENERIC_READ) && (flags & FD_FLAG_RECV_SHUTDOWN)) ||
334 ((access & GENERIC_WRITE) && (flags & FD_FLAG_SEND_SHUTDOWN)))
336 close (fd);
337 SetLastError ( ERROR_PIPE_NOT_CONNECTED );
338 return -1;
340 return fd;
343 /***********************************************************************
344 * FILE_GetUnixHandle
346 * Retrieve the Unix handle corresponding to a file handle.
347 * Returns -1 on failure.
349 int FILE_GetUnixHandle( HANDLE handle, DWORD access )
351 return FILE_GetUnixHandleType( handle, access, NULL, NULL );
354 /*************************************************************************
355 * FILE_OpenConsole
357 * Open a handle to the current process console.
358 * Returns 0 on failure.
360 static HANDLE FILE_OpenConsole( BOOL output, DWORD access, DWORD sharing, LPSECURITY_ATTRIBUTES sa )
362 HANDLE ret;
364 SERVER_START_REQ( open_console )
366 req->from = output;
367 req->access = access;
368 req->share = sharing;
369 req->inherit = (sa && (sa->nLength>=sizeof(*sa)) && sa->bInheritHandle);
370 SetLastError(0);
371 wine_server_call_err( req );
372 ret = reply->handle;
374 SERVER_END_REQ;
375 return ret;
378 /* FIXME: those routines defined as pointers are needed, because this file is
379 * currently compiled into NTDLL whereas it belongs to kernel32.
380 * this shall go away once all the DLL separation process is done
382 typedef BOOL (WINAPI* pRW)(HANDLE, const void*, DWORD, DWORD*, void*);
384 static BOOL FILE_ReadConsole(HANDLE hCon, void* buf, DWORD nb, DWORD* nr, void* p)
386 static HANDLE hKernel /* = 0 */;
387 static pRW pReadConsole /* = 0 */;
389 if ((!hKernel && !(hKernel = LoadLibraryA("kernel32"))) ||
390 (!pReadConsole &&
391 !(pReadConsole = GetProcAddress(hKernel, "ReadConsoleA"))))
393 *nr = 0;
394 return 0;
396 return (pReadConsole)(hCon, buf, nb, nr, p);
399 static BOOL FILE_WriteConsole(HANDLE hCon, const void* buf, DWORD nb, DWORD* nr, void* p)
401 static HANDLE hKernel /* = 0 */;
402 static pRW pWriteConsole /* = 0 */;
404 if ((!hKernel && !(hKernel = LoadLibraryA("kernel32"))) ||
405 (!pWriteConsole &&
406 !(pWriteConsole = GetProcAddress(hKernel, "WriteConsoleA"))))
408 *nr = 0;
409 return 0;
411 return (pWriteConsole)(hCon, buf, nb, nr, p);
413 /* end of FIXME */
415 /***********************************************************************
416 * FILE_CreateFile
418 * Implementation of CreateFile. Takes a Unix path name.
419 * Returns 0 on failure.
421 HANDLE FILE_CreateFile( LPCSTR filename, DWORD access, DWORD sharing,
422 LPSECURITY_ATTRIBUTES sa, DWORD creation,
423 DWORD attributes, HANDLE template, BOOL fail_read_only,
424 UINT drive_type )
426 unsigned int err;
427 HANDLE ret;
429 for (;;)
431 SERVER_START_REQ( create_file )
433 req->access = access;
434 req->inherit = (sa && (sa->nLength>=sizeof(*sa)) && sa->bInheritHandle);
435 req->sharing = sharing;
436 req->create = creation;
437 req->attrs = attributes;
438 req->drive_type = drive_type;
439 wine_server_add_data( req, filename, strlen(filename) );
440 SetLastError(0);
441 err = wine_server_call( req );
442 ret = reply->handle;
444 SERVER_END_REQ;
446 /* If write access failed, retry without GENERIC_WRITE */
448 if (!ret && !fail_read_only && (access & GENERIC_WRITE))
450 if ((err == STATUS_MEDIA_WRITE_PROTECTED) || (err == STATUS_ACCESS_DENIED))
452 TRACE("Write access failed for file '%s', trying without "
453 "write access\n", filename);
454 access &= ~GENERIC_WRITE;
455 continue;
459 if (err)
461 /* In the case file creation was rejected due to CREATE_NEW flag
462 * was specified and file with that name already exists, correct
463 * last error is ERROR_FILE_EXISTS and not ERROR_ALREADY_EXISTS.
464 * Note: RtlNtStatusToDosError is not the subject to blame here.
466 if (err == STATUS_OBJECT_NAME_COLLISION)
467 SetLastError( ERROR_FILE_EXISTS );
468 else
469 SetLastError( RtlNtStatusToDosError(err) );
472 if (!ret) WARN("Unable to create file '%s' (GLE %ld)\n", filename, GetLastError());
473 return ret;
478 /***********************************************************************
479 * FILE_CreateDevice
481 * Same as FILE_CreateFile but for a device
482 * Returns 0 on failure.
484 HANDLE FILE_CreateDevice( int client_id, DWORD access, LPSECURITY_ATTRIBUTES sa )
486 HANDLE ret;
487 SERVER_START_REQ( create_device )
489 req->access = access;
490 req->inherit = (sa && (sa->nLength>=sizeof(*sa)) && sa->bInheritHandle);
491 req->id = client_id;
492 SetLastError(0);
493 wine_server_call_err( req );
494 ret = reply->handle;
496 SERVER_END_REQ;
497 return ret;
500 static HANDLE FILE_OpenPipe(LPCWSTR name, DWORD access)
502 HANDLE ret;
503 DWORD len = 0;
505 if (name && (len = strlenW(name)) > MAX_PATH)
507 SetLastError( ERROR_FILENAME_EXCED_RANGE );
508 return 0;
510 SERVER_START_REQ( open_named_pipe )
512 req->access = access;
513 SetLastError(0);
514 wine_server_add_data( req, name, len * sizeof(WCHAR) );
515 wine_server_call_err( req );
516 ret = reply->handle;
518 SERVER_END_REQ;
519 TRACE("Returned %p\n",ret);
520 return ret;
523 /*************************************************************************
524 * CreateFileW [KERNEL32.@] Creates or opens a file or other object
526 * Creates or opens an object, and returns a handle that can be used to
527 * access that object.
529 * PARAMS
531 * filename [in] pointer to filename to be accessed
532 * access [in] access mode requested
533 * sharing [in] share mode
534 * sa [in] pointer to security attributes
535 * creation [in] how to create the file
536 * attributes [in] attributes for newly created file
537 * template [in] handle to file with extended attributes to copy
539 * RETURNS
540 * Success: Open handle to specified file
541 * Failure: INVALID_HANDLE_VALUE
543 * NOTES
544 * Should call SetLastError() on failure.
546 * BUGS
548 * Doesn't support character devices, template files, or a
549 * lot of the 'attributes' flags yet.
551 HANDLE WINAPI CreateFileW( LPCWSTR filename, DWORD access, DWORD sharing,
552 LPSECURITY_ATTRIBUTES sa, DWORD creation,
553 DWORD attributes, HANDLE template )
555 DOS_FULL_NAME full_name;
556 HANDLE ret;
557 static const WCHAR bkslashes_with_question_markW[] = {'\\','\\','?','\\',0};
558 static const WCHAR bkslashes_with_dotW[] = {'\\','\\','.','\\',0};
559 static const WCHAR bkslashesW[] = {'\\','\\',0};
560 static const WCHAR coninW[] = {'C','O','N','I','N','$',0};
561 static const WCHAR conoutW[] = {'C','O','N','O','U','T','$',0};
563 if (!filename)
565 SetLastError( ERROR_INVALID_PARAMETER );
566 return INVALID_HANDLE_VALUE;
568 TRACE("%s %s%s%s%s%s%s%s attributes 0x%lx\n", debugstr_w(filename),
569 ((access & GENERIC_READ)==GENERIC_READ)?"GENERIC_READ ":"",
570 ((access & GENERIC_WRITE)==GENERIC_WRITE)?"GENERIC_WRITE ":"",
571 (!access)?"QUERY_ACCESS ":"",
572 ((sharing & FILE_SHARE_READ)==FILE_SHARE_READ)?"FILE_SHARE_READ ":"",
573 ((sharing & FILE_SHARE_WRITE)==FILE_SHARE_WRITE)?"FILE_SHARE_WRITE ":"",
574 ((sharing & FILE_SHARE_DELETE)==FILE_SHARE_DELETE)?"FILE_SHARE_DELETE ":"",
575 (creation ==CREATE_NEW)?"CREATE_NEW":
576 (creation ==CREATE_ALWAYS)?"CREATE_ALWAYS ":
577 (creation ==OPEN_EXISTING)?"OPEN_EXISTING ":
578 (creation ==OPEN_ALWAYS)?"OPEN_ALWAYS ":
579 (creation ==TRUNCATE_EXISTING)?"TRUNCATE_EXISTING ":"", attributes);
581 /* If the name starts with '\\?\', ignore the first 4 chars. */
582 if (!strncmpW(filename, bkslashes_with_question_markW, 4))
584 static const WCHAR uncW[] = {'U','N','C','\\',0};
585 filename += 4;
586 if (!strncmpiW(filename, uncW, 4))
588 FIXME("UNC name (%s) not supported.\n", debugstr_w(filename) );
589 SetLastError( ERROR_PATH_NOT_FOUND );
590 return INVALID_HANDLE_VALUE;
594 if (!strncmpW(filename, bkslashes_with_dotW, 4))
596 static const WCHAR pipeW[] = {'P','I','P','E','\\',0};
597 if(!strncmpiW(filename + 4, pipeW, 5))
599 TRACE("Opening a pipe: %s\n", debugstr_w(filename));
600 ret = FILE_OpenPipe(filename,access);
601 goto done;
603 else if (isalphaW(filename[4]) && filename[5] == ':' && filename[6] == '\0')
605 ret = FILE_CreateDevice( (toupperW(filename[4]) - 'A') | 0x20000, access, sa );
606 goto done;
608 else if (!DOSFS_GetDevice( filename ))
610 ret = DEVICE_Open( filename+4, access, sa );
611 goto done;
613 else
614 filename+=4; /* fall into DOSFS_Device case below */
617 /* If the name still starts with '\\', it's a UNC name. */
618 if (!strncmpW(filename, bkslashesW, 2))
620 ret = SMB_CreateFileW(filename, access, sharing, sa, creation, attributes, template );
621 goto done;
624 /* If the name contains a DOS wild card (* or ?), do no create a file */
625 if(strchrW(filename, '*') || strchrW(filename, '?'))
627 SetLastError(ERROR_BAD_PATHNAME);
628 return INVALID_HANDLE_VALUE;
631 /* Open a console for CONIN$ or CONOUT$ */
632 if (!strcmpiW(filename, coninW))
634 ret = FILE_OpenConsole( FALSE, access, sharing, sa );
635 goto done;
637 if (!strcmpiW(filename, conoutW))
639 ret = FILE_OpenConsole( TRUE, access, sharing, sa );
640 goto done;
643 if (DOSFS_GetDevice( filename ))
645 TRACE("opening device %s\n", debugstr_w(filename) );
647 if (!(ret = DOSFS_OpenDevice( filename, access, attributes, sa )))
649 /* Do not silence this please. It is a critical error. -MM */
650 ERR("Couldn't open device %s!\n", debugstr_w(filename));
651 SetLastError( ERROR_FILE_NOT_FOUND );
653 goto done;
656 /* check for filename, don't check for last entry if creating */
657 if (!DOSFS_GetFullName( filename,
658 (creation == OPEN_EXISTING) ||
659 (creation == TRUNCATE_EXISTING),
660 &full_name )) {
661 WARN("Unable to get full filename from %s (GLE %ld)\n",
662 debugstr_w(filename), GetLastError());
663 return INVALID_HANDLE_VALUE;
666 ret = FILE_CreateFile( full_name.long_name, access, sharing,
667 sa, creation, attributes, template,
668 DRIVE_GetFlags(full_name.drive) & DRIVE_FAIL_READ_ONLY,
669 GetDriveTypeW( full_name.short_name ) );
670 done:
671 if (!ret) ret = INVALID_HANDLE_VALUE;
672 TRACE("returning %p\n", ret);
673 return ret;
678 /*************************************************************************
679 * CreateFileA (KERNEL32.@)
681 HANDLE WINAPI CreateFileA( LPCSTR filename, DWORD access, DWORD sharing,
682 LPSECURITY_ATTRIBUTES sa, DWORD creation,
683 DWORD attributes, HANDLE template)
685 UNICODE_STRING filenameW;
686 HANDLE ret = INVALID_HANDLE_VALUE;
688 if (!filename)
690 SetLastError( ERROR_INVALID_PARAMETER );
691 return INVALID_HANDLE_VALUE;
694 if (RtlCreateUnicodeStringFromAsciiz(&filenameW, filename))
696 ret = CreateFileW(filenameW.Buffer, access, sharing, sa, creation,
697 attributes, template);
698 RtlFreeUnicodeString(&filenameW);
700 else
701 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
702 return ret;
706 /***********************************************************************
707 * FILE_FillInfo
709 * Fill a file information from a struct stat.
711 static void FILE_FillInfo( struct stat *st, BY_HANDLE_FILE_INFORMATION *info )
713 if (S_ISDIR(st->st_mode))
714 info->dwFileAttributes = FILE_ATTRIBUTE_DIRECTORY;
715 else
716 info->dwFileAttributes = FILE_ATTRIBUTE_ARCHIVE;
717 if (!(st->st_mode & S_IWUSR))
718 info->dwFileAttributes |= FILE_ATTRIBUTE_READONLY;
720 RtlSecondsSince1970ToTime( st->st_mtime, (LARGE_INTEGER *)&info->ftCreationTime );
721 RtlSecondsSince1970ToTime( st->st_mtime, (LARGE_INTEGER *)&info->ftLastWriteTime );
722 RtlSecondsSince1970ToTime( st->st_atime, (LARGE_INTEGER *)&info->ftLastAccessTime );
724 info->dwVolumeSerialNumber = 0; /* FIXME */
725 info->nFileSizeHigh = 0;
726 info->nFileSizeLow = 0;
727 if (!S_ISDIR(st->st_mode)) {
728 info->nFileSizeHigh = st->st_size >> 32;
729 info->nFileSizeLow = st->st_size & 0xffffffff;
731 info->nNumberOfLinks = st->st_nlink;
732 info->nFileIndexHigh = 0;
733 info->nFileIndexLow = st->st_ino;
737 /***********************************************************************
738 * FILE_Stat
740 * Stat a Unix path name. Return TRUE if OK.
742 BOOL FILE_Stat( LPCSTR unixName, BY_HANDLE_FILE_INFORMATION *info, BOOL *is_symlink_ptr )
744 struct stat st;
745 int is_symlink;
746 LPCSTR p;
748 if (lstat( unixName, &st ) == -1)
750 FILE_SetDosError();
751 return FALSE;
753 is_symlink = S_ISLNK(st.st_mode);
754 if (is_symlink)
756 /* do a "real" stat to find out
757 about the type of the symlink destination */
758 if (stat( unixName, &st ) == -1)
760 FILE_SetDosError();
761 return FALSE;
765 /* fill in the information we gathered so far */
766 FILE_FillInfo( &st, info );
768 /* and now see if this is a hidden file, based on the name */
769 p = strrchr( unixName, '/');
770 p = p ? p + 1 : unixName;
771 if (*p == '.' && *(p+1) && (*(p+1) != '.' || *(p+2)))
773 static const WCHAR wineW[] = {'w','i','n','e',0};
774 static const WCHAR ShowDotFilesW[] = {'S','h','o','w','D','o','t','F','i','l','e','s',0};
775 static int show_dot_files = -1;
776 if (show_dot_files == -1)
777 show_dot_files = PROFILE_GetWineIniBool(wineW, ShowDotFilesW, 0);
778 if (!show_dot_files)
779 info->dwFileAttributes |= FILE_ATTRIBUTE_HIDDEN;
781 if (is_symlink_ptr) *is_symlink_ptr = is_symlink;
782 return TRUE;
786 /***********************************************************************
787 * GetFileInformationByHandle (KERNEL32.@)
789 DWORD WINAPI GetFileInformationByHandle( HANDLE hFile,
790 BY_HANDLE_FILE_INFORMATION *info )
792 DWORD ret;
793 if (!info) return 0;
795 TRACE("%p\n", hFile);
797 SERVER_START_REQ( get_file_info )
799 req->handle = hFile;
800 if ((ret = !wine_server_call_err( req )))
802 /* FIXME: which file types are supported ?
803 * Serial ports (FILE_TYPE_CHAR) are not,
804 * and MSDN also says that pipes are not supported.
805 * FILE_TYPE_REMOTE seems to be supported according to
806 * MSDN q234741.txt */
807 if ((reply->type == FILE_TYPE_DISK) || (reply->type == FILE_TYPE_REMOTE))
809 RtlSecondsSince1970ToTime( reply->write_time, (LARGE_INTEGER *)&info->ftCreationTime );
810 RtlSecondsSince1970ToTime( reply->write_time, (LARGE_INTEGER *)&info->ftLastWriteTime );
811 RtlSecondsSince1970ToTime( reply->access_time, (LARGE_INTEGER *)&info->ftLastAccessTime );
812 info->dwFileAttributes = reply->attr;
813 info->dwVolumeSerialNumber = reply->serial;
814 info->nFileSizeHigh = reply->size_high;
815 info->nFileSizeLow = reply->size_low;
816 info->nNumberOfLinks = reply->links;
817 info->nFileIndexHigh = reply->index_high;
818 info->nFileIndexLow = reply->index_low;
820 else
822 SetLastError(ERROR_NOT_SUPPORTED);
823 ret = 0;
827 SERVER_END_REQ;
828 return ret;
832 /**************************************************************************
833 * GetFileAttributes (KERNEL.420)
835 DWORD WINAPI GetFileAttributes16( LPCSTR name )
837 return GetFileAttributesA( name );
841 /**************************************************************************
842 * GetFileAttributesW (KERNEL32.@)
844 DWORD WINAPI GetFileAttributesW( LPCWSTR name )
846 DOS_FULL_NAME full_name;
847 BY_HANDLE_FILE_INFORMATION info;
849 if (name == NULL)
851 SetLastError( ERROR_INVALID_PARAMETER );
852 return -1;
854 if (!DOSFS_GetFullName( name, TRUE, &full_name) )
855 return -1;
856 if (!FILE_Stat( full_name.long_name, &info, NULL )) return -1;
857 return info.dwFileAttributes;
861 /**************************************************************************
862 * GetFileAttributesA (KERNEL32.@)
864 DWORD WINAPI GetFileAttributesA( LPCSTR name )
866 UNICODE_STRING nameW;
867 DWORD ret = (DWORD)-1;
869 if (!name)
871 SetLastError( ERROR_INVALID_PARAMETER );
872 return (DWORD)-1;
875 if (RtlCreateUnicodeStringFromAsciiz(&nameW, name))
877 ret = GetFileAttributesW(nameW.Buffer);
878 RtlFreeUnicodeString(&nameW);
880 else
881 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
882 return ret;
886 /**************************************************************************
887 * SetFileAttributes (KERNEL.421)
889 BOOL16 WINAPI SetFileAttributes16( LPCSTR lpFileName, DWORD attributes )
891 return SetFileAttributesA( lpFileName, attributes );
895 /**************************************************************************
896 * SetFileAttributesW (KERNEL32.@)
898 BOOL WINAPI SetFileAttributesW(LPCWSTR lpFileName, DWORD attributes)
900 struct stat buf;
901 DOS_FULL_NAME full_name;
903 if (!lpFileName)
905 SetLastError( ERROR_INVALID_PARAMETER );
906 return FALSE;
909 TRACE("(%s,%lx)\n", debugstr_w(lpFileName), attributes);
911 if (!DOSFS_GetFullName( lpFileName, TRUE, &full_name ))
912 return FALSE;
914 if(stat(full_name.long_name,&buf)==-1)
916 FILE_SetDosError();
917 return FALSE;
919 if (attributes & FILE_ATTRIBUTE_READONLY)
921 if(S_ISDIR(buf.st_mode))
922 /* FIXME */
923 WARN("FILE_ATTRIBUTE_READONLY ignored for directory.\n");
924 else
925 buf.st_mode &= ~0222; /* octal!, clear write permission bits */
926 attributes &= ~FILE_ATTRIBUTE_READONLY;
928 else
930 /* add write permission */
931 buf.st_mode |= (0600 | ((buf.st_mode & 044) >> 1)) & (~FILE_umask);
933 if (attributes & FILE_ATTRIBUTE_DIRECTORY)
935 if (!S_ISDIR(buf.st_mode))
936 FIXME("SetFileAttributes expected the file %s to be a directory\n",
937 debugstr_w(lpFileName));
938 attributes &= ~FILE_ATTRIBUTE_DIRECTORY;
940 attributes &= ~(FILE_ATTRIBUTE_NORMAL|FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_HIDDEN|FILE_ATTRIBUTE_SYSTEM);
941 if (attributes)
942 FIXME("(%s):%lx attribute(s) not implemented.\n", debugstr_w(lpFileName), attributes);
943 if (-1==chmod(full_name.long_name,buf.st_mode))
945 if (GetDriveTypeW(lpFileName) == DRIVE_CDROM)
947 SetLastError( ERROR_ACCESS_DENIED );
948 return FALSE;
952 * FIXME: We don't return FALSE here because of differences between
953 * Linux and Windows privileges. Under Linux only the owner of
954 * the file is allowed to change file attributes. Under Windows,
955 * applications expect that if you can write to a file, you can also
956 * change its attributes (see GENERIC_WRITE). We could try to be
957 * clever here but that would break multi-user installations where
958 * users share read-only DLLs. This is because some installers like
959 * to change attributes of already installed DLLs.
961 FIXME("Couldn't set file attributes for existing file \"%s\".\n"
962 "Check permissions or set VFAT \"quiet\" mount flag\n", full_name.long_name);
964 return TRUE;
968 /**************************************************************************
969 * SetFileAttributesA (KERNEL32.@)
971 BOOL WINAPI SetFileAttributesA(LPCSTR lpFileName, DWORD attributes)
973 UNICODE_STRING filenameW;
974 BOOL ret = FALSE;
976 if (!lpFileName)
978 SetLastError( ERROR_INVALID_PARAMETER );
979 return FALSE;
982 if (RtlCreateUnicodeStringFromAsciiz(&filenameW, lpFileName))
984 ret = SetFileAttributesW(filenameW.Buffer, attributes);
985 RtlFreeUnicodeString(&filenameW);
987 else
988 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
989 return ret;
993 /***********************************************************************
994 * GetFileSize (KERNEL32.@)
996 DWORD WINAPI GetFileSize( HANDLE hFile, LPDWORD filesizehigh )
998 BY_HANDLE_FILE_INFORMATION info;
999 if (!GetFileInformationByHandle( hFile, &info )) return -1;
1000 if (filesizehigh) *filesizehigh = info.nFileSizeHigh;
1001 return info.nFileSizeLow;
1005 /***********************************************************************
1006 * GetFileSizeEx (KERNEL32.@)
1008 BOOL WINAPI GetFileSizeEx( HANDLE hFile, PLARGE_INTEGER lpFileSize )
1010 BY_HANDLE_FILE_INFORMATION info;
1012 if (!lpFileSize)
1014 SetLastError( ERROR_INVALID_PARAMETER );
1015 return FALSE;
1018 if (!GetFileInformationByHandle( hFile, &info ))
1020 return FALSE;
1023 lpFileSize->s.LowPart = info.nFileSizeLow;
1024 lpFileSize->s.HighPart = info.nFileSizeHigh;
1026 return TRUE;
1030 /***********************************************************************
1031 * GetFileTime (KERNEL32.@)
1033 BOOL WINAPI GetFileTime( HANDLE hFile, FILETIME *lpCreationTime,
1034 FILETIME *lpLastAccessTime,
1035 FILETIME *lpLastWriteTime )
1037 BY_HANDLE_FILE_INFORMATION info;
1038 if (!GetFileInformationByHandle( hFile, &info )) return FALSE;
1039 if (lpCreationTime) *lpCreationTime = info.ftCreationTime;
1040 if (lpLastAccessTime) *lpLastAccessTime = info.ftLastAccessTime;
1041 if (lpLastWriteTime) *lpLastWriteTime = info.ftLastWriteTime;
1042 return TRUE;
1045 /***********************************************************************
1046 * FILE_GetTempFileName : utility for GetTempFileName
1048 static UINT FILE_GetTempFileName( LPCWSTR path, LPCWSTR prefix, UINT unique,
1049 LPWSTR buffer )
1051 static UINT unique_temp;
1052 DOS_FULL_NAME full_name;
1053 int i;
1054 LPWSTR p;
1055 UINT num;
1056 char buf[20];
1058 if ( !path || !prefix || !buffer )
1060 SetLastError( ERROR_INVALID_PARAMETER );
1061 return 0;
1064 if (!unique_temp) unique_temp = time(NULL) & 0xffff;
1065 num = unique ? (unique & 0xffff) : (unique_temp++ & 0xffff);
1067 strcpyW( buffer, path );
1068 p = buffer + strlenW(buffer);
1070 /* add a \, if there isn't one and path is more than just the drive letter ... */
1071 if ( !((strlenW(buffer) == 2) && (buffer[1] == ':'))
1072 && ((p == buffer) || (p[-1] != '\\'))) *p++ = '\\';
1074 for (i = 3; (i > 0) && (*prefix); i--) *p++ = *prefix++;
1076 sprintf( buf, "%04x.tmp", num );
1077 MultiByteToWideChar(CP_ACP, 0, buf, -1, p, 20);
1079 /* Now try to create it */
1081 if (!unique)
1085 HANDLE handle = CreateFileW( buffer, GENERIC_WRITE, 0, NULL,
1086 CREATE_NEW, FILE_ATTRIBUTE_NORMAL, 0 );
1087 if (handle != INVALID_HANDLE_VALUE)
1088 { /* We created it */
1089 TRACE("created %s\n", debugstr_w(buffer) );
1090 CloseHandle( handle );
1091 break;
1093 if (GetLastError() != ERROR_FILE_EXISTS)
1094 break; /* No need to go on */
1095 num++;
1096 sprintf( buf, "%04x.tmp", num );
1097 MultiByteToWideChar(CP_ACP, 0, buf, -1, p, 20);
1098 } while (num != (unique & 0xffff));
1101 /* Get the full path name */
1103 if (DOSFS_GetFullName( buffer, FALSE, &full_name ))
1105 char *slash;
1106 /* Check if we have write access in the directory */
1107 if ((slash = strrchr( full_name.long_name, '/' ))) *slash = '\0';
1108 if (access( full_name.long_name, W_OK ) == -1)
1109 WARN("returns %s, which doesn't seem to be writeable.\n",
1110 debugstr_w(buffer) );
1112 TRACE("returning %s\n", debugstr_w(buffer) );
1113 return unique ? unique : num;
1117 /***********************************************************************
1118 * GetTempFileNameA (KERNEL32.@)
1120 UINT WINAPI GetTempFileNameA( LPCSTR path, LPCSTR prefix, UINT unique,
1121 LPSTR buffer)
1123 UNICODE_STRING pathW, prefixW;
1124 WCHAR bufferW[MAX_PATH];
1125 UINT ret;
1127 if ( !path || !prefix || !buffer )
1129 SetLastError( ERROR_INVALID_PARAMETER );
1130 return 0;
1133 RtlCreateUnicodeStringFromAsciiz(&pathW, path);
1134 RtlCreateUnicodeStringFromAsciiz(&prefixW, prefix);
1136 ret = GetTempFileNameW(pathW.Buffer, prefixW.Buffer, unique, bufferW);
1137 if (ret)
1138 WideCharToMultiByte(CP_ACP, 0, bufferW, -1, buffer, MAX_PATH, NULL, NULL);
1140 RtlFreeUnicodeString(&pathW);
1141 RtlFreeUnicodeString(&prefixW);
1142 return ret;
1145 /***********************************************************************
1146 * GetTempFileNameW (KERNEL32.@)
1148 UINT WINAPI GetTempFileNameW( LPCWSTR path, LPCWSTR prefix, UINT unique,
1149 LPWSTR buffer )
1151 return FILE_GetTempFileName( path, prefix, unique, buffer );
1155 /***********************************************************************
1156 * GetTempFileName (KERNEL.97)
1158 UINT16 WINAPI GetTempFileName16( BYTE drive, LPCSTR prefix, UINT16 unique,
1159 LPSTR buffer )
1161 char temppath[MAX_PATH];
1162 char *prefix16 = NULL;
1163 UINT16 ret;
1165 if (!(drive & ~TF_FORCEDRIVE)) /* drive 0 means current default drive */
1166 drive |= DRIVE_GetCurrentDrive() + 'A';
1168 if ((drive & TF_FORCEDRIVE) &&
1169 !DRIVE_IsValid( toupper(drive & ~TF_FORCEDRIVE) - 'A' ))
1171 drive &= ~TF_FORCEDRIVE;
1172 WARN("invalid drive %d specified\n", drive );
1175 if (drive & TF_FORCEDRIVE)
1176 sprintf(temppath,"%c:", drive & ~TF_FORCEDRIVE );
1177 else
1178 GetTempPathA( MAX_PATH, temppath );
1180 if (prefix)
1182 prefix16 = HeapAlloc(GetProcessHeap(), 0, strlen(prefix) + 2);
1183 *prefix16 = '~';
1184 strcpy(prefix16 + 1, prefix);
1187 ret = GetTempFileNameA( temppath, prefix16, unique, buffer );
1189 if (prefix16) HeapFree(GetProcessHeap(), 0, prefix16);
1190 return ret;
1193 /***********************************************************************
1194 * FILE_DoOpenFile
1196 * Implementation of OpenFile16() and OpenFile32().
1198 static HFILE FILE_DoOpenFile( LPCSTR name, OFSTRUCT *ofs, UINT mode,
1199 BOOL win32 )
1201 HFILE hFileRet;
1202 HANDLE handle;
1203 FILETIME filetime;
1204 WORD filedatetime[2];
1205 DOS_FULL_NAME full_name;
1206 DWORD access, sharing;
1207 WCHAR *p;
1208 WCHAR buffer[MAX_PATH];
1209 LPWSTR nameW;
1211 if (!ofs) return HFILE_ERROR;
1213 TRACE("%s %s %s %s%s%s%s%s%s%s%s%s\n",name,
1214 ((mode & 0x3 )==OF_READ)?"OF_READ":
1215 ((mode & 0x3 )==OF_WRITE)?"OF_WRITE":
1216 ((mode & 0x3 )==OF_READWRITE)?"OF_READWRITE":"unknown",
1217 ((mode & 0x70 )==OF_SHARE_COMPAT)?"OF_SHARE_COMPAT":
1218 ((mode & 0x70 )==OF_SHARE_DENY_NONE)?"OF_SHARE_DENY_NONE":
1219 ((mode & 0x70 )==OF_SHARE_DENY_READ)?"OF_SHARE_DENY_READ":
1220 ((mode & 0x70 )==OF_SHARE_DENY_WRITE)?"OF_SHARE_DENY_WRITE":
1221 ((mode & 0x70 )==OF_SHARE_EXCLUSIVE)?"OF_SHARE_EXCLUSIVE":"unknown",
1222 ((mode & OF_PARSE )==OF_PARSE)?"OF_PARSE ":"",
1223 ((mode & OF_DELETE )==OF_DELETE)?"OF_DELETE ":"",
1224 ((mode & OF_VERIFY )==OF_VERIFY)?"OF_VERIFY ":"",
1225 ((mode & OF_SEARCH )==OF_SEARCH)?"OF_SEARCH ":"",
1226 ((mode & OF_CANCEL )==OF_CANCEL)?"OF_CANCEL ":"",
1227 ((mode & OF_CREATE )==OF_CREATE)?"OF_CREATE ":"",
1228 ((mode & OF_PROMPT )==OF_PROMPT)?"OF_PROMPT ":"",
1229 ((mode & OF_EXIST )==OF_EXIST)?"OF_EXIST ":"",
1230 ((mode & OF_REOPEN )==OF_REOPEN)?"OF_REOPEN ":""
1234 ofs->cBytes = sizeof(OFSTRUCT);
1235 ofs->nErrCode = 0;
1236 if (mode & OF_REOPEN) name = ofs->szPathName;
1238 if (!name) {
1239 ERR("called with `name' set to NULL ! Please debug.\n");
1240 return HFILE_ERROR;
1243 TRACE("%s %04x\n", name, mode );
1245 /* the watcom 10.6 IDE relies on a valid path returned in ofs->szPathName
1246 Are there any cases where getting the path here is wrong?
1247 Uwe Bonnes 1997 Apr 2 */
1248 if (!GetFullPathNameA( name, sizeof(ofs->szPathName),
1249 ofs->szPathName, NULL )) goto error;
1250 FILE_ConvertOFMode( mode, &access, &sharing );
1252 /* OF_PARSE simply fills the structure */
1254 if (mode & OF_PARSE)
1256 ofs->fFixedDisk = (GetDriveType16( ofs->szPathName[0]-'A' )
1257 != DRIVE_REMOVABLE);
1258 TRACE("(%s): OF_PARSE, res = '%s'\n",
1259 name, ofs->szPathName );
1260 return 0;
1263 /* OF_CREATE is completely different from all other options, so
1264 handle it first */
1266 if (mode & OF_CREATE)
1268 if ((handle = CreateFileA( name, GENERIC_READ | GENERIC_WRITE,
1269 sharing, NULL, CREATE_ALWAYS,
1270 FILE_ATTRIBUTE_NORMAL, 0 ))== INVALID_HANDLE_VALUE)
1271 goto error;
1272 goto success;
1275 MultiByteToWideChar(CP_ACP, 0, name, -1, buffer, MAX_PATH);
1276 nameW = buffer;
1278 /* If OF_SEARCH is set, ignore the given path */
1280 if ((mode & OF_SEARCH) && !(mode & OF_REOPEN))
1282 /* First try the file name as is */
1283 if (DOSFS_GetFullName( nameW, TRUE, &full_name )) goto found;
1284 /* Now remove the path */
1285 if (nameW[0] && (nameW[1] == ':')) nameW += 2;
1286 if ((p = strrchrW( nameW, '\\' ))) nameW = p + 1;
1287 if ((p = strrchrW( nameW, '/' ))) nameW = p + 1;
1288 if (!nameW[0]) goto not_found;
1291 /* Now look for the file */
1293 if (!DIR_SearchPath( NULL, nameW, NULL, &full_name, win32 )) goto not_found;
1295 found:
1296 TRACE("found %s = %s\n",
1297 full_name.long_name, debugstr_w(full_name.short_name) );
1298 WideCharToMultiByte(CP_ACP, 0, full_name.short_name, -1,
1299 ofs->szPathName, sizeof(ofs->szPathName), NULL, NULL);
1301 if (mode & OF_SHARE_EXCLUSIVE)
1302 /* Some InstallShield version uses OF_SHARE_EXCLUSIVE
1303 on the file <tempdir>/_ins0432._mp to determine how
1304 far installation has proceeded.
1305 _ins0432._mp is an executable and while running the
1306 application expects the open with OF_SHARE_ to fail*/
1307 /* Probable FIXME:
1308 As our loader closes the files after loading the executable,
1309 we can't find the running executable with FILE_InUse.
1310 The loader should keep the file open, as Windows does that, too.
1313 char *last = strrchr(full_name.long_name,'/');
1314 if (!last)
1315 last = full_name.long_name - 1;
1316 if (GetModuleHandle16(last+1))
1318 TRACE("Denying shared open for %s\n",full_name.long_name);
1319 return HFILE_ERROR;
1323 if (mode & OF_DELETE)
1325 if (unlink( full_name.long_name ) == -1) goto not_found;
1326 TRACE("(%s): OF_DELETE return = OK\n", name);
1327 return 1;
1330 handle = FILE_CreateFile( full_name.long_name, access, sharing,
1331 NULL, OPEN_EXISTING, 0, 0,
1332 DRIVE_GetFlags(full_name.drive) & DRIVE_FAIL_READ_ONLY,
1333 GetDriveTypeW( full_name.short_name ) );
1334 if (!handle) goto not_found;
1336 GetFileTime( handle, NULL, NULL, &filetime );
1337 FileTimeToDosDateTime( &filetime, &filedatetime[0], &filedatetime[1] );
1338 if ((mode & OF_VERIFY) && (mode & OF_REOPEN))
1340 if (ofs->Reserved1 != filedatetime[0] || ofs->Reserved2 != filedatetime[1] )
1342 CloseHandle( handle );
1343 WARN("(%s): OF_VERIFY failed\n", name );
1344 /* FIXME: what error here? */
1345 SetLastError( ERROR_FILE_NOT_FOUND );
1346 goto error;
1349 ofs->Reserved1 = filedatetime[0];
1350 ofs->Reserved2 = filedatetime[1];
1352 success: /* We get here if the open was successful */
1353 TRACE("(%s): OK, return = %p\n", name, handle );
1354 if (win32)
1356 hFileRet = (HFILE)handle;
1357 if (mode & OF_EXIST) /* Return the handle, but close it first */
1358 CloseHandle( handle );
1360 else
1362 hFileRet = Win32HandleToDosFileHandle( handle );
1363 if (hFileRet == HFILE_ERROR16) goto error;
1364 if (mode & OF_EXIST) /* Return the handle, but close it first */
1365 _lclose16( hFileRet );
1367 return hFileRet;
1369 not_found: /* We get here if the file does not exist */
1370 WARN("'%s' not found or sharing violation\n", name );
1371 SetLastError( ERROR_FILE_NOT_FOUND );
1372 /* fall through */
1374 error: /* We get here if there was an error opening the file */
1375 ofs->nErrCode = GetLastError();
1376 WARN("(%s): return = HFILE_ERROR error= %d\n",
1377 name,ofs->nErrCode );
1378 return HFILE_ERROR;
1382 /***********************************************************************
1383 * OpenFile (KERNEL.74)
1384 * OpenFileEx (KERNEL.360)
1386 HFILE16 WINAPI OpenFile16( LPCSTR name, OFSTRUCT *ofs, UINT16 mode )
1388 return FILE_DoOpenFile( name, ofs, mode, FALSE );
1392 /***********************************************************************
1393 * OpenFile (KERNEL32.@)
1395 HFILE WINAPI OpenFile( LPCSTR name, OFSTRUCT *ofs, UINT mode )
1397 return FILE_DoOpenFile( name, ofs, mode, TRUE );
1401 /***********************************************************************
1402 * FILE_InitProcessDosHandles
1404 * Allocates the default DOS handles for a process. Called either by
1405 * Win32HandleToDosFileHandle below or by the DOSVM stuff.
1407 static void FILE_InitProcessDosHandles( void )
1409 HANDLE cp = GetCurrentProcess();
1410 DuplicateHandle(cp, GetStdHandle(STD_INPUT_HANDLE), cp, &dos_handles[0],
1411 0, TRUE, DUPLICATE_SAME_ACCESS);
1412 DuplicateHandle(cp, GetStdHandle(STD_OUTPUT_HANDLE), cp, &dos_handles[1],
1413 0, TRUE, DUPLICATE_SAME_ACCESS);
1414 DuplicateHandle(cp, GetStdHandle(STD_ERROR_HANDLE), cp, &dos_handles[2],
1415 0, TRUE, DUPLICATE_SAME_ACCESS);
1416 DuplicateHandle(cp, GetStdHandle(STD_ERROR_HANDLE), cp, &dos_handles[3],
1417 0, TRUE, DUPLICATE_SAME_ACCESS);
1418 DuplicateHandle(cp, GetStdHandle(STD_ERROR_HANDLE), cp, &dos_handles[4],
1419 0, TRUE, DUPLICATE_SAME_ACCESS);
1422 /***********************************************************************
1423 * Win32HandleToDosFileHandle (KERNEL32.21)
1425 * Allocate a DOS handle for a Win32 handle. The Win32 handle is no
1426 * longer valid after this function (even on failure).
1428 * Note: this is not exactly right, since on Win95 the Win32 handles
1429 * are on top of DOS handles and we do it the other way
1430 * around. Should be good enough though.
1432 HFILE WINAPI Win32HandleToDosFileHandle( HANDLE handle )
1434 int i;
1436 if (!handle || (handle == INVALID_HANDLE_VALUE))
1437 return HFILE_ERROR;
1439 for (i = 5; i < DOS_TABLE_SIZE; i++)
1440 if (!dos_handles[i])
1442 dos_handles[i] = handle;
1443 TRACE("Got %d for h32 %p\n", i, handle );
1444 return (HFILE)i;
1446 CloseHandle( handle );
1447 SetLastError( ERROR_TOO_MANY_OPEN_FILES );
1448 return HFILE_ERROR;
1452 /***********************************************************************
1453 * DosFileHandleToWin32Handle (KERNEL32.20)
1455 * Return the Win32 handle for a DOS handle.
1457 * Note: this is not exactly right, since on Win95 the Win32 handles
1458 * are on top of DOS handles and we do it the other way
1459 * around. Should be good enough though.
1461 HANDLE WINAPI DosFileHandleToWin32Handle( HFILE handle )
1463 HFILE16 hfile = (HFILE16)handle;
1464 if (hfile < 5 && !dos_handles[hfile]) FILE_InitProcessDosHandles();
1465 if ((hfile >= DOS_TABLE_SIZE) || !dos_handles[hfile])
1467 SetLastError( ERROR_INVALID_HANDLE );
1468 return INVALID_HANDLE_VALUE;
1470 return dos_handles[hfile];
1474 /***********************************************************************
1475 * DisposeLZ32Handle (KERNEL32.22)
1477 * Note: this is not entirely correct, we should only close the
1478 * 32-bit handle and not the 16-bit one, but we cannot do
1479 * this because of the way our DOS handles are implemented.
1480 * It shouldn't break anything though.
1482 void WINAPI DisposeLZ32Handle( HANDLE handle )
1484 int i;
1486 if (!handle || (handle == INVALID_HANDLE_VALUE)) return;
1488 for (i = 5; i < DOS_TABLE_SIZE; i++)
1489 if (dos_handles[i] == handle)
1491 dos_handles[i] = 0;
1492 CloseHandle( handle );
1493 break;
1498 /***********************************************************************
1499 * FILE_Dup2
1501 * dup2() function for DOS handles.
1503 HFILE16 FILE_Dup2( HFILE16 hFile1, HFILE16 hFile2 )
1505 HANDLE new_handle;
1507 if (hFile1 < 5 && !dos_handles[hFile1]) FILE_InitProcessDosHandles();
1509 if ((hFile1 >= DOS_TABLE_SIZE) || (hFile2 >= DOS_TABLE_SIZE) || !dos_handles[hFile1])
1511 SetLastError( ERROR_INVALID_HANDLE );
1512 return HFILE_ERROR16;
1514 if (!DuplicateHandle( GetCurrentProcess(), dos_handles[hFile1],
1515 GetCurrentProcess(), &new_handle,
1516 0, FALSE, DUPLICATE_SAME_ACCESS ))
1517 return HFILE_ERROR16;
1518 if (dos_handles[hFile2]) CloseHandle( dos_handles[hFile2] );
1519 dos_handles[hFile2] = new_handle;
1520 return hFile2;
1524 /***********************************************************************
1525 * _lclose (KERNEL.81)
1527 HFILE16 WINAPI _lclose16( HFILE16 hFile )
1529 if ((hFile >= DOS_TABLE_SIZE) || !dos_handles[hFile])
1531 SetLastError( ERROR_INVALID_HANDLE );
1532 return HFILE_ERROR16;
1534 TRACE("%d (handle32=%p)\n", hFile, dos_handles[hFile] );
1535 CloseHandle( dos_handles[hFile] );
1536 dos_handles[hFile] = 0;
1537 return 0;
1541 /***********************************************************************
1542 * _lclose (KERNEL32.@)
1544 HFILE WINAPI _lclose( HFILE hFile )
1546 TRACE("handle %d\n", hFile );
1547 return CloseHandle( (HANDLE)hFile ) ? 0 : HFILE_ERROR;
1550 /***********************************************************************
1551 * GetOverlappedResult (KERNEL32.@)
1553 * Check the result of an Asynchronous data transfer from a file.
1555 * RETURNS
1556 * TRUE on success
1557 * FALSE on failure
1559 * If successful (and relevant) lpTransferred will hold the number of
1560 * bytes transferred during the async operation.
1562 * BUGS
1564 * Currently only works for WaitCommEvent, ReadFile, WriteFile
1565 * with communications ports.
1568 BOOL WINAPI GetOverlappedResult(
1569 HANDLE hFile, /* [in] handle of file to check on */
1570 LPOVERLAPPED lpOverlapped, /* [in/out] pointer to overlapped */
1571 LPDWORD lpTransferred, /* [in/out] number of bytes transferred */
1572 BOOL bWait /* [in] wait for the transfer to complete ? */
1574 DWORD r;
1576 TRACE("(%p %p %p %x)\n", hFile, lpOverlapped, lpTransferred, bWait);
1578 if(lpOverlapped==NULL)
1580 ERR("lpOverlapped was null\n");
1581 return FALSE;
1583 if(!lpOverlapped->hEvent)
1585 ERR("lpOverlapped->hEvent was null\n");
1586 return FALSE;
1589 if ( bWait )
1591 do {
1592 TRACE("waiting on %p\n",lpOverlapped);
1593 r = WaitForSingleObjectEx(lpOverlapped->hEvent, INFINITE, TRUE);
1594 TRACE("wait on %p returned %ld\n",lpOverlapped,r);
1595 } while (r==STATUS_USER_APC);
1597 else if ( lpOverlapped->Internal == STATUS_PENDING )
1599 /* Wait in order to give APCs a chance to run. */
1600 /* This is cheating, so we must set the event again in case of success -
1601 it may be a non-manual reset event. */
1602 do {
1603 TRACE("waiting on %p\n",lpOverlapped);
1604 r = WaitForSingleObjectEx(lpOverlapped->hEvent, 0, TRUE);
1605 TRACE("wait on %p returned %ld\n",lpOverlapped,r);
1606 } while (r==STATUS_USER_APC);
1607 if ( r == WAIT_OBJECT_0 )
1608 NtSetEvent ( lpOverlapped->hEvent, NULL );
1611 if(lpTransferred)
1612 *lpTransferred = lpOverlapped->InternalHigh;
1614 switch ( lpOverlapped->Internal )
1616 case STATUS_SUCCESS:
1617 return TRUE;
1618 case STATUS_PENDING:
1619 SetLastError ( ERROR_IO_INCOMPLETE );
1620 if ( bWait ) ERR ("PENDING status after waiting!\n");
1621 return FALSE;
1622 default:
1623 SetLastError ( RtlNtStatusToDosError ( lpOverlapped->Internal ) );
1624 return FALSE;
1628 /***********************************************************************
1629 * CancelIo (KERNEL32.@)
1631 BOOL WINAPI CancelIo(HANDLE handle)
1633 async_private *ovp,*t;
1635 TRACE("handle = %p\n",handle);
1637 for (ovp = NtCurrentTeb()->pending_list; ovp; ovp = t)
1639 t = ovp->next;
1640 if ( ovp->handle == handle )
1641 cancel_async ( ovp );
1643 WaitForMultipleObjectsEx(0,NULL,FALSE,1,TRUE);
1644 return TRUE;
1647 /***********************************************************************
1648 * FILE_AsyncReadService (INTERNAL)
1650 * This function is called while the client is waiting on the
1651 * server, so we can't make any server calls here.
1653 static void FILE_AsyncReadService(async_private *ovp)
1655 async_fileio *fileio = (async_fileio*) ovp;
1656 LPOVERLAPPED lpOverlapped = fileio->lpOverlapped;
1657 int result, r;
1658 int already = lpOverlapped->InternalHigh;
1660 TRACE("%p %p\n", lpOverlapped, fileio->buffer );
1662 /* check to see if the data is ready (non-blocking) */
1664 if ( fileio->fd_type == FD_TYPE_SOCKET )
1665 result = read (ovp->fd, &fileio->buffer[already], fileio->count - already);
1666 else
1668 result = pread (ovp->fd, &fileio->buffer[already], fileio->count - already,
1669 OVERLAPPED_OFFSET (lpOverlapped) + already);
1670 if ((result < 0) && (errno == ESPIPE))
1671 result = read (ovp->fd, &fileio->buffer[already], fileio->count - already);
1674 if ( (result<0) && ((errno == EAGAIN) || (errno == EINTR)))
1676 TRACE("Deferred read %d\n",errno);
1677 r = STATUS_PENDING;
1678 goto async_end;
1681 /* check to see if the transfer is complete */
1682 if(result<0)
1684 r = FILE_GetNtStatus ();
1685 goto async_end;
1687 else if ( result == 0 )
1689 r = ( lpOverlapped->InternalHigh ? STATUS_SUCCESS : STATUS_END_OF_FILE );
1690 goto async_end;
1693 lpOverlapped->InternalHigh += result;
1694 TRACE("read %d more bytes %ld/%d so far\n",result,lpOverlapped->InternalHigh,fileio->count);
1696 if(lpOverlapped->InternalHigh >= fileio->count || fileio->fd_type == FD_TYPE_SOCKET )
1697 r = STATUS_SUCCESS;
1698 else
1699 r = STATUS_PENDING;
1701 async_end:
1702 lpOverlapped->Internal = r;
1705 /***********************************************************************
1706 * FILE_ReadFileEx (INTERNAL)
1708 static BOOL FILE_ReadFileEx(HANDLE hFile, LPVOID buffer, DWORD bytesToRead,
1709 LPOVERLAPPED overlapped,
1710 LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine,
1711 HANDLE hEvent)
1713 async_fileio *ovp;
1714 int fd;
1715 int flags;
1716 enum fd_type type;
1718 TRACE("file %p to buf %p num %ld %p func %p\n",
1719 hFile, buffer, bytesToRead, overlapped, lpCompletionRoutine);
1721 /* check that there is an overlapped struct */
1722 if (overlapped==NULL)
1724 SetLastError(ERROR_INVALID_PARAMETER);
1725 return FALSE;
1728 fd = FILE_GetUnixHandleType ( hFile, GENERIC_READ, &type, &flags);
1729 if ( fd < 0 )
1731 WARN ( "Couldn't get FD\n" );
1732 return FALSE;
1735 ovp = (async_fileio*) HeapAlloc(GetProcessHeap(), 0, sizeof (async_fileio));
1736 if(!ovp)
1738 TRACE("HeapAlloc Failed\n");
1739 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1740 goto error;
1743 ovp->async.ops = ( lpCompletionRoutine ? &fileio_async_ops : &fileio_nocomp_async_ops );
1744 ovp->async.handle = hFile;
1745 ovp->async.fd = fd;
1746 ovp->async.type = ASYNC_TYPE_READ;
1747 ovp->async.func = FILE_AsyncReadService;
1748 ovp->async.event = hEvent;
1749 ovp->lpOverlapped = overlapped;
1750 ovp->count = bytesToRead;
1751 ovp->completion_func = lpCompletionRoutine;
1752 ovp->buffer = buffer;
1753 ovp->fd_type = type;
1755 return !register_new_async (&ovp->async);
1757 error:
1758 close (fd);
1759 return FALSE;
1763 /***********************************************************************
1764 * ReadFileEx (KERNEL32.@)
1766 BOOL WINAPI ReadFileEx(HANDLE hFile, LPVOID buffer, DWORD bytesToRead,
1767 LPOVERLAPPED overlapped,
1768 LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine)
1770 overlapped->InternalHigh = 0;
1771 return FILE_ReadFileEx(hFile,buffer,bytesToRead,overlapped,lpCompletionRoutine, INVALID_HANDLE_VALUE);
1774 static BOOL FILE_TimeoutRead(HANDLE hFile, LPVOID buffer, DWORD bytesToRead, LPDWORD bytesRead)
1776 OVERLAPPED ov;
1777 BOOL r = FALSE;
1779 TRACE("%p %p %ld %p\n", hFile, buffer, bytesToRead, bytesRead );
1781 ZeroMemory(&ov, sizeof (OVERLAPPED));
1782 if(STATUS_SUCCESS==NtCreateEvent(&ov.hEvent, SYNCHRONIZE, NULL, 0, 0))
1784 if(FILE_ReadFileEx(hFile, buffer, bytesToRead, &ov, NULL, ov.hEvent))
1786 r = GetOverlappedResult(hFile, &ov, bytesRead, TRUE);
1789 CloseHandle(ov.hEvent);
1790 return r;
1793 /***********************************************************************
1794 * ReadFile (KERNEL32.@)
1796 BOOL WINAPI ReadFile( HANDLE hFile, LPVOID buffer, DWORD bytesToRead,
1797 LPDWORD bytesRead, LPOVERLAPPED overlapped )
1799 int unix_handle, result, flags;
1800 enum fd_type type;
1802 TRACE("%p %p %ld %p %p\n", hFile, buffer, bytesToRead,
1803 bytesRead, overlapped );
1805 if (bytesRead) *bytesRead = 0; /* Do this before anything else */
1806 if (!bytesToRead) return TRUE;
1808 unix_handle = FILE_GetUnixHandleType( hFile, GENERIC_READ, &type, &flags );
1810 if (flags & FD_FLAG_OVERLAPPED)
1812 if (unix_handle == -1) return FALSE;
1813 if ( (overlapped==NULL) || NtResetEvent( overlapped->hEvent, NULL ) )
1815 TRACE("Overlapped not specified or invalid event flag\n");
1816 close(unix_handle);
1817 SetLastError(ERROR_INVALID_PARAMETER);
1818 return FALSE;
1821 close(unix_handle);
1822 overlapped->InternalHigh = 0;
1824 if(!FILE_ReadFileEx(hFile, buffer, bytesToRead, overlapped, NULL, overlapped->hEvent))
1825 return FALSE;
1827 if ( !GetOverlappedResult (hFile, overlapped, bytesRead, FALSE) )
1829 if ( GetLastError() == ERROR_IO_INCOMPLETE )
1830 SetLastError ( ERROR_IO_PENDING );
1831 return FALSE;
1834 return TRUE;
1836 if (flags & FD_FLAG_TIMEOUT)
1838 close(unix_handle);
1839 return FILE_TimeoutRead(hFile, buffer, bytesToRead, bytesRead);
1841 switch(type)
1843 case FD_TYPE_SMB:
1844 return SMB_ReadFile(hFile, buffer, bytesToRead, bytesRead, NULL);
1846 case FD_TYPE_CONSOLE:
1847 return FILE_ReadConsole(hFile, buffer, bytesToRead, bytesRead, NULL);
1849 case FD_TYPE_DEFAULT:
1850 /* normal unix files */
1851 if (unix_handle == -1) return FALSE;
1852 if (overlapped)
1854 DWORD highOffset = overlapped->OffsetHigh;
1855 if ( (INVALID_SET_FILE_POINTER == SetFilePointer(hFile, overlapped->Offset,
1856 &highOffset, FILE_BEGIN)) &&
1857 (GetLastError() != NO_ERROR) )
1859 close(unix_handle);
1860 return FALSE;
1863 break;
1865 default:
1866 if (unix_handle == -1)
1867 return FALSE;
1870 if(overlapped)
1872 off_t offset = OVERLAPPED_OFFSET(overlapped);
1873 if(lseek(unix_handle, offset, SEEK_SET) == -1)
1875 close(unix_handle);
1876 SetLastError(ERROR_INVALID_PARAMETER);
1877 return FALSE;
1881 /* code for synchronous reads */
1882 while ((result = read( unix_handle, buffer, bytesToRead )) == -1)
1884 if ((errno == EAGAIN) || (errno == EINTR)) continue;
1885 if ((errno == EFAULT) && !IsBadWritePtr( buffer, bytesToRead )) continue;
1886 FILE_SetDosError();
1887 break;
1889 close( unix_handle );
1890 if (result == -1) return FALSE;
1891 if (bytesRead) *bytesRead = result;
1892 return TRUE;
1896 /***********************************************************************
1897 * FILE_AsyncWriteService (INTERNAL)
1899 * This function is called while the client is waiting on the
1900 * server, so we can't make any server calls here.
1902 static void FILE_AsyncWriteService(struct async_private *ovp)
1904 async_fileio *fileio = (async_fileio *) ovp;
1905 LPOVERLAPPED lpOverlapped = fileio->lpOverlapped;
1906 int result, r;
1907 int already = lpOverlapped->InternalHigh;
1909 TRACE("(%p %p)\n",lpOverlapped,fileio->buffer);
1911 /* write some data (non-blocking) */
1913 if ( fileio->fd_type == FD_TYPE_SOCKET )
1914 result = write(ovp->fd, &fileio->buffer[already], fileio->count - already);
1915 else
1917 result = pwrite(ovp->fd, &fileio->buffer[already], fileio->count - already,
1918 OVERLAPPED_OFFSET (lpOverlapped) + already);
1919 if ((result < 0) && (errno == ESPIPE))
1920 result = write(ovp->fd, &fileio->buffer[already], fileio->count - already);
1923 if ( (result<0) && ((errno == EAGAIN) || (errno == EINTR)))
1925 r = STATUS_PENDING;
1926 goto async_end;
1929 /* check to see if the transfer is complete */
1930 if(result<0)
1932 r = FILE_GetNtStatus ();
1933 goto async_end;
1936 lpOverlapped->InternalHigh += result;
1938 TRACE("wrote %d more bytes %ld/%d so far\n",result,lpOverlapped->InternalHigh,fileio->count);
1940 if(lpOverlapped->InternalHigh < fileio->count)
1941 r = STATUS_PENDING;
1942 else
1943 r = STATUS_SUCCESS;
1945 async_end:
1946 lpOverlapped->Internal = r;
1949 /***********************************************************************
1950 * FILE_WriteFileEx
1952 static BOOL FILE_WriteFileEx(HANDLE hFile, LPCVOID buffer, DWORD bytesToWrite,
1953 LPOVERLAPPED overlapped,
1954 LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine,
1955 HANDLE hEvent)
1957 async_fileio *ovp;
1958 int fd;
1959 int flags;
1960 enum fd_type type;
1962 TRACE("file %p to buf %p num %ld %p func %p handle %p\n",
1963 hFile, buffer, bytesToWrite, overlapped, lpCompletionRoutine, hEvent);
1965 if (overlapped == NULL)
1967 SetLastError(ERROR_INVALID_PARAMETER);
1968 return FALSE;
1971 fd = FILE_GetUnixHandleType ( hFile, GENERIC_WRITE, &type, &flags );
1972 if ( fd < 0 )
1974 TRACE( "Couldn't get FD\n" );
1975 return FALSE;
1978 ovp = (async_fileio*) HeapAlloc(GetProcessHeap(), 0, sizeof (async_fileio));
1979 if(!ovp)
1981 TRACE("HeapAlloc Failed\n");
1982 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1983 goto error;
1986 ovp->async.ops = ( lpCompletionRoutine ? &fileio_async_ops : &fileio_nocomp_async_ops );
1987 ovp->async.handle = hFile;
1988 ovp->async.fd = fd;
1989 ovp->async.type = ASYNC_TYPE_WRITE;
1990 ovp->async.func = FILE_AsyncWriteService;
1991 ovp->lpOverlapped = overlapped;
1992 ovp->async.event = hEvent;
1993 ovp->buffer = (LPVOID) buffer;
1994 ovp->count = bytesToWrite;
1995 ovp->completion_func = lpCompletionRoutine;
1996 ovp->fd_type = type;
1998 return !register_new_async (&ovp->async);
2000 error:
2001 close (fd);
2002 return FALSE;
2005 /***********************************************************************
2006 * WriteFileEx (KERNEL32.@)
2008 BOOL WINAPI WriteFileEx(HANDLE hFile, LPCVOID buffer, DWORD bytesToWrite,
2009 LPOVERLAPPED overlapped,
2010 LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine)
2012 overlapped->InternalHigh = 0;
2014 return FILE_WriteFileEx(hFile, buffer, bytesToWrite, overlapped, lpCompletionRoutine, INVALID_HANDLE_VALUE);
2017 /***********************************************************************
2018 * WriteFile (KERNEL32.@)
2020 BOOL WINAPI WriteFile( HANDLE hFile, LPCVOID buffer, DWORD bytesToWrite,
2021 LPDWORD bytesWritten, LPOVERLAPPED overlapped )
2023 int unix_handle, result, flags;
2024 enum fd_type type;
2026 TRACE("%p %p %ld %p %p\n", hFile, buffer, bytesToWrite,
2027 bytesWritten, overlapped );
2029 if (bytesWritten) *bytesWritten = 0; /* Do this before anything else */
2030 if (!bytesToWrite) return TRUE;
2032 unix_handle = FILE_GetUnixHandleType( hFile, GENERIC_WRITE, &type, &flags );
2034 if (flags & FD_FLAG_OVERLAPPED)
2036 if (unix_handle == -1) return FALSE;
2037 if ( (overlapped==NULL) || NtResetEvent( overlapped->hEvent, NULL ) )
2039 TRACE("Overlapped not specified or invalid event flag\n");
2040 close(unix_handle);
2041 SetLastError(ERROR_INVALID_PARAMETER);
2042 return FALSE;
2045 close(unix_handle);
2046 overlapped->InternalHigh = 0;
2048 if(!FILE_WriteFileEx(hFile, buffer, bytesToWrite, overlapped, NULL, overlapped->hEvent))
2049 return FALSE;
2051 if ( !GetOverlappedResult (hFile, overlapped, bytesWritten, FALSE) )
2053 if ( GetLastError() == ERROR_IO_INCOMPLETE )
2054 SetLastError ( ERROR_IO_PENDING );
2055 return FALSE;
2058 return TRUE;
2061 switch(type)
2063 case FD_TYPE_CONSOLE:
2064 TRACE("%p %s %ld %p %p\n", hFile, debugstr_an(buffer, bytesToWrite), bytesToWrite,
2065 bytesWritten, overlapped );
2066 return FILE_WriteConsole(hFile, buffer, bytesToWrite, bytesWritten, NULL);
2068 case FD_TYPE_DEFAULT:
2069 if (unix_handle == -1) return FALSE;
2071 if(overlapped)
2073 DWORD highOffset = overlapped->OffsetHigh;
2074 if ( (INVALID_SET_FILE_POINTER == SetFilePointer(hFile, overlapped->Offset,
2075 &highOffset, FILE_BEGIN)) &&
2076 (GetLastError() != NO_ERROR) )
2078 close(unix_handle);
2079 return FALSE;
2082 break;
2084 default:
2085 if (unix_handle == -1)
2086 return FALSE;
2087 if (overlapped)
2089 close(unix_handle);
2090 SetLastError(ERROR_INVALID_PARAMETER);
2091 return FALSE;
2093 break;
2096 if(overlapped)
2098 off_t offset = OVERLAPPED_OFFSET(overlapped);
2099 if(lseek(unix_handle, offset, SEEK_SET) == -1)
2101 close(unix_handle);
2102 SetLastError(ERROR_INVALID_PARAMETER);
2103 return FALSE;
2107 /* synchronous file write */
2108 while ((result = write( unix_handle, buffer, bytesToWrite )) == -1)
2110 if ((errno == EAGAIN) || (errno == EINTR)) continue;
2111 if ((errno == EFAULT) && !IsBadReadPtr( buffer, bytesToWrite )) continue;
2112 if (errno == ENOSPC)
2113 SetLastError( ERROR_DISK_FULL );
2114 else
2115 FILE_SetDosError();
2116 break;
2118 close( unix_handle );
2119 if (result == -1) return FALSE;
2120 if (bytesWritten) *bytesWritten = result;
2121 return TRUE;
2125 /***********************************************************************
2126 * _hread (KERNEL.349)
2128 LONG WINAPI WIN16_hread( HFILE16 hFile, SEGPTR buffer, LONG count )
2130 LONG maxlen;
2132 TRACE("%d %08lx %ld\n",
2133 hFile, (DWORD)buffer, count );
2135 /* Some programs pass a count larger than the allocated buffer */
2136 maxlen = GetSelectorLimit16( SELECTOROF(buffer) ) - OFFSETOF(buffer) + 1;
2137 if (count > maxlen) count = maxlen;
2138 return _lread((HFILE)DosFileHandleToWin32Handle(hFile), MapSL(buffer), count );
2142 /***********************************************************************
2143 * _lread (KERNEL.82)
2145 UINT16 WINAPI WIN16_lread( HFILE16 hFile, SEGPTR buffer, UINT16 count )
2147 return (UINT16)WIN16_hread( hFile, buffer, (LONG)count );
2151 /***********************************************************************
2152 * _lread (KERNEL32.@)
2154 UINT WINAPI _lread( HFILE handle, LPVOID buffer, UINT count )
2156 DWORD result;
2157 if (!ReadFile( (HANDLE)handle, buffer, count, &result, NULL )) return -1;
2158 return result;
2162 /***********************************************************************
2163 * _lread16 (KERNEL.82)
2165 UINT16 WINAPI _lread16( HFILE16 hFile, LPVOID buffer, UINT16 count )
2167 return (UINT16)_lread((HFILE)DosFileHandleToWin32Handle(hFile), buffer, (LONG)count );
2171 /***********************************************************************
2172 * _lcreat (KERNEL.83)
2174 HFILE16 WINAPI _lcreat16( LPCSTR path, INT16 attr )
2176 return Win32HandleToDosFileHandle( (HANDLE)_lcreat( path, attr ) );
2180 /***********************************************************************
2181 * _lcreat (KERNEL32.@)
2183 HFILE WINAPI _lcreat( LPCSTR path, INT attr )
2185 /* Mask off all flags not explicitly allowed by the doc */
2186 attr &= FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM;
2187 TRACE("%s %02x\n", path, attr );
2188 return (HFILE)CreateFileA( path, GENERIC_READ | GENERIC_WRITE,
2189 FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
2190 CREATE_ALWAYS, attr, 0 );
2194 /***********************************************************************
2195 * SetFilePointer (KERNEL32.@)
2197 DWORD WINAPI SetFilePointer( HANDLE hFile, LONG distance, LONG *highword,
2198 DWORD method )
2200 DWORD ret = INVALID_SET_FILE_POINTER;
2202 TRACE("handle %p offset %ld high %ld origin %ld\n",
2203 hFile, distance, highword?*highword:0, method );
2205 SERVER_START_REQ( set_file_pointer )
2207 req->handle = hFile;
2208 req->low = distance;
2209 req->high = highword ? *highword : (distance >= 0) ? 0 : -1;
2210 /* FIXME: assumes 1:1 mapping between Windows and Unix seek constants */
2211 req->whence = method;
2212 SetLastError( 0 );
2213 if (!wine_server_call_err( req ))
2215 ret = reply->new_low;
2216 if (highword) *highword = reply->new_high;
2219 SERVER_END_REQ;
2220 return ret;
2224 /***********************************************************************
2225 * _llseek (KERNEL.84)
2227 * FIXME:
2228 * Seeking before the start of the file should be allowed for _llseek16,
2229 * but cause subsequent I/O operations to fail (cf. interrupt list)
2232 LONG WINAPI _llseek16( HFILE16 hFile, LONG lOffset, INT16 nOrigin )
2234 return SetFilePointer( DosFileHandleToWin32Handle(hFile), lOffset, NULL, nOrigin );
2238 /***********************************************************************
2239 * _llseek (KERNEL32.@)
2241 LONG WINAPI _llseek( HFILE hFile, LONG lOffset, INT nOrigin )
2243 return SetFilePointer( (HANDLE)hFile, lOffset, NULL, nOrigin );
2247 /***********************************************************************
2248 * _lopen (KERNEL.85)
2250 HFILE16 WINAPI _lopen16( LPCSTR path, INT16 mode )
2252 return Win32HandleToDosFileHandle( (HANDLE)_lopen( path, mode ) );
2256 /***********************************************************************
2257 * _lopen (KERNEL32.@)
2259 HFILE WINAPI _lopen( LPCSTR path, INT mode )
2261 DWORD access, sharing;
2263 TRACE("('%s',%04x)\n", path, mode );
2264 FILE_ConvertOFMode( mode, &access, &sharing );
2265 return (HFILE)CreateFileA( path, access, sharing, NULL, OPEN_EXISTING, 0, 0 );
2269 /***********************************************************************
2270 * _lwrite (KERNEL.86)
2272 UINT16 WINAPI _lwrite16( HFILE16 hFile, LPCSTR buffer, UINT16 count )
2274 return (UINT16)_hwrite( (HFILE)DosFileHandleToWin32Handle(hFile), buffer, (LONG)count );
2277 /***********************************************************************
2278 * _lwrite (KERNEL32.@)
2280 UINT WINAPI _lwrite( HFILE hFile, LPCSTR buffer, UINT count )
2282 return (UINT)_hwrite( hFile, buffer, (LONG)count );
2286 /***********************************************************************
2287 * _hread16 (KERNEL.349)
2289 LONG WINAPI _hread16( HFILE16 hFile, LPVOID buffer, LONG count)
2291 return _lread( (HFILE)DosFileHandleToWin32Handle(hFile), buffer, count );
2295 /***********************************************************************
2296 * _hread (KERNEL32.@)
2298 LONG WINAPI _hread( HFILE hFile, LPVOID buffer, LONG count)
2300 return _lread( hFile, buffer, count );
2304 /***********************************************************************
2305 * _hwrite (KERNEL.350)
2307 LONG WINAPI _hwrite16( HFILE16 hFile, LPCSTR buffer, LONG count )
2309 return _hwrite( (HFILE)DosFileHandleToWin32Handle(hFile), buffer, count );
2313 /***********************************************************************
2314 * _hwrite (KERNEL32.@)
2316 * experimentation yields that _lwrite:
2317 * o truncates the file at the current position with
2318 * a 0 len write
2319 * o returns 0 on a 0 length write
2320 * o works with console handles
2323 LONG WINAPI _hwrite( HFILE handle, LPCSTR buffer, LONG count )
2325 DWORD result;
2327 TRACE("%d %p %ld\n", handle, buffer, count );
2329 if (!count)
2331 /* Expand or truncate at current position */
2332 if (!SetEndOfFile( (HANDLE)handle )) return HFILE_ERROR;
2333 return 0;
2335 if (!WriteFile( (HANDLE)handle, buffer, count, &result, NULL ))
2336 return HFILE_ERROR;
2337 return result;
2341 /***********************************************************************
2342 * SetHandleCount (KERNEL.199)
2344 UINT16 WINAPI SetHandleCount16( UINT16 count )
2346 return SetHandleCount( count );
2350 /*************************************************************************
2351 * SetHandleCount (KERNEL32.@)
2353 UINT WINAPI SetHandleCount( UINT count )
2355 return min( 256, count );
2359 /***********************************************************************
2360 * FlushFileBuffers (KERNEL32.@)
2362 BOOL WINAPI FlushFileBuffers( HANDLE hFile )
2364 BOOL ret;
2365 SERVER_START_REQ( flush_file )
2367 req->handle = hFile;
2368 ret = !wine_server_call_err( req );
2370 SERVER_END_REQ;
2371 return ret;
2375 /**************************************************************************
2376 * SetEndOfFile (KERNEL32.@)
2378 BOOL WINAPI SetEndOfFile( HANDLE hFile )
2380 BOOL ret;
2381 SERVER_START_REQ( truncate_file )
2383 req->handle = hFile;
2384 ret = !wine_server_call_err( req );
2386 SERVER_END_REQ;
2387 return ret;
2391 /***********************************************************************
2392 * DeleteFile (KERNEL.146)
2394 BOOL16 WINAPI DeleteFile16( LPCSTR path )
2396 return DeleteFileA( path );
2400 /***********************************************************************
2401 * DeleteFileW (KERNEL32.@)
2403 BOOL WINAPI DeleteFileW( LPCWSTR path )
2405 DOS_FULL_NAME full_name;
2406 HANDLE hFile;
2408 TRACE("%s\n", debugstr_w(path) );
2409 if (!path || !*path)
2411 SetLastError(ERROR_PATH_NOT_FOUND);
2412 return FALSE;
2414 if (DOSFS_GetDevice( path ))
2416 WARN("cannot remove DOS device %s!\n", debugstr_w(path));
2417 SetLastError( ERROR_FILE_NOT_FOUND );
2418 return FALSE;
2421 if (!DOSFS_GetFullName( path, TRUE, &full_name )) return FALSE;
2423 /* check if we are allowed to delete the source */
2424 hFile = FILE_CreateFile( full_name.long_name, GENERIC_READ|GENERIC_WRITE, 0,
2425 NULL, OPEN_EXISTING, 0, 0, TRUE,
2426 GetDriveTypeW( full_name.short_name ) );
2427 if (!hFile) return FALSE;
2429 if (unlink( full_name.long_name ) == -1)
2431 FILE_SetDosError();
2432 CloseHandle(hFile);
2433 return FALSE;
2435 CloseHandle(hFile);
2436 return TRUE;
2440 /***********************************************************************
2441 * DeleteFileA (KERNEL32.@)
2443 BOOL WINAPI DeleteFileA( LPCSTR path )
2445 UNICODE_STRING pathW;
2446 BOOL ret = FALSE;
2448 if (!path)
2450 SetLastError(ERROR_INVALID_PARAMETER);
2451 return FALSE;
2454 if (RtlCreateUnicodeStringFromAsciiz(&pathW, path))
2456 ret = DeleteFileW(pathW.Buffer);
2457 RtlFreeUnicodeString(&pathW);
2459 else
2460 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
2461 return ret;
2465 /***********************************************************************
2466 * GetFileType (KERNEL32.@)
2468 DWORD WINAPI GetFileType( HANDLE hFile )
2470 DWORD ret = FILE_TYPE_UNKNOWN;
2471 SERVER_START_REQ( get_file_info )
2473 req->handle = hFile;
2474 if (!wine_server_call_err( req )) ret = reply->type;
2476 SERVER_END_REQ;
2477 return ret;
2481 /* check if a file name is for an executable file (.exe or .com) */
2482 inline static BOOL is_executable( const char *name )
2484 int len = strlen(name);
2486 if (len < 4) return FALSE;
2487 return (!strcasecmp( name + len - 4, ".exe" ) ||
2488 !strcasecmp( name + len - 4, ".com" ));
2492 /***********************************************************************
2493 * FILE_AddBootRenameEntry
2495 * Adds an entry to the registry that is loaded when windows boots and
2496 * checks if there are some files to be removed or renamed/moved.
2497 * <fn1> has to be valid and <fn2> may be NULL. If both pointers are
2498 * non-NULL then the file is moved, otherwise it is deleted. The
2499 * entry of the registrykey is always appended with two zero
2500 * terminated strings. If <fn2> is NULL then the second entry is
2501 * simply a single 0-byte. Otherwise the second filename goes
2502 * there. The entries are prepended with \??\ before the path and the
2503 * second filename gets also a '!' as the first character if
2504 * MOVEFILE_REPLACE_EXISTING is set. After the final string another
2505 * 0-byte follows to indicate the end of the strings.
2506 * i.e.:
2507 * \??\D:\test\file1[0]
2508 * !\??\D:\test\file1_renamed[0]
2509 * \??\D:\Test|delete[0]
2510 * [0] <- file is to be deleted, second string empty
2511 * \??\D:\test\file2[0]
2512 * !\??\D:\test\file2_renamed[0]
2513 * [0] <- indicates end of strings
2515 * or:
2516 * \??\D:\test\file1[0]
2517 * !\??\D:\test\file1_renamed[0]
2518 * \??\D:\Test|delete[0]
2519 * [0] <- file is to be deleted, second string empty
2520 * [0] <- indicates end of strings
2523 static BOOL FILE_AddBootRenameEntry( LPCWSTR fn1, LPCWSTR fn2, DWORD flags )
2525 static const WCHAR PreString[] = {'\\','?','?','\\',0};
2526 static const WCHAR ValueName[] = {'P','e','n','d','i','n','g',
2527 'F','i','l','e','R','e','n','a','m','e',
2528 'O','p','e','r','a','t','i','o','n','s',0};
2529 static const WCHAR SessionW[] = {'M','a','c','h','i','n','e','\\',
2530 'S','y','s','t','e','m','\\',
2531 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
2532 'C','o','n','t','r','o','l','\\',
2533 'S','e','s','s','i','o','n',' ','M','a','n','a','g','e','r',0};
2534 static const int info_size = FIELD_OFFSET( KEY_VALUE_PARTIAL_INFORMATION, Data );
2536 OBJECT_ATTRIBUTES attr;
2537 UNICODE_STRING nameW;
2538 KEY_VALUE_PARTIAL_INFORMATION *info;
2539 BOOL rc = FALSE;
2540 HKEY Reboot = 0;
2541 DWORD len0, len1, len2;
2542 DWORD DataSize = 0;
2543 BYTE *Buffer = NULL;
2544 WCHAR *p;
2546 attr.Length = sizeof(attr);
2547 attr.RootDirectory = 0;
2548 attr.ObjectName = &nameW;
2549 attr.Attributes = 0;
2550 attr.SecurityDescriptor = NULL;
2551 attr.SecurityQualityOfService = NULL;
2552 RtlInitUnicodeString( &nameW, SessionW );
2554 if (NtCreateKey( &Reboot, KEY_ALL_ACCESS, &attr, 0, NULL, 0, NULL ) != STATUS_SUCCESS)
2556 WARN("Error creating key for reboot managment [%s]\n",
2557 "SYSTEM\\CurrentControlSet\\Control\\Session Manager");
2558 return FALSE;
2561 len0 = strlenW(PreString);
2562 len1 = strlenW(fn1) + len0 + 1;
2563 if (fn2)
2565 len2 = strlenW(fn2) + len0 + 1;
2566 if (flags & MOVEFILE_REPLACE_EXISTING) len2++; /* Plus 1 because of the leading '!' */
2568 else len2 = 1; /* minimum is the 0 characters for the empty second string */
2570 /* convert characters to bytes */
2571 len0 *= sizeof(WCHAR);
2572 len1 *= sizeof(WCHAR);
2573 len2 *= sizeof(WCHAR);
2575 RtlInitUnicodeString( &nameW, ValueName );
2577 /* First we check if the key exists and if so how many bytes it already contains. */
2578 if (NtQueryValueKey( Reboot, &nameW, KeyValuePartialInformation,
2579 NULL, 0, &DataSize ) == STATUS_BUFFER_OVERFLOW)
2581 if (!(Buffer = HeapAlloc( GetProcessHeap(), 0, DataSize + len1 + len2 + sizeof(WCHAR) )))
2582 goto Quit;
2583 if (NtQueryValueKey( Reboot, &nameW, KeyValuePartialInformation,
2584 Buffer, DataSize, &DataSize )) goto Quit;
2585 info = (KEY_VALUE_PARTIAL_INFORMATION *)Buffer;
2586 if (info->Type != REG_MULTI_SZ) goto Quit;
2587 if (DataSize > sizeof(info)) DataSize -= sizeof(WCHAR); /* remove terminating null (will be added back later) */
2589 else
2591 DataSize = info_size;
2592 if (!(Buffer = HeapAlloc( GetProcessHeap(), 0, DataSize + len1 + len2 + sizeof(WCHAR) )))
2593 goto Quit;
2596 p = (WCHAR *)(Buffer + DataSize);
2597 strcpyW( p, PreString );
2598 strcatW( p, fn1 );
2599 DataSize += len1;
2600 if (fn2)
2602 p = (WCHAR *)(Buffer + DataSize);
2603 if (flags & MOVEFILE_REPLACE_EXISTING)
2604 *p++ = '!';
2605 strcpyW( p, PreString );
2606 strcatW( p, fn2 );
2607 DataSize += len2;
2609 else
2611 p = (WCHAR *)(Buffer + DataSize);
2612 *p = 0;
2613 DataSize += sizeof(WCHAR);
2616 /* add final null */
2617 p = (WCHAR *)(Buffer + DataSize);
2618 *p = 0;
2619 DataSize += sizeof(WCHAR);
2621 rc = !NtSetValueKey(Reboot, &nameW, 0, REG_MULTI_SZ, Buffer + info_size, DataSize - info_size);
2623 Quit:
2624 if (Reboot) NtClose(Reboot);
2625 if (Buffer) HeapFree( GetProcessHeap(), 0, Buffer );
2626 return(rc);
2630 /**************************************************************************
2631 * MoveFileExW (KERNEL32.@)
2633 BOOL WINAPI MoveFileExW( LPCWSTR fn1, LPCWSTR fn2, DWORD flag )
2635 DOS_FULL_NAME full_name1, full_name2;
2636 HANDLE hFile;
2637 DWORD attr = INVALID_FILE_ATTRIBUTES;
2639 TRACE("(%s,%s,%04lx)\n", debugstr_w(fn1), debugstr_w(fn2), flag);
2641 /* FIXME: <Gerhard W. Gruber>sparhawk@gmx.at
2642 In case of W9x and lesser this function should return 120 (ERROR_CALL_NOT_IMPLEMENTED)
2643 to be really compatible. Most programs wont have any problems though. In case
2644 you encounter one, this is what you should return here. I don't know what's up
2645 with NT 3.5. Is this function available there or not?
2646 Does anybody really care about 3.5? :)
2649 /* Filename1 has to be always set to a valid path. Filename2 may be NULL
2650 if the source file has to be deleted.
2652 if (!fn1) {
2653 SetLastError(ERROR_INVALID_PARAMETER);
2654 return FALSE;
2657 /* This function has to be run through in order to process the name properly.
2658 If the BOOTDELAY flag is set, the file doesn't need to exist though. At least
2659 that is the behaviour on NT 4.0. The operation accepts the filenames as
2660 they are given but it can't reply with a reasonable returncode. Success
2661 means in that case success for entering the values into the registry.
2663 if(!DOSFS_GetFullName( fn1, TRUE, &full_name1 ))
2665 if(!(flag & MOVEFILE_DELAY_UNTIL_REBOOT))
2666 return FALSE;
2669 if (fn2) /* !fn2 means delete fn1 */
2671 if (DOSFS_GetFullName( fn2, TRUE, &full_name2 ))
2673 if(!(flag & MOVEFILE_DELAY_UNTIL_REBOOT))
2675 /* target exists, check if we may overwrite */
2676 if (!(flag & MOVEFILE_REPLACE_EXISTING))
2678 SetLastError( ERROR_FILE_EXISTS );
2679 return FALSE;
2683 else
2685 if (!DOSFS_GetFullName( fn2, FALSE, &full_name2 ))
2687 if(!(flag & MOVEFILE_DELAY_UNTIL_REBOOT))
2688 return FALSE;
2692 /* Source name and target path are valid */
2694 if (flag & MOVEFILE_DELAY_UNTIL_REBOOT)
2696 return FILE_AddBootRenameEntry( fn1, fn2, flag );
2699 attr = GetFileAttributesW( fn1 );
2700 if ( attr == INVALID_FILE_ATTRIBUTES ) return FALSE;
2702 /* check if we are allowed to rename the source */
2703 hFile = FILE_CreateFile( full_name1.long_name, 0, 0,
2704 NULL, OPEN_EXISTING, 0, 0, TRUE,
2705 GetDriveTypeW( full_name1.short_name ) );
2706 if (!hFile)
2708 if (GetLastError() != ERROR_ACCESS_DENIED) return FALSE;
2709 if ( !(attr & FILE_ATTRIBUTE_DIRECTORY) ) return FALSE;
2710 /* if it's a directory we can continue */
2712 else CloseHandle(hFile);
2714 /* check, if we are allowed to delete the destination,
2715 ** (but the file not being there is fine) */
2716 hFile = FILE_CreateFile( full_name2.long_name, GENERIC_READ|GENERIC_WRITE, 0,
2717 NULL, OPEN_EXISTING, 0, 0, TRUE,
2718 GetDriveTypeW( full_name2.short_name ) );
2719 if(!hFile && GetLastError() != ERROR_FILE_NOT_FOUND) return FALSE;
2720 CloseHandle(hFile);
2722 if (full_name1.drive != full_name2.drive)
2724 if (!(flag & MOVEFILE_COPY_ALLOWED))
2726 SetLastError( ERROR_NOT_SAME_DEVICE );
2727 return FALSE;
2729 else if ( attr & FILE_ATTRIBUTE_DIRECTORY )
2731 /* Strange, but that's what Windows returns */
2732 SetLastError ( ERROR_ACCESS_DENIED );
2733 return FALSE;
2736 if (rename( full_name1.long_name, full_name2.long_name ) == -1)
2737 /* Try copy/delete unless it's a directory. */
2738 /* FIXME: This does not handle the (unlikely) case that the two locations
2739 are on the same Wine drive, but on different Unix file systems. */
2741 if ( attr & FILE_ATTRIBUTE_DIRECTORY )
2743 FILE_SetDosError();
2744 return FALSE;
2746 else
2748 if ( ! CopyFileW( fn1, fn2, !(flag & MOVEFILE_REPLACE_EXISTING) ))
2749 return FALSE;
2750 if ( ! DeleteFileW ( fn1 ) )
2751 return FALSE;
2754 if (is_executable( full_name1.long_name ) != is_executable( full_name2.long_name ))
2756 struct stat fstat;
2757 if (stat( full_name2.long_name, &fstat ) != -1)
2759 if (is_executable( full_name2.long_name ))
2760 /* set executable bit where read bit is set */
2761 fstat.st_mode |= (fstat.st_mode & 0444) >> 2;
2762 else
2763 fstat.st_mode &= ~0111;
2764 chmod( full_name2.long_name, fstat.st_mode );
2767 return TRUE;
2769 else /* fn2 == NULL means delete source */
2771 if (flag & MOVEFILE_DELAY_UNTIL_REBOOT)
2773 if (flag & MOVEFILE_COPY_ALLOWED) {
2774 WARN("Illegal flag\n");
2775 SetLastError( ERROR_GEN_FAILURE );
2776 return FALSE;
2779 return FILE_AddBootRenameEntry( fn1, NULL, flag );
2782 if (unlink( full_name1.long_name ) == -1)
2784 FILE_SetDosError();
2785 return FALSE;
2787 return TRUE; /* successfully deleted */
2791 /**************************************************************************
2792 * MoveFileExA (KERNEL32.@)
2794 BOOL WINAPI MoveFileExA( LPCSTR fn1, LPCSTR fn2, DWORD flag )
2796 UNICODE_STRING fn1W, fn2W;
2797 BOOL ret;
2799 if (!fn1)
2801 SetLastError(ERROR_INVALID_PARAMETER);
2802 return FALSE;
2805 RtlCreateUnicodeStringFromAsciiz(&fn1W, fn1);
2806 if (fn2) RtlCreateUnicodeStringFromAsciiz(&fn2W, fn2);
2807 else fn2W.Buffer = NULL;
2809 ret = MoveFileExW( fn1W.Buffer, fn2W.Buffer, flag );
2811 RtlFreeUnicodeString(&fn1W);
2812 RtlFreeUnicodeString(&fn2W);
2813 return ret;
2817 /**************************************************************************
2818 * MoveFileW (KERNEL32.@)
2820 * Move file or directory
2822 BOOL WINAPI MoveFileW( LPCWSTR fn1, LPCWSTR fn2 )
2824 DOS_FULL_NAME full_name1, full_name2;
2825 struct stat fstat;
2827 if (!fn1 || !fn2)
2829 SetLastError(ERROR_INVALID_PARAMETER);
2830 return FALSE;
2833 TRACE("(%s,%s)\n", debugstr_w(fn1), debugstr_w(fn2) );
2835 if (!DOSFS_GetFullName( fn1, TRUE, &full_name1 )) return FALSE;
2836 if (DOSFS_GetFullName( fn2, TRUE, &full_name2 )) {
2837 /* The new name must not already exist */
2838 SetLastError(ERROR_ALREADY_EXISTS);
2839 return FALSE;
2841 if (!DOSFS_GetFullName( fn2, FALSE, &full_name2 )) return FALSE;
2843 if (full_name1.drive == full_name2.drive) /* move */
2844 return MoveFileExW( fn1, fn2, MOVEFILE_COPY_ALLOWED );
2846 /* copy */
2847 if (stat( full_name1.long_name, &fstat ))
2849 WARN("Invalid source file %s\n",
2850 full_name1.long_name);
2851 FILE_SetDosError();
2852 return FALSE;
2854 if (S_ISDIR(fstat.st_mode)) {
2855 /* No Move for directories across file systems */
2856 /* FIXME: Use right error code */
2857 SetLastError( ERROR_GEN_FAILURE );
2858 return FALSE;
2860 return CopyFileW(fn1, fn2, TRUE); /*fail, if exist */
2864 /**************************************************************************
2865 * MoveFileA (KERNEL32.@)
2867 BOOL WINAPI MoveFileA( LPCSTR fn1, LPCSTR fn2 )
2869 UNICODE_STRING fn1W, fn2W;
2870 BOOL ret;
2872 if (!fn1 || !fn2)
2874 SetLastError(ERROR_INVALID_PARAMETER);
2875 return FALSE;
2878 RtlCreateUnicodeStringFromAsciiz(&fn1W, fn1);
2879 RtlCreateUnicodeStringFromAsciiz(&fn2W, fn2);
2881 ret = MoveFileW( fn1W.Buffer, fn2W.Buffer );
2883 RtlFreeUnicodeString(&fn1W);
2884 RtlFreeUnicodeString(&fn2W);
2885 return ret;
2889 /**************************************************************************
2890 * CopyFileW (KERNEL32.@)
2892 BOOL WINAPI CopyFileW( LPCWSTR source, LPCWSTR dest, BOOL fail_if_exists )
2894 HANDLE h1, h2;
2895 BY_HANDLE_FILE_INFORMATION info;
2896 DWORD count;
2897 BOOL ret = FALSE;
2898 char buffer[2048];
2900 if (!source || !dest)
2902 SetLastError(ERROR_INVALID_PARAMETER);
2903 return FALSE;
2906 TRACE("%s -> %s\n", debugstr_w(source), debugstr_w(dest));
2908 if ((h1 = CreateFileW(source, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE,
2909 NULL, OPEN_EXISTING, 0, 0)) == INVALID_HANDLE_VALUE)
2911 WARN("Unable to open source %s\n", debugstr_w(source));
2912 return FALSE;
2915 if (!GetFileInformationByHandle( h1, &info ))
2917 WARN("GetFileInformationByHandle returned error for %s\n", debugstr_w(source));
2918 CloseHandle( h1 );
2919 return FALSE;
2922 if ((h2 = CreateFileW( dest, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
2923 fail_if_exists ? CREATE_NEW : CREATE_ALWAYS,
2924 info.dwFileAttributes, h1 )) == INVALID_HANDLE_VALUE)
2926 WARN("Unable to open dest %s\n", debugstr_w(dest));
2927 CloseHandle( h1 );
2928 return FALSE;
2931 while (ReadFile( h1, buffer, sizeof(buffer), &count, NULL ) && count)
2933 char *p = buffer;
2934 while (count != 0)
2936 DWORD res;
2937 if (!WriteFile( h2, p, count, &res, NULL ) || !res) goto done;
2938 p += res;
2939 count -= res;
2942 ret = TRUE;
2943 done:
2944 CloseHandle( h1 );
2945 CloseHandle( h2 );
2946 return ret;
2950 /**************************************************************************
2951 * CopyFileA (KERNEL32.@)
2953 BOOL WINAPI CopyFileA( LPCSTR source, LPCSTR dest, BOOL fail_if_exists)
2955 UNICODE_STRING sourceW, destW;
2956 BOOL ret;
2958 if (!source || !dest)
2960 SetLastError(ERROR_INVALID_PARAMETER);
2961 return FALSE;
2964 RtlCreateUnicodeStringFromAsciiz(&sourceW, source);
2965 RtlCreateUnicodeStringFromAsciiz(&destW, dest);
2967 ret = CopyFileW(sourceW.Buffer, destW.Buffer, fail_if_exists);
2969 RtlFreeUnicodeString(&sourceW);
2970 RtlFreeUnicodeString(&destW);
2971 return ret;
2975 /**************************************************************************
2976 * CopyFileExW (KERNEL32.@)
2978 * This implementation ignores most of the extra parameters passed-in into
2979 * the "ex" version of the method and calls the CopyFile method.
2980 * It will have to be fixed eventually.
2982 BOOL WINAPI CopyFileExW(LPCWSTR sourceFilename, LPCWSTR destFilename,
2983 LPPROGRESS_ROUTINE progressRoutine, LPVOID appData,
2984 LPBOOL cancelFlagPointer, DWORD copyFlags)
2987 * Interpret the only flag that CopyFile can interpret.
2989 return CopyFileW(sourceFilename, destFilename, (copyFlags & COPY_FILE_FAIL_IF_EXISTS) != 0);
2992 /**************************************************************************
2993 * CopyFileExA (KERNEL32.@)
2995 BOOL WINAPI CopyFileExA(LPCSTR sourceFilename, LPCSTR destFilename,
2996 LPPROGRESS_ROUTINE progressRoutine, LPVOID appData,
2997 LPBOOL cancelFlagPointer, DWORD copyFlags)
2999 UNICODE_STRING sourceW, destW;
3000 BOOL ret;
3002 if (!sourceFilename || !destFilename)
3004 SetLastError(ERROR_INVALID_PARAMETER);
3005 return FALSE;
3008 RtlCreateUnicodeStringFromAsciiz(&sourceW, sourceFilename);
3009 RtlCreateUnicodeStringFromAsciiz(&destW, destFilename);
3011 ret = CopyFileExW(sourceW.Buffer, destW.Buffer, progressRoutine, appData,
3012 cancelFlagPointer, copyFlags);
3014 RtlFreeUnicodeString(&sourceW);
3015 RtlFreeUnicodeString(&destW);
3016 return ret;
3020 /***********************************************************************
3021 * SetFileTime (KERNEL32.@)
3023 BOOL WINAPI SetFileTime( HANDLE hFile,
3024 const FILETIME *lpCreationTime,
3025 const FILETIME *lpLastAccessTime,
3026 const FILETIME *lpLastWriteTime )
3028 BOOL ret;
3029 SERVER_START_REQ( set_file_time )
3031 req->handle = hFile;
3032 if (lpLastAccessTime)
3033 RtlTimeToSecondsSince1970( (PLARGE_INTEGER) lpLastAccessTime, (DWORD *)&req->access_time );
3034 else
3035 req->access_time = 0; /* FIXME */
3036 if (lpLastWriteTime)
3037 RtlTimeToSecondsSince1970( (PLARGE_INTEGER) lpLastWriteTime, (DWORD *)&req->write_time );
3038 else
3039 req->write_time = 0; /* FIXME */
3040 ret = !wine_server_call_err( req );
3042 SERVER_END_REQ;
3043 return ret;
3047 /**************************************************************************
3048 * LockFile (KERNEL32.@)
3050 BOOL WINAPI LockFile( HANDLE hFile, DWORD dwFileOffsetLow, DWORD dwFileOffsetHigh,
3051 DWORD nNumberOfBytesToLockLow, DWORD nNumberOfBytesToLockHigh )
3053 BOOL ret;
3055 FIXME("not implemented in server\n");
3057 SERVER_START_REQ( lock_file )
3059 req->handle = hFile;
3060 req->offset_low = dwFileOffsetLow;
3061 req->offset_high = dwFileOffsetHigh;
3062 req->count_low = nNumberOfBytesToLockLow;
3063 req->count_high = nNumberOfBytesToLockHigh;
3064 ret = !wine_server_call_err( req );
3066 SERVER_END_REQ;
3067 return ret;
3070 /**************************************************************************
3071 * LockFileEx [KERNEL32.@]
3073 * Locks a byte range within an open file for shared or exclusive access.
3075 * RETURNS
3076 * success: TRUE
3077 * failure: FALSE
3079 * NOTES
3080 * Per Microsoft docs, the third parameter (reserved) must be set to 0.
3082 BOOL WINAPI LockFileEx( HANDLE hFile, DWORD flags, DWORD reserved,
3083 DWORD nNumberOfBytesToLockLow, DWORD nNumberOfBytesToLockHigh,
3084 LPOVERLAPPED pOverlapped )
3086 FIXME("hFile=%p,flags=%ld,reserved=%ld,lowbytes=%ld,highbytes=%ld,overlapped=%p: stub.\n",
3087 hFile, flags, reserved, nNumberOfBytesToLockLow, nNumberOfBytesToLockHigh,
3088 pOverlapped);
3089 if (reserved == 0)
3090 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
3091 else
3093 ERR("reserved == %ld: Supposed to be 0??\n", reserved);
3094 SetLastError(ERROR_INVALID_PARAMETER);
3097 return FALSE;
3101 /**************************************************************************
3102 * UnlockFile (KERNEL32.@)
3104 BOOL WINAPI UnlockFile( HANDLE hFile, DWORD dwFileOffsetLow, DWORD dwFileOffsetHigh,
3105 DWORD nNumberOfBytesToUnlockLow, DWORD nNumberOfBytesToUnlockHigh )
3107 BOOL ret;
3109 FIXME("not implemented in server\n");
3111 SERVER_START_REQ( unlock_file )
3113 req->handle = hFile;
3114 req->offset_low = dwFileOffsetLow;
3115 req->offset_high = dwFileOffsetHigh;
3116 req->count_low = nNumberOfBytesToUnlockLow;
3117 req->count_high = nNumberOfBytesToUnlockHigh;
3118 ret = !wine_server_call_err( req );
3120 SERVER_END_REQ;
3121 return ret;
3125 /**************************************************************************
3126 * UnlockFileEx (KERNEL32.@)
3128 BOOL WINAPI UnlockFileEx(
3129 HANDLE hFile,
3130 DWORD dwReserved,
3131 DWORD nNumberOfBytesToUnlockLow,
3132 DWORD nNumberOfBytesToUnlockHigh,
3133 LPOVERLAPPED lpOverlapped
3136 FIXME("hFile=%p,reserved=%ld,lowbytes=%ld,highbytes=%ld,overlapped=%p: stub.\n",
3137 hFile, dwReserved, nNumberOfBytesToUnlockLow, nNumberOfBytesToUnlockHigh,
3138 lpOverlapped);
3139 if (dwReserved == 0)
3140 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
3141 else
3143 ERR("reserved == %ld: Supposed to be 0??\n", dwReserved);
3144 SetLastError(ERROR_INVALID_PARAMETER);
3147 return FALSE;
3151 #if 0
3153 struct DOS_FILE_LOCK {
3154 struct DOS_FILE_LOCK * next;
3155 DWORD base;
3156 DWORD len;
3157 DWORD processId;
3158 FILE_OBJECT * dos_file;
3159 /* char * unix_name;*/
3162 typedef struct DOS_FILE_LOCK DOS_FILE_LOCK;
3164 static DOS_FILE_LOCK *locks = NULL;
3165 static void DOS_RemoveFileLocks(FILE_OBJECT *file);
3168 /* Locks need to be mirrored because unix file locking is based
3169 * on the pid. Inside of wine there can be multiple WINE processes
3170 * that share the same unix pid.
3171 * Read's and writes should check these locks also - not sure
3172 * how critical that is at this point (FIXME).
3175 static BOOL DOS_AddLock(FILE_OBJECT *file, struct flock *f)
3177 DOS_FILE_LOCK *curr;
3178 DWORD processId;
3180 processId = GetCurrentProcessId();
3182 /* check if lock overlaps a current lock for the same file */
3183 #if 0
3184 for (curr = locks; curr; curr = curr->next) {
3185 if (strcmp(curr->unix_name, file->unix_name) == 0) {
3186 if ((f->l_start == curr->base) && (f->l_len == curr->len))
3187 return TRUE;/* region is identic */
3188 if ((f->l_start < (curr->base + curr->len)) &&
3189 ((f->l_start + f->l_len) > curr->base)) {
3190 /* region overlaps */
3191 return FALSE;
3195 #endif
3197 curr = HeapAlloc( GetProcessHeap(), 0, sizeof(DOS_FILE_LOCK) );
3198 curr->processId = GetCurrentProcessId();
3199 curr->base = f->l_start;
3200 curr->len = f->l_len;
3201 /* curr->unix_name = HEAP_strdupA( GetProcessHeap(), 0, file->unix_name);*/
3202 curr->next = locks;
3203 curr->dos_file = file;
3204 locks = curr;
3205 return TRUE;
3208 static void DOS_RemoveFileLocks(FILE_OBJECT *file)
3210 DWORD processId;
3211 DOS_FILE_LOCK **curr;
3212 DOS_FILE_LOCK *rem;
3214 processId = GetCurrentProcessId();
3215 curr = &locks;
3216 while (*curr) {
3217 if ((*curr)->dos_file == file) {
3218 rem = *curr;
3219 *curr = (*curr)->next;
3220 /* HeapFree( GetProcessHeap(), 0, rem->unix_name );*/
3221 HeapFree( GetProcessHeap(), 0, rem );
3223 else
3224 curr = &(*curr)->next;
3228 static BOOL DOS_RemoveLock(FILE_OBJECT *file, struct flock *f)
3230 DWORD processId;
3231 DOS_FILE_LOCK **curr;
3232 DOS_FILE_LOCK *rem;
3234 processId = GetCurrentProcessId();
3235 for (curr = &locks; *curr; curr = &(*curr)->next) {
3236 if ((*curr)->processId == processId &&
3237 (*curr)->dos_file == file &&
3238 (*curr)->base == f->l_start &&
3239 (*curr)->len == f->l_len) {
3240 /* this is the same lock */
3241 rem = *curr;
3242 *curr = (*curr)->next;
3243 /* HeapFree( GetProcessHeap(), 0, rem->unix_name );*/
3244 HeapFree( GetProcessHeap(), 0, rem );
3245 return TRUE;
3248 /* no matching lock found */
3249 return FALSE;
3253 /**************************************************************************
3254 * LockFile (KERNEL32.@)
3256 BOOL WINAPI LockFile(
3257 HANDLE hFile,DWORD dwFileOffsetLow,DWORD dwFileOffsetHigh,
3258 DWORD nNumberOfBytesToLockLow,DWORD nNumberOfBytesToLockHigh )
3260 struct flock f;
3261 FILE_OBJECT *file;
3263 TRACE("handle %d offsetlow=%ld offsethigh=%ld nbyteslow=%ld nbyteshigh=%ld\n",
3264 hFile, dwFileOffsetLow, dwFileOffsetHigh,
3265 nNumberOfBytesToLockLow, nNumberOfBytesToLockHigh);
3267 if (dwFileOffsetHigh || nNumberOfBytesToLockHigh) {
3268 FIXME("Unimplemented bytes > 32bits\n");
3269 return FALSE;
3272 f.l_start = dwFileOffsetLow;
3273 f.l_len = nNumberOfBytesToLockLow;
3274 f.l_whence = SEEK_SET;
3275 f.l_pid = 0;
3276 f.l_type = F_WRLCK;
3278 if (!(file = FILE_GetFile(hFile,0,NULL))) return FALSE;
3280 /* shadow locks internally */
3281 if (!DOS_AddLock(file, &f)) {
3282 SetLastError( ERROR_LOCK_VIOLATION );
3283 return FALSE;
3286 /* FIXME: Unix locking commented out for now, doesn't work with Excel */
3287 #ifdef USE_UNIX_LOCKS
3288 if (fcntl(file->unix_handle, F_SETLK, &f) == -1) {
3289 if (errno == EACCES || errno == EAGAIN) {
3290 SetLastError( ERROR_LOCK_VIOLATION );
3292 else {
3293 FILE_SetDosError();
3295 /* remove our internal copy of the lock */
3296 DOS_RemoveLock(file, &f);
3297 return FALSE;
3299 #endif
3300 return TRUE;
3304 /**************************************************************************
3305 * UnlockFile (KERNEL32.@)
3307 BOOL WINAPI UnlockFile(
3308 HANDLE hFile,DWORD dwFileOffsetLow,DWORD dwFileOffsetHigh,
3309 DWORD nNumberOfBytesToUnlockLow,DWORD nNumberOfBytesToUnlockHigh )
3311 FILE_OBJECT *file;
3312 struct flock f;
3314 TRACE("handle %d offsetlow=%ld offsethigh=%ld nbyteslow=%ld nbyteshigh=%ld\n",
3315 hFile, dwFileOffsetLow, dwFileOffsetHigh,
3316 nNumberOfBytesToUnlockLow, nNumberOfBytesToUnlockHigh);
3318 if (dwFileOffsetHigh || nNumberOfBytesToUnlockHigh) {
3319 WARN("Unimplemented bytes > 32bits\n");
3320 return FALSE;
3323 f.l_start = dwFileOffsetLow;
3324 f.l_len = nNumberOfBytesToUnlockLow;
3325 f.l_whence = SEEK_SET;
3326 f.l_pid = 0;
3327 f.l_type = F_UNLCK;
3329 if (!(file = FILE_GetFile(hFile,0,NULL))) return FALSE;
3331 DOS_RemoveLock(file, &f); /* ok if fails - may be another wine */
3333 /* FIXME: Unix locking commented out for now, doesn't work with Excel */
3334 #ifdef USE_UNIX_LOCKS
3335 if (fcntl(file->unix_handle, F_SETLK, &f) == -1) {
3336 FILE_SetDosError();
3337 return FALSE;
3339 #endif
3340 return TRUE;
3342 #endif
3344 /**************************************************************************
3345 * GetFileAttributesExW (KERNEL32.@)
3347 BOOL WINAPI GetFileAttributesExW(
3348 LPCWSTR lpFileName, GET_FILEEX_INFO_LEVELS fInfoLevelId,
3349 LPVOID lpFileInformation)
3351 DOS_FULL_NAME full_name;
3352 BY_HANDLE_FILE_INFORMATION info;
3354 if (!lpFileName || !lpFileInformation)
3356 SetLastError(ERROR_INVALID_PARAMETER);
3357 return FALSE;
3360 if (fInfoLevelId == GetFileExInfoStandard) {
3361 LPWIN32_FILE_ATTRIBUTE_DATA lpFad =
3362 (LPWIN32_FILE_ATTRIBUTE_DATA) lpFileInformation;
3363 if (!DOSFS_GetFullName( lpFileName, TRUE, &full_name )) return FALSE;
3364 if (!FILE_Stat( full_name.long_name, &info, NULL )) return FALSE;
3366 lpFad->dwFileAttributes = info.dwFileAttributes;
3367 lpFad->ftCreationTime = info.ftCreationTime;
3368 lpFad->ftLastAccessTime = info.ftLastAccessTime;
3369 lpFad->ftLastWriteTime = info.ftLastWriteTime;
3370 lpFad->nFileSizeHigh = info.nFileSizeHigh;
3371 lpFad->nFileSizeLow = info.nFileSizeLow;
3373 else {
3374 FIXME("invalid info level %d!\n", fInfoLevelId);
3375 return FALSE;
3378 return TRUE;
3382 /**************************************************************************
3383 * GetFileAttributesExA (KERNEL32.@)
3385 BOOL WINAPI GetFileAttributesExA(
3386 LPCSTR filename, GET_FILEEX_INFO_LEVELS fInfoLevelId,
3387 LPVOID lpFileInformation)
3389 UNICODE_STRING filenameW;
3390 BOOL ret = FALSE;
3392 if (!filename || !lpFileInformation)
3394 SetLastError(ERROR_INVALID_PARAMETER);
3395 return FALSE;
3398 if (RtlCreateUnicodeStringFromAsciiz(&filenameW, filename))
3400 ret = GetFileAttributesExW(filenameW.Buffer, fInfoLevelId, lpFileInformation);
3401 RtlFreeUnicodeString(&filenameW);
3403 else
3404 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
3405 return ret;
3408 /**************************************************************************
3409 * ReplaceFileW (KERNEL32.@)
3410 * ReplaceFile (KERNEL32.@)
3412 BOOL WINAPI ReplaceFileW(LPCWSTR lpReplacedFileName,LPCWSTR lpReplacementFileName,
3413 LPCWSTR lpBackupFileName, DWORD dwReplaceFlags,
3414 LPVOID lpExclude, LPVOID lpReserved)
3416 FIXME("(%s,%s,%s,%08lx,%p,%p) stub\n",debugstr_w(lpReplacedFileName),debugstr_w(lpReplacementFileName),
3417 debugstr_w(lpBackupFileName),dwReplaceFlags,lpExclude,lpReserved);
3418 SetLastError(ERROR_UNABLE_TO_MOVE_REPLACEMENT);
3419 return FALSE;
3422 /**************************************************************************
3423 * ReplaceFileA (KERNEL32.@)
3425 BOOL WINAPI ReplaceFileA(LPCSTR lpReplacedFileName,LPCSTR lpReplacementFileName,
3426 LPCSTR lpBackupFileName, DWORD dwReplaceFlags,
3427 LPVOID lpExclude, LPVOID lpReserved)
3429 FIXME("(%s,%s,%s,%08lx,%p,%p) stub\n",lpReplacedFileName,lpReplacementFileName,
3430 lpBackupFileName,dwReplaceFlags,lpExclude,lpReserved);
3431 SetLastError(ERROR_UNABLE_TO_MOVE_REPLACEMENT);
3432 return FALSE;