Add support for Jack audio server.
[wine.git] / files / file.c
blob0ae97d29aeaefa4b4b3878d2f2f350a50e36b499
1 /*
2 * File handling functions
4 * Copyright 1993 John Burton
5 * Copyright 1996 Alexandre Julliard
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 * TODO:
22 * Fix the CopyFileEx methods to implement the "extended" functionality.
23 * Right now, they simply call the CopyFile method.
26 #include "config.h"
27 #include "wine/port.h"
29 #include <assert.h>
30 #include <ctype.h>
31 #include <errno.h>
32 #include <fcntl.h>
33 #include <stdlib.h>
34 #include <stdio.h>
35 #include <string.h>
36 #ifdef HAVE_SYS_ERRNO_H
37 #include <sys/errno.h>
38 #endif
39 #include <sys/types.h>
40 #include <sys/stat.h>
41 #ifdef HAVE_SYS_MMAN_H
42 #include <sys/mman.h>
43 #endif
44 #ifdef HAVE_SYS_TIME_H
45 # include <sys/time.h>
46 #endif
47 #ifdef HAVE_SYS_POLL_H
48 # include <sys/poll.h>
49 #endif
50 #include <time.h>
51 #ifdef HAVE_UNISTD_H
52 # include <unistd.h>
53 #endif
54 #ifdef HAVE_UTIME_H
55 # include <utime.h>
56 #endif
58 #include "winerror.h"
59 #include "windef.h"
60 #include "winbase.h"
61 #include "winternl.h"
62 #include "wine/winbase16.h"
63 #include "wine/server.h"
65 #include "drive.h"
66 #include "file.h"
67 #include "async.h"
68 #include "heap.h"
69 #include "msdos.h"
70 #include "wincon.h"
72 #include "smb.h"
73 #include "wine/unicode.h"
74 #include "wine/debug.h"
76 WINE_DEFAULT_DEBUG_CHANNEL(file);
78 #if defined(MAP_ANONYMOUS) && !defined(MAP_ANON)
79 #define MAP_ANON MAP_ANONYMOUS
80 #endif
82 /* Size of per-process table of DOS handles */
83 #define DOS_TABLE_SIZE 256
85 /* Macro to derive file offset from OVERLAPPED struct */
86 #define OVERLAPPED_OFFSET(overlapped) ((off_t) (overlapped)->Offset + ((off_t) (overlapped)->OffsetHigh << 32))
88 static HANDLE dos_handles[DOS_TABLE_SIZE];
90 mode_t FILE_umask;
92 extern HANDLE WINAPI FILE_SmbOpen(LPCSTR name);
94 /***********************************************************************
95 * Asynchronous file I/O *
97 static DWORD fileio_get_async_status (const async_private *ovp);
98 static DWORD fileio_get_async_count (const async_private *ovp);
99 static void fileio_set_async_status (async_private *ovp, const DWORD status);
100 static void CALLBACK fileio_call_completion_func (ULONG_PTR data);
101 static void fileio_async_cleanup (async_private *ovp);
103 static async_ops fileio_async_ops =
105 fileio_get_async_status, /* get_status */
106 fileio_set_async_status, /* set_status */
107 fileio_get_async_count, /* get_count */
108 fileio_call_completion_func, /* call_completion */
109 fileio_async_cleanup /* cleanup */
112 static async_ops fileio_nocomp_async_ops =
114 fileio_get_async_status, /* get_status */
115 fileio_set_async_status, /* set_status */
116 fileio_get_async_count, /* get_count */
117 NULL, /* call_completion */
118 fileio_async_cleanup /* cleanup */
121 typedef struct async_fileio
123 struct async_private async;
124 LPOVERLAPPED lpOverlapped;
125 LPOVERLAPPED_COMPLETION_ROUTINE completion_func;
126 char *buffer;
127 unsigned int count;
128 enum fd_type fd_type;
129 } async_fileio;
131 static DWORD fileio_get_async_status (const struct async_private *ovp)
133 return ((async_fileio*) ovp)->lpOverlapped->Internal;
136 static void fileio_set_async_status (async_private *ovp, const DWORD status)
138 ((async_fileio*) ovp)->lpOverlapped->Internal = status;
141 static DWORD fileio_get_async_count (const struct async_private *ovp)
143 async_fileio *fileio = (async_fileio*) ovp;
145 if (fileio->count < fileio->lpOverlapped->InternalHigh)
146 return 0;
147 return fileio->count - fileio->lpOverlapped->InternalHigh;
150 static void CALLBACK fileio_call_completion_func (ULONG_PTR data)
152 async_fileio *ovp = (async_fileio*) data;
153 TRACE ("data: %p\n", ovp);
155 ovp->completion_func( RtlNtStatusToDosError ( ovp->lpOverlapped->Internal ),
156 ovp->lpOverlapped->InternalHigh,
157 ovp->lpOverlapped );
159 fileio_async_cleanup ( &ovp->async );
162 static void fileio_async_cleanup ( struct async_private *ovp )
164 HeapFree ( GetProcessHeap(), 0, ovp );
167 /***********************************************************************
168 * FILE_ConvertOFMode
170 * Convert OF_* mode into flags for CreateFile.
172 static void FILE_ConvertOFMode( INT mode, DWORD *access, DWORD *sharing )
174 switch(mode & 0x03)
176 case OF_READ: *access = GENERIC_READ; break;
177 case OF_WRITE: *access = GENERIC_WRITE; break;
178 case OF_READWRITE: *access = GENERIC_READ | GENERIC_WRITE; break;
179 default: *access = 0; break;
181 switch(mode & 0x70)
183 case OF_SHARE_EXCLUSIVE: *sharing = 0; break;
184 case OF_SHARE_DENY_WRITE: *sharing = FILE_SHARE_READ; break;
185 case OF_SHARE_DENY_READ: *sharing = FILE_SHARE_WRITE; break;
186 case OF_SHARE_DENY_NONE:
187 case OF_SHARE_COMPAT:
188 default: *sharing = FILE_SHARE_READ | FILE_SHARE_WRITE; break;
193 /***********************************************************************
194 * FILE_strcasecmp
196 * locale-independent case conversion for file I/O
198 int FILE_strcasecmp( const char *str1, const char *str2 )
200 int ret = 0;
201 for ( ; ; str1++, str2++)
202 if ((ret = FILE_toupper(*str1) - FILE_toupper(*str2)) || !*str1) break;
203 return ret;
207 /***********************************************************************
208 * FILE_strncasecmp
210 * locale-independent case conversion for file I/O
212 int FILE_strncasecmp( const char *str1, const char *str2, int len )
214 int ret = 0;
215 for ( ; len > 0; len--, str1++, str2++)
216 if ((ret = FILE_toupper(*str1) - FILE_toupper(*str2)) || !*str1) break;
217 return ret;
221 /***********************************************************************
222 * FILE_GetNtStatus(void)
224 * Retrieve the Nt Status code from errno.
225 * Try to be consistent with FILE_SetDosError().
227 DWORD FILE_GetNtStatus(void)
229 int err = errno;
230 DWORD nt;
231 TRACE ( "errno = %d\n", errno );
232 switch ( err )
234 case EAGAIN: nt = STATUS_SHARING_VIOLATION; break;
235 case EBADF: nt = STATUS_INVALID_HANDLE; break;
236 case ENOSPC: nt = STATUS_DISK_FULL; break;
237 case EPERM:
238 case EROFS:
239 case EACCES: nt = STATUS_ACCESS_DENIED; break;
240 case ENOENT: nt = STATUS_SHARING_VIOLATION; break;
241 case EISDIR: nt = STATUS_FILE_IS_A_DIRECTORY; break;
242 case EMFILE:
243 case ENFILE: nt = STATUS_NO_MORE_FILES; break;
244 case EINVAL:
245 case ENOTEMPTY: nt = STATUS_DIRECTORY_NOT_EMPTY; break;
246 case EPIPE: nt = STATUS_PIPE_BROKEN; break;
247 case ENOEXEC: /* ?? */
248 case ESPIPE: /* ?? */
249 case EEXIST: /* ?? */
250 default:
251 FIXME ( "Converting errno %d to STATUS_UNSUCCESSFUL\n", err );
252 nt = STATUS_UNSUCCESSFUL;
254 return nt;
257 /***********************************************************************
258 * FILE_SetDosError
260 * Set the DOS error code from errno.
262 void FILE_SetDosError(void)
264 int save_errno = errno; /* errno gets overwritten by printf */
266 TRACE("errno = %d %s\n", errno, strerror(errno));
267 switch (save_errno)
269 case EAGAIN:
270 SetLastError( ERROR_SHARING_VIOLATION );
271 break;
272 case EBADF:
273 SetLastError( ERROR_INVALID_HANDLE );
274 break;
275 case ENOSPC:
276 SetLastError( ERROR_HANDLE_DISK_FULL );
277 break;
278 case EACCES:
279 case EPERM:
280 case EROFS:
281 SetLastError( ERROR_ACCESS_DENIED );
282 break;
283 case EBUSY:
284 SetLastError( ERROR_LOCK_VIOLATION );
285 break;
286 case ENOENT:
287 SetLastError( ERROR_FILE_NOT_FOUND );
288 break;
289 case EISDIR:
290 SetLastError( ERROR_CANNOT_MAKE );
291 break;
292 case ENFILE:
293 case EMFILE:
294 SetLastError( ERROR_NO_MORE_FILES );
295 break;
296 case EEXIST:
297 SetLastError( ERROR_FILE_EXISTS );
298 break;
299 case EINVAL:
300 case ESPIPE:
301 SetLastError( ERROR_SEEK );
302 break;
303 case ENOTEMPTY:
304 SetLastError( ERROR_DIR_NOT_EMPTY );
305 break;
306 case ENOEXEC:
307 SetLastError( ERROR_BAD_FORMAT );
308 break;
309 default:
310 WARN("unknown file error: %s\n", strerror(save_errno) );
311 SetLastError( ERROR_GEN_FAILURE );
312 break;
314 errno = save_errno;
318 /***********************************************************************
319 * FILE_GetUnixHandleType
321 * Retrieve the Unix handle corresponding to a file handle.
322 * Returns -1 on failure.
324 static int FILE_GetUnixHandleType( HANDLE handle, DWORD access, enum fd_type *type, int *flags_ptr )
326 int ret, flags, fd = -1;
328 ret = wine_server_handle_to_fd( handle, access, &fd, type, &flags );
329 if (flags_ptr) *flags_ptr = flags;
330 if (ret) SetLastError( RtlNtStatusToDosError(ret) );
331 else if (((access & GENERIC_READ) && (flags & FD_FLAG_RECV_SHUTDOWN)) ||
332 ((access & GENERIC_WRITE) && (flags & FD_FLAG_SEND_SHUTDOWN)))
334 close (fd);
335 SetLastError ( ERROR_PIPE_NOT_CONNECTED );
336 return -1;
338 return fd;
341 /***********************************************************************
342 * FILE_GetUnixHandle
344 * Retrieve the Unix handle corresponding to a file handle.
345 * Returns -1 on failure.
347 int FILE_GetUnixHandle( HANDLE handle, DWORD access )
349 return FILE_GetUnixHandleType( handle, access, NULL, NULL );
352 /*************************************************************************
353 * FILE_OpenConsole
355 * Open a handle to the current process console.
356 * Returns 0 on failure.
358 static HANDLE FILE_OpenConsole( BOOL output, DWORD access, DWORD sharing, LPSECURITY_ATTRIBUTES sa )
360 HANDLE ret;
362 SERVER_START_REQ( open_console )
364 req->from = output;
365 req->access = access;
366 req->share = sharing;
367 req->inherit = (sa && (sa->nLength>=sizeof(*sa)) && sa->bInheritHandle);
368 SetLastError(0);
369 wine_server_call_err( req );
370 ret = reply->handle;
372 SERVER_END_REQ;
373 return ret;
376 /* FIXME: those routines defined as pointers are needed, because this file is
377 * currently compiled into NTDLL whereas it belongs to kernel32.
378 * this shall go away once all the DLL separation process is done
380 typedef BOOL (WINAPI* pRW)(HANDLE, const void*, DWORD, DWORD*, void*);
382 static BOOL FILE_ReadConsole(HANDLE hCon, void* buf, DWORD nb, DWORD* nr, void* p)
384 static HANDLE hKernel /* = 0 */;
385 static pRW pReadConsole /* = 0 */;
387 if ((!hKernel && !(hKernel = LoadLibraryA("kernel32"))) ||
388 (!pReadConsole &&
389 !(pReadConsole = GetProcAddress(hKernel, "ReadConsoleA"))))
391 *nr = 0;
392 return 0;
394 return (pReadConsole)(hCon, buf, nb, nr, p);
397 static BOOL FILE_WriteConsole(HANDLE hCon, const void* buf, DWORD nb, DWORD* nr, void* p)
399 static HANDLE hKernel /* = 0 */;
400 static pRW pWriteConsole /* = 0 */;
402 if ((!hKernel && !(hKernel = LoadLibraryA("kernel32"))) ||
403 (!pWriteConsole &&
404 !(pWriteConsole = GetProcAddress(hKernel, "WriteConsoleA"))))
406 *nr = 0;
407 return 0;
409 return (pWriteConsole)(hCon, buf, nb, nr, p);
411 /* end of FIXME */
413 /***********************************************************************
414 * FILE_CreateFile
416 * Implementation of CreateFile. Takes a Unix path name.
417 * Returns 0 on failure.
419 HANDLE FILE_CreateFile( LPCSTR filename, DWORD access, DWORD sharing,
420 LPSECURITY_ATTRIBUTES sa, DWORD creation,
421 DWORD attributes, HANDLE template, BOOL fail_read_only,
422 UINT drive_type )
424 unsigned int err;
425 HANDLE ret;
427 for (;;)
429 SERVER_START_REQ( create_file )
431 req->access = access;
432 req->inherit = (sa && (sa->nLength>=sizeof(*sa)) && sa->bInheritHandle);
433 req->sharing = sharing;
434 req->create = creation;
435 req->attrs = attributes;
436 req->drive_type = drive_type;
437 wine_server_add_data( req, filename, strlen(filename) );
438 SetLastError(0);
439 err = wine_server_call( req );
440 ret = reply->handle;
442 SERVER_END_REQ;
444 /* If write access failed, retry without GENERIC_WRITE */
446 if (!ret && !fail_read_only && (access & GENERIC_WRITE))
448 if ((err == STATUS_MEDIA_WRITE_PROTECTED) || (err == STATUS_ACCESS_DENIED))
450 TRACE("Write access failed for file '%s', trying without "
451 "write access\n", filename);
452 access &= ~GENERIC_WRITE;
453 continue;
457 if (err)
459 /* In the case file creation was rejected due to CREATE_NEW flag
460 * was specified and file with that name already exists, correct
461 * last error is ERROR_FILE_EXISTS and not ERROR_ALREADY_EXISTS.
462 * Note: RtlNtStatusToDosError is not the subject to blame here.
464 if (err == STATUS_OBJECT_NAME_COLLISION)
465 SetLastError( ERROR_FILE_EXISTS );
466 else
467 SetLastError( RtlNtStatusToDosError(err) );
470 if (!ret) WARN("Unable to create file '%s' (GLE %ld)\n", filename, GetLastError());
471 return ret;
476 /***********************************************************************
477 * FILE_CreateDevice
479 * Same as FILE_CreateFile but for a device
480 * Returns 0 on failure.
482 HANDLE FILE_CreateDevice( int client_id, DWORD access, LPSECURITY_ATTRIBUTES sa )
484 HANDLE ret;
485 SERVER_START_REQ( create_device )
487 req->access = access;
488 req->inherit = (sa && (sa->nLength>=sizeof(*sa)) && sa->bInheritHandle);
489 req->id = client_id;
490 SetLastError(0);
491 wine_server_call_err( req );
492 ret = reply->handle;
494 SERVER_END_REQ;
495 return ret;
498 static HANDLE FILE_OpenPipe(LPCWSTR name, DWORD access)
500 HANDLE ret;
501 DWORD len = 0;
503 if (name && (len = strlenW(name)) > MAX_PATH)
505 SetLastError( ERROR_FILENAME_EXCED_RANGE );
506 return 0;
508 SERVER_START_REQ( open_named_pipe )
510 req->access = access;
511 SetLastError(0);
512 wine_server_add_data( req, name, len * sizeof(WCHAR) );
513 wine_server_call_err( req );
514 ret = reply->handle;
516 SERVER_END_REQ;
517 TRACE("Returned %p\n",ret);
518 return ret;
521 /*************************************************************************
522 * CreateFileW [KERNEL32.@] Creates or opens a file or other object
524 * Creates or opens an object, and returns a handle that can be used to
525 * access that object.
527 * PARAMS
529 * filename [in] pointer to filename to be accessed
530 * access [in] access mode requested
531 * sharing [in] share mode
532 * sa [in] pointer to security attributes
533 * creation [in] how to create the file
534 * attributes [in] attributes for newly created file
535 * template [in] handle to file with extended attributes to copy
537 * RETURNS
538 * Success: Open handle to specified file
539 * Failure: INVALID_HANDLE_VALUE
541 * NOTES
542 * Should call SetLastError() on failure.
544 * BUGS
546 * Doesn't support character devices, template files, or a
547 * lot of the 'attributes' flags yet.
549 HANDLE WINAPI CreateFileW( LPCWSTR filename, DWORD access, DWORD sharing,
550 LPSECURITY_ATTRIBUTES sa, DWORD creation,
551 DWORD attributes, HANDLE template )
553 DOS_FULL_NAME full_name;
554 HANDLE ret;
555 static const WCHAR bkslashes_with_question_markW[] = {'\\','\\','?','\\',0};
556 static const WCHAR bkslashes_with_dotW[] = {'\\','\\','.','\\',0};
557 static const WCHAR bkslashesW[] = {'\\','\\',0};
558 static const WCHAR coninW[] = {'C','O','N','I','N','$',0};
559 static const WCHAR conoutW[] = {'C','O','N','O','U','T','$',0};
561 if (!filename)
563 SetLastError( ERROR_INVALID_PARAMETER );
564 return INVALID_HANDLE_VALUE;
566 TRACE("%s %s%s%s%s%s%s%s attributes 0x%lx\n", debugstr_w(filename),
567 ((access & GENERIC_READ)==GENERIC_READ)?"GENERIC_READ ":"",
568 ((access & GENERIC_WRITE)==GENERIC_WRITE)?"GENERIC_WRITE ":"",
569 (!access)?"QUERY_ACCESS ":"",
570 ((sharing & FILE_SHARE_READ)==FILE_SHARE_READ)?"FILE_SHARE_READ ":"",
571 ((sharing & FILE_SHARE_WRITE)==FILE_SHARE_WRITE)?"FILE_SHARE_WRITE ":"",
572 ((sharing & FILE_SHARE_DELETE)==FILE_SHARE_DELETE)?"FILE_SHARE_DELETE ":"",
573 (creation ==CREATE_NEW)?"CREATE_NEW":
574 (creation ==CREATE_ALWAYS)?"CREATE_ALWAYS ":
575 (creation ==OPEN_EXISTING)?"OPEN_EXISTING ":
576 (creation ==OPEN_ALWAYS)?"OPEN_ALWAYS ":
577 (creation ==TRUNCATE_EXISTING)?"TRUNCATE_EXISTING ":"", attributes);
579 /* If the name starts with '\\?\', ignore the first 4 chars. */
580 if (!strncmpW(filename, bkslashes_with_question_markW, 4))
582 static const WCHAR uncW[] = {'U','N','C','\\',0};
583 filename += 4;
584 if (!strncmpiW(filename, uncW, 4))
586 FIXME("UNC name (%s) not supported.\n", debugstr_w(filename) );
587 SetLastError( ERROR_PATH_NOT_FOUND );
588 return INVALID_HANDLE_VALUE;
592 if (!strncmpW(filename, bkslashes_with_dotW, 4))
594 static const WCHAR pipeW[] = {'P','I','P','E','\\',0};
595 if(!strncmpiW(filename + 4, pipeW, 5))
597 TRACE("Opening a pipe: %s\n", debugstr_w(filename));
598 ret = FILE_OpenPipe(filename,access);
599 goto done;
601 else if (isalphaW(filename[4]) && filename[5] == ':' && filename[6] == '\0')
603 ret = FILE_CreateDevice( (toupperW(filename[4]) - 'A') | 0x20000, access, sa );
604 goto done;
606 else if (!DOSFS_GetDevice( filename ))
608 ret = DEVICE_Open( filename+4, access, sa );
609 goto done;
611 else
612 filename+=4; /* fall into DOSFS_Device case below */
615 /* If the name still starts with '\\', it's a UNC name. */
616 if (!strncmpW(filename, bkslashesW, 2))
618 ret = SMB_CreateFileW(filename, access, sharing, sa, creation, attributes, template );
619 goto done;
622 /* If the name contains a DOS wild card (* or ?), do no create a file */
623 if(strchrW(filename, '*') || strchrW(filename, '?'))
624 return INVALID_HANDLE_VALUE;
626 /* Open a console for CONIN$ or CONOUT$ */
627 if (!strcmpiW(filename, coninW))
629 ret = FILE_OpenConsole( FALSE, access, sharing, sa );
630 goto done;
632 if (!strcmpiW(filename, conoutW))
634 ret = FILE_OpenConsole( TRUE, access, sharing, sa );
635 goto done;
638 if (DOSFS_GetDevice( filename ))
640 TRACE("opening device %s\n", debugstr_w(filename) );
642 if (!(ret = DOSFS_OpenDevice( filename, access, attributes, sa )))
644 /* Do not silence this please. It is a critical error. -MM */
645 ERR("Couldn't open device %s!\n", debugstr_w(filename));
646 SetLastError( ERROR_FILE_NOT_FOUND );
648 goto done;
651 /* check for filename, don't check for last entry if creating */
652 if (!DOSFS_GetFullName( filename,
653 (creation == OPEN_EXISTING) ||
654 (creation == TRUNCATE_EXISTING),
655 &full_name )) {
656 WARN("Unable to get full filename from %s (GLE %ld)\n",
657 debugstr_w(filename), GetLastError());
658 return INVALID_HANDLE_VALUE;
661 ret = FILE_CreateFile( full_name.long_name, access, sharing,
662 sa, creation, attributes, template,
663 DRIVE_GetFlags(full_name.drive) & DRIVE_FAIL_READ_ONLY,
664 GetDriveTypeW( full_name.short_name ) );
665 done:
666 if (!ret) ret = INVALID_HANDLE_VALUE;
667 TRACE("returning %p\n", ret);
668 return ret;
673 /*************************************************************************
674 * CreateFileA (KERNEL32.@)
676 HANDLE WINAPI CreateFileA( LPCSTR filename, DWORD access, DWORD sharing,
677 LPSECURITY_ATTRIBUTES sa, DWORD creation,
678 DWORD attributes, HANDLE template)
680 UNICODE_STRING filenameW;
681 HANDLE ret = INVALID_HANDLE_VALUE;
683 if (!filename)
685 SetLastError( ERROR_INVALID_PARAMETER );
686 return INVALID_HANDLE_VALUE;
689 if (RtlCreateUnicodeStringFromAsciiz(&filenameW, filename))
691 ret = CreateFileW(filenameW.Buffer, access, sharing, sa, creation,
692 attributes, template);
693 RtlFreeUnicodeString(&filenameW);
695 else
696 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
697 return ret;
701 /***********************************************************************
702 * FILE_FillInfo
704 * Fill a file information from a struct stat.
706 static void FILE_FillInfo( struct stat *st, BY_HANDLE_FILE_INFORMATION *info )
708 if (S_ISDIR(st->st_mode))
709 info->dwFileAttributes = FILE_ATTRIBUTE_DIRECTORY;
710 else
711 info->dwFileAttributes = FILE_ATTRIBUTE_ARCHIVE;
712 if (!(st->st_mode & S_IWUSR))
713 info->dwFileAttributes |= FILE_ATTRIBUTE_READONLY;
715 RtlSecondsSince1970ToTime( st->st_mtime, (LARGE_INTEGER *)&info->ftCreationTime );
716 RtlSecondsSince1970ToTime( st->st_mtime, (LARGE_INTEGER *)&info->ftLastWriteTime );
717 RtlSecondsSince1970ToTime( st->st_atime, (LARGE_INTEGER *)&info->ftLastAccessTime );
719 info->dwVolumeSerialNumber = 0; /* FIXME */
720 info->nFileSizeHigh = 0;
721 info->nFileSizeLow = 0;
722 if (!S_ISDIR(st->st_mode)) {
723 info->nFileSizeHigh = st->st_size >> 32;
724 info->nFileSizeLow = st->st_size & 0xffffffff;
726 info->nNumberOfLinks = st->st_nlink;
727 info->nFileIndexHigh = 0;
728 info->nFileIndexLow = st->st_ino;
732 /***********************************************************************
733 * FILE_Stat
735 * Stat a Unix path name. Return TRUE if OK.
737 BOOL FILE_Stat( LPCSTR unixName, BY_HANDLE_FILE_INFORMATION *info, BOOL *is_symlink_ptr )
739 struct stat st;
740 int is_symlink;
741 LPCSTR p;
743 if (lstat( unixName, &st ) == -1)
745 FILE_SetDosError();
746 return FALSE;
748 is_symlink = S_ISLNK(st.st_mode);
749 if (is_symlink)
751 /* do a "real" stat to find out
752 about the type of the symlink destination */
753 if (stat( unixName, &st ) == -1)
755 FILE_SetDosError();
756 return FALSE;
760 /* fill in the information we gathered so far */
761 FILE_FillInfo( &st, info );
763 /* and now see if this is a hidden file, based on the name */
764 p = strrchr( unixName, '/');
765 p = p ? p + 1 : unixName;
766 if (*p == '.' && *(p+1) && (*(p+1) != '.' || *(p+2)))
768 static const WCHAR wineW[] = {'w','i','n','e',0};
769 static const WCHAR ShowDotFilesW[] = {'S','h','o','w','D','o','t','F','i','l','e','s',0};
770 static int show_dot_files = -1;
771 if (show_dot_files == -1)
772 show_dot_files = PROFILE_GetWineIniBool(wineW, ShowDotFilesW, 0);
773 if (!show_dot_files)
774 info->dwFileAttributes |= FILE_ATTRIBUTE_HIDDEN;
776 if (is_symlink_ptr) *is_symlink_ptr = is_symlink;
777 return TRUE;
781 /***********************************************************************
782 * GetFileInformationByHandle (KERNEL32.@)
784 DWORD WINAPI GetFileInformationByHandle( HANDLE hFile,
785 BY_HANDLE_FILE_INFORMATION *info )
787 DWORD ret;
788 if (!info) return 0;
790 TRACE("%p\n", hFile);
792 SERVER_START_REQ( get_file_info )
794 req->handle = hFile;
795 if ((ret = !wine_server_call_err( req )))
797 /* FIXME: which file types are supported ?
798 * Serial ports (FILE_TYPE_CHAR) are not,
799 * and MSDN also says that pipes are not supported.
800 * FILE_TYPE_REMOTE seems to be supported according to
801 * MSDN q234741.txt */
802 if ((reply->type == FILE_TYPE_DISK) || (reply->type == FILE_TYPE_REMOTE))
804 RtlSecondsSince1970ToTime( reply->write_time, (LARGE_INTEGER *)&info->ftCreationTime );
805 RtlSecondsSince1970ToTime( reply->write_time, (LARGE_INTEGER *)&info->ftLastWriteTime );
806 RtlSecondsSince1970ToTime( reply->access_time, (LARGE_INTEGER *)&info->ftLastAccessTime );
807 info->dwFileAttributes = reply->attr;
808 info->dwVolumeSerialNumber = reply->serial;
809 info->nFileSizeHigh = reply->size_high;
810 info->nFileSizeLow = reply->size_low;
811 info->nNumberOfLinks = reply->links;
812 info->nFileIndexHigh = reply->index_high;
813 info->nFileIndexLow = reply->index_low;
815 else
817 SetLastError(ERROR_NOT_SUPPORTED);
818 ret = 0;
822 SERVER_END_REQ;
823 return ret;
827 /**************************************************************************
828 * GetFileAttributes (KERNEL.420)
830 DWORD WINAPI GetFileAttributes16( LPCSTR name )
832 return GetFileAttributesA( name );
836 /**************************************************************************
837 * GetFileAttributesW (KERNEL32.@)
839 DWORD WINAPI GetFileAttributesW( LPCWSTR name )
841 DOS_FULL_NAME full_name;
842 BY_HANDLE_FILE_INFORMATION info;
844 if (name == NULL)
846 SetLastError( ERROR_INVALID_PARAMETER );
847 return -1;
849 if (!DOSFS_GetFullName( name, TRUE, &full_name) )
850 return -1;
851 if (!FILE_Stat( full_name.long_name, &info, NULL )) return -1;
852 return info.dwFileAttributes;
856 /**************************************************************************
857 * GetFileAttributesA (KERNEL32.@)
859 DWORD WINAPI GetFileAttributesA( LPCSTR name )
861 UNICODE_STRING nameW;
862 DWORD ret = (DWORD)-1;
864 if (!name)
866 SetLastError( ERROR_INVALID_PARAMETER );
867 return (DWORD)-1;
870 if (RtlCreateUnicodeStringFromAsciiz(&nameW, name))
872 ret = GetFileAttributesW(nameW.Buffer);
873 RtlFreeUnicodeString(&nameW);
875 else
876 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
877 return ret;
881 /**************************************************************************
882 * SetFileAttributes (KERNEL.421)
884 BOOL16 WINAPI SetFileAttributes16( LPCSTR lpFileName, DWORD attributes )
886 return SetFileAttributesA( lpFileName, attributes );
890 /**************************************************************************
891 * SetFileAttributesW (KERNEL32.@)
893 BOOL WINAPI SetFileAttributesW(LPCWSTR lpFileName, DWORD attributes)
895 struct stat buf;
896 DOS_FULL_NAME full_name;
898 if (!lpFileName)
900 SetLastError( ERROR_INVALID_PARAMETER );
901 return FALSE;
904 TRACE("(%s,%lx)\n", debugstr_w(lpFileName), attributes);
906 if (!DOSFS_GetFullName( lpFileName, TRUE, &full_name ))
907 return FALSE;
909 if(stat(full_name.long_name,&buf)==-1)
911 FILE_SetDosError();
912 return FALSE;
914 if (attributes & FILE_ATTRIBUTE_READONLY)
916 if(S_ISDIR(buf.st_mode))
917 /* FIXME */
918 WARN("FILE_ATTRIBUTE_READONLY ignored for directory.\n");
919 else
920 buf.st_mode &= ~0222; /* octal!, clear write permission bits */
921 attributes &= ~FILE_ATTRIBUTE_READONLY;
923 else
925 /* add write permission */
926 buf.st_mode |= (0600 | ((buf.st_mode & 044) >> 1)) & (~FILE_umask);
928 if (attributes & FILE_ATTRIBUTE_DIRECTORY)
930 if (!S_ISDIR(buf.st_mode))
931 FIXME("SetFileAttributes expected the file %s to be a directory\n",
932 debugstr_w(lpFileName));
933 attributes &= ~FILE_ATTRIBUTE_DIRECTORY;
935 attributes &= ~(FILE_ATTRIBUTE_NORMAL|FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_HIDDEN|FILE_ATTRIBUTE_SYSTEM);
936 if (attributes)
937 FIXME("(%s):%lx attribute(s) not implemented.\n", debugstr_w(lpFileName), attributes);
938 if (-1==chmod(full_name.long_name,buf.st_mode))
940 if (GetDriveTypeW(lpFileName) == DRIVE_CDROM)
942 SetLastError( ERROR_ACCESS_DENIED );
943 return FALSE;
947 * FIXME: We don't return FALSE here because of differences between
948 * Linux and Windows privileges. Under Linux only the owner of
949 * the file is allowed to change file attributes. Under Windows,
950 * applications expect that if you can write to a file, you can also
951 * change its attributes (see GENERIC_WRITE). We could try to be
952 * clever here but that would break multi-user installations where
953 * users share read-only DLLs. This is because some installers like
954 * to change attributes of already installed DLLs.
956 FIXME("Couldn't set file attributes for existing file \"%s\".\n"
957 "Check permissions or set VFAT \"quiet\" mount flag\n", full_name.long_name);
959 return TRUE;
963 /**************************************************************************
964 * SetFileAttributesA (KERNEL32.@)
966 BOOL WINAPI SetFileAttributesA(LPCSTR lpFileName, DWORD attributes)
968 UNICODE_STRING filenameW;
969 BOOL ret = FALSE;
971 if (!lpFileName)
973 SetLastError( ERROR_INVALID_PARAMETER );
974 return FALSE;
977 if (RtlCreateUnicodeStringFromAsciiz(&filenameW, lpFileName))
979 ret = SetFileAttributesW(filenameW.Buffer, attributes);
980 RtlFreeUnicodeString(&filenameW);
982 else
983 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
984 return ret;
988 /***********************************************************************
989 * GetFileSize (KERNEL32.@)
991 DWORD WINAPI GetFileSize( HANDLE hFile, LPDWORD filesizehigh )
993 BY_HANDLE_FILE_INFORMATION info;
994 if (!GetFileInformationByHandle( hFile, &info )) return -1;
995 if (filesizehigh) *filesizehigh = info.nFileSizeHigh;
996 return info.nFileSizeLow;
1000 /***********************************************************************
1001 * GetFileSizeEx (KERNEL32.@)
1003 BOOL WINAPI GetFileSizeEx( HANDLE hFile, PLARGE_INTEGER lpFileSize )
1005 BY_HANDLE_FILE_INFORMATION info;
1007 if (!lpFileSize)
1009 SetLastError( ERROR_INVALID_PARAMETER );
1010 return FALSE;
1013 if (!GetFileInformationByHandle( hFile, &info ))
1015 return FALSE;
1018 lpFileSize->s.LowPart = info.nFileSizeLow;
1019 lpFileSize->s.HighPart = info.nFileSizeHigh;
1021 return TRUE;
1025 /***********************************************************************
1026 * GetFileTime (KERNEL32.@)
1028 BOOL WINAPI GetFileTime( HANDLE hFile, FILETIME *lpCreationTime,
1029 FILETIME *lpLastAccessTime,
1030 FILETIME *lpLastWriteTime )
1032 BY_HANDLE_FILE_INFORMATION info;
1033 if (!GetFileInformationByHandle( hFile, &info )) return FALSE;
1034 if (lpCreationTime) *lpCreationTime = info.ftCreationTime;
1035 if (lpLastAccessTime) *lpLastAccessTime = info.ftLastAccessTime;
1036 if (lpLastWriteTime) *lpLastWriteTime = info.ftLastWriteTime;
1037 return TRUE;
1040 /***********************************************************************
1041 * CompareFileTime (KERNEL32.@)
1043 INT WINAPI CompareFileTime( LPFILETIME x, LPFILETIME y )
1045 if (!x || !y) return -1;
1047 if (x->dwHighDateTime > y->dwHighDateTime)
1048 return 1;
1049 if (x->dwHighDateTime < y->dwHighDateTime)
1050 return -1;
1051 if (x->dwLowDateTime > y->dwLowDateTime)
1052 return 1;
1053 if (x->dwLowDateTime < y->dwLowDateTime)
1054 return -1;
1055 return 0;
1058 /***********************************************************************
1059 * FILE_GetTempFileName : utility for GetTempFileName
1061 static UINT FILE_GetTempFileName( LPCWSTR path, LPCWSTR prefix, UINT unique,
1062 LPWSTR buffer )
1064 static UINT unique_temp;
1065 DOS_FULL_NAME full_name;
1066 int i;
1067 LPWSTR p;
1068 UINT num;
1069 char buf[20];
1071 if ( !path || !prefix || !buffer )
1073 SetLastError( ERROR_INVALID_PARAMETER );
1074 return 0;
1077 if (!unique_temp) unique_temp = time(NULL) & 0xffff;
1078 num = unique ? (unique & 0xffff) : (unique_temp++ & 0xffff);
1080 strcpyW( buffer, path );
1081 p = buffer + strlenW(buffer);
1083 /* add a \, if there isn't one and path is more than just the drive letter ... */
1084 if ( !((strlenW(buffer) == 2) && (buffer[1] == ':'))
1085 && ((p == buffer) || (p[-1] != '\\'))) *p++ = '\\';
1087 for (i = 3; (i > 0) && (*prefix); i--) *p++ = *prefix++;
1089 sprintf( buf, "%04x.tmp", num );
1090 MultiByteToWideChar(CP_ACP, 0, buf, -1, p, 20);
1092 /* Now try to create it */
1094 if (!unique)
1098 HANDLE handle = CreateFileW( buffer, GENERIC_WRITE, 0, NULL,
1099 CREATE_NEW, FILE_ATTRIBUTE_NORMAL, 0 );
1100 if (handle != INVALID_HANDLE_VALUE)
1101 { /* We created it */
1102 TRACE("created %s\n", debugstr_w(buffer) );
1103 CloseHandle( handle );
1104 break;
1106 if (GetLastError() != ERROR_FILE_EXISTS)
1107 break; /* No need to go on */
1108 num++;
1109 sprintf( buf, "%04x.tmp", num );
1110 MultiByteToWideChar(CP_ACP, 0, buf, -1, p, 20);
1111 } while (num != (unique & 0xffff));
1114 /* Get the full path name */
1116 if (DOSFS_GetFullName( buffer, FALSE, &full_name ))
1118 char *slash;
1119 /* Check if we have write access in the directory */
1120 if ((slash = strrchr( full_name.long_name, '/' ))) *slash = '\0';
1121 if (access( full_name.long_name, W_OK ) == -1)
1122 WARN("returns %s, which doesn't seem to be writeable.\n",
1123 debugstr_w(buffer) );
1125 TRACE("returning %s\n", debugstr_w(buffer) );
1126 return unique ? unique : num;
1130 /***********************************************************************
1131 * GetTempFileNameA (KERNEL32.@)
1133 UINT WINAPI GetTempFileNameA( LPCSTR path, LPCSTR prefix, UINT unique,
1134 LPSTR buffer)
1136 UNICODE_STRING pathW, prefixW;
1137 WCHAR bufferW[MAX_PATH];
1138 UINT ret;
1140 if ( !path || !prefix || !buffer )
1142 SetLastError( ERROR_INVALID_PARAMETER );
1143 return 0;
1146 RtlCreateUnicodeStringFromAsciiz(&pathW, path);
1147 RtlCreateUnicodeStringFromAsciiz(&prefixW, prefix);
1149 ret = GetTempFileNameW(pathW.Buffer, prefixW.Buffer, unique, bufferW);
1150 if (ret)
1151 WideCharToMultiByte(CP_ACP, 0, bufferW, -1, buffer, MAX_PATH, NULL, NULL);
1153 RtlFreeUnicodeString(&pathW);
1154 RtlFreeUnicodeString(&prefixW);
1155 return ret;
1158 /***********************************************************************
1159 * GetTempFileNameW (KERNEL32.@)
1161 UINT WINAPI GetTempFileNameW( LPCWSTR path, LPCWSTR prefix, UINT unique,
1162 LPWSTR buffer )
1164 return FILE_GetTempFileName( path, prefix, unique, buffer );
1168 /***********************************************************************
1169 * GetTempFileName (KERNEL.97)
1171 UINT16 WINAPI GetTempFileName16( BYTE drive, LPCSTR prefix, UINT16 unique,
1172 LPSTR buffer )
1174 char temppath[MAX_PATH];
1175 char *prefix16 = NULL;
1176 UINT16 ret;
1178 if (!(drive & ~TF_FORCEDRIVE)) /* drive 0 means current default drive */
1179 drive |= DRIVE_GetCurrentDrive() + 'A';
1181 if ((drive & TF_FORCEDRIVE) &&
1182 !DRIVE_IsValid( toupper(drive & ~TF_FORCEDRIVE) - 'A' ))
1184 drive &= ~TF_FORCEDRIVE;
1185 WARN("invalid drive %d specified\n", drive );
1188 if (drive & TF_FORCEDRIVE)
1189 sprintf(temppath,"%c:", drive & ~TF_FORCEDRIVE );
1190 else
1191 GetTempPathA( MAX_PATH, temppath );
1193 if (prefix)
1195 prefix16 = HeapAlloc(GetProcessHeap(), 0, strlen(prefix) + 2);
1196 *prefix16 = '~';
1197 strcpy(prefix16 + 1, prefix);
1200 ret = GetTempFileNameA( temppath, prefix16, unique, buffer );
1202 if (prefix16) HeapFree(GetProcessHeap(), 0, prefix16);
1203 return ret;
1206 /***********************************************************************
1207 * FILE_DoOpenFile
1209 * Implementation of OpenFile16() and OpenFile32().
1211 static HFILE FILE_DoOpenFile( LPCSTR name, OFSTRUCT *ofs, UINT mode,
1212 BOOL win32 )
1214 HFILE hFileRet;
1215 HANDLE handle;
1216 FILETIME filetime;
1217 WORD filedatetime[2];
1218 DOS_FULL_NAME full_name;
1219 DWORD access, sharing;
1220 WCHAR *p;
1221 WCHAR buffer[MAX_PATH];
1222 LPWSTR nameW;
1224 if (!ofs) return HFILE_ERROR;
1226 TRACE("%s %s %s %s%s%s%s%s%s%s%s%s\n",name,
1227 ((mode & 0x3 )==OF_READ)?"OF_READ":
1228 ((mode & 0x3 )==OF_WRITE)?"OF_WRITE":
1229 ((mode & 0x3 )==OF_READWRITE)?"OF_READWRITE":"unknown",
1230 ((mode & 0x70 )==OF_SHARE_COMPAT)?"OF_SHARE_COMPAT":
1231 ((mode & 0x70 )==OF_SHARE_DENY_NONE)?"OF_SHARE_DENY_NONE":
1232 ((mode & 0x70 )==OF_SHARE_DENY_READ)?"OF_SHARE_DENY_READ":
1233 ((mode & 0x70 )==OF_SHARE_DENY_WRITE)?"OF_SHARE_DENY_WRITE":
1234 ((mode & 0x70 )==OF_SHARE_EXCLUSIVE)?"OF_SHARE_EXCLUSIVE":"unknown",
1235 ((mode & OF_PARSE )==OF_PARSE)?"OF_PARSE ":"",
1236 ((mode & OF_DELETE )==OF_DELETE)?"OF_DELETE ":"",
1237 ((mode & OF_VERIFY )==OF_VERIFY)?"OF_VERIFY ":"",
1238 ((mode & OF_SEARCH )==OF_SEARCH)?"OF_SEARCH ":"",
1239 ((mode & OF_CANCEL )==OF_CANCEL)?"OF_CANCEL ":"",
1240 ((mode & OF_CREATE )==OF_CREATE)?"OF_CREATE ":"",
1241 ((mode & OF_PROMPT )==OF_PROMPT)?"OF_PROMPT ":"",
1242 ((mode & OF_EXIST )==OF_EXIST)?"OF_EXIST ":"",
1243 ((mode & OF_REOPEN )==OF_REOPEN)?"OF_REOPEN ":""
1247 ofs->cBytes = sizeof(OFSTRUCT);
1248 ofs->nErrCode = 0;
1249 if (mode & OF_REOPEN) name = ofs->szPathName;
1251 if (!name) {
1252 ERR("called with `name' set to NULL ! Please debug.\n");
1253 return HFILE_ERROR;
1256 TRACE("%s %04x\n", name, mode );
1258 /* the watcom 10.6 IDE relies on a valid path returned in ofs->szPathName
1259 Are there any cases where getting the path here is wrong?
1260 Uwe Bonnes 1997 Apr 2 */
1261 if (!GetFullPathNameA( name, sizeof(ofs->szPathName),
1262 ofs->szPathName, NULL )) goto error;
1263 FILE_ConvertOFMode( mode, &access, &sharing );
1265 /* OF_PARSE simply fills the structure */
1267 if (mode & OF_PARSE)
1269 ofs->fFixedDisk = (GetDriveType16( ofs->szPathName[0]-'A' )
1270 != DRIVE_REMOVABLE);
1271 TRACE("(%s): OF_PARSE, res = '%s'\n",
1272 name, ofs->szPathName );
1273 return 0;
1276 /* OF_CREATE is completely different from all other options, so
1277 handle it first */
1279 if (mode & OF_CREATE)
1281 if ((handle = CreateFileA( name, GENERIC_READ | GENERIC_WRITE,
1282 sharing, NULL, CREATE_ALWAYS,
1283 FILE_ATTRIBUTE_NORMAL, 0 ))== INVALID_HANDLE_VALUE)
1284 goto error;
1285 goto success;
1288 MultiByteToWideChar(CP_ACP, 0, name, -1, buffer, MAX_PATH);
1289 nameW = buffer;
1291 /* If OF_SEARCH is set, ignore the given path */
1293 if ((mode & OF_SEARCH) && !(mode & OF_REOPEN))
1295 /* First try the file name as is */
1296 if (DOSFS_GetFullName( nameW, TRUE, &full_name )) goto found;
1297 /* Now remove the path */
1298 if (nameW[0] && (nameW[1] == ':')) nameW += 2;
1299 if ((p = strrchrW( nameW, '\\' ))) nameW = p + 1;
1300 if ((p = strrchrW( nameW, '/' ))) nameW = p + 1;
1301 if (!nameW[0]) goto not_found;
1304 /* Now look for the file */
1306 if (!DIR_SearchPath( NULL, nameW, NULL, &full_name, win32 )) goto not_found;
1308 found:
1309 TRACE("found %s = %s\n",
1310 full_name.long_name, debugstr_w(full_name.short_name) );
1311 WideCharToMultiByte(CP_ACP, 0, full_name.short_name, -1,
1312 ofs->szPathName, sizeof(ofs->szPathName), NULL, NULL);
1314 if (mode & OF_SHARE_EXCLUSIVE)
1315 /* Some InstallShield version uses OF_SHARE_EXCLUSIVE
1316 on the file <tempdir>/_ins0432._mp to determine how
1317 far installation has proceeded.
1318 _ins0432._mp is an executable and while running the
1319 application expects the open with OF_SHARE_ to fail*/
1320 /* Probable FIXME:
1321 As our loader closes the files after loading the executable,
1322 we can't find the running executable with FILE_InUse.
1323 The loader should keep the file open, as Windows does that, too.
1326 char *last = strrchr(full_name.long_name,'/');
1327 if (!last)
1328 last = full_name.long_name - 1;
1329 if (GetModuleHandle16(last+1))
1331 TRACE("Denying shared open for %s\n",full_name.long_name);
1332 return HFILE_ERROR;
1336 if (mode & OF_DELETE)
1338 if (unlink( full_name.long_name ) == -1) goto not_found;
1339 TRACE("(%s): OF_DELETE return = OK\n", name);
1340 return 1;
1343 handle = FILE_CreateFile( full_name.long_name, access, sharing,
1344 NULL, OPEN_EXISTING, 0, 0,
1345 DRIVE_GetFlags(full_name.drive) & DRIVE_FAIL_READ_ONLY,
1346 GetDriveTypeW( full_name.short_name ) );
1347 if (!handle) goto not_found;
1349 GetFileTime( handle, NULL, NULL, &filetime );
1350 FileTimeToDosDateTime( &filetime, &filedatetime[0], &filedatetime[1] );
1351 if ((mode & OF_VERIFY) && (mode & OF_REOPEN))
1353 if (ofs->Reserved1 != filedatetime[0] || ofs->Reserved2 != filedatetime[1] )
1355 CloseHandle( handle );
1356 WARN("(%s): OF_VERIFY failed\n", name );
1357 /* FIXME: what error here? */
1358 SetLastError( ERROR_FILE_NOT_FOUND );
1359 goto error;
1362 ofs->Reserved1 = filedatetime[0];
1363 ofs->Reserved2 = filedatetime[1];
1365 success: /* We get here if the open was successful */
1366 TRACE("(%s): OK, return = %p\n", name, handle );
1367 if (win32)
1369 hFileRet = (HFILE)handle;
1370 if (mode & OF_EXIST) /* Return the handle, but close it first */
1371 CloseHandle( handle );
1373 else
1375 hFileRet = Win32HandleToDosFileHandle( handle );
1376 if (hFileRet == HFILE_ERROR16) goto error;
1377 if (mode & OF_EXIST) /* Return the handle, but close it first */
1378 _lclose16( hFileRet );
1380 return hFileRet;
1382 not_found: /* We get here if the file does not exist */
1383 WARN("'%s' not found or sharing violation\n", name );
1384 SetLastError( ERROR_FILE_NOT_FOUND );
1385 /* fall through */
1387 error: /* We get here if there was an error opening the file */
1388 ofs->nErrCode = GetLastError();
1389 WARN("(%s): return = HFILE_ERROR error= %d\n",
1390 name,ofs->nErrCode );
1391 return HFILE_ERROR;
1395 /***********************************************************************
1396 * OpenFile (KERNEL.74)
1397 * OpenFileEx (KERNEL.360)
1399 HFILE16 WINAPI OpenFile16( LPCSTR name, OFSTRUCT *ofs, UINT16 mode )
1401 return FILE_DoOpenFile( name, ofs, mode, FALSE );
1405 /***********************************************************************
1406 * OpenFile (KERNEL32.@)
1408 HFILE WINAPI OpenFile( LPCSTR name, OFSTRUCT *ofs, UINT mode )
1410 return FILE_DoOpenFile( name, ofs, mode, TRUE );
1414 /***********************************************************************
1415 * FILE_InitProcessDosHandles
1417 * Allocates the default DOS handles for a process. Called either by
1418 * Win32HandleToDosFileHandle below or by the DOSVM stuff.
1420 static void FILE_InitProcessDosHandles( void )
1422 HANDLE cp = GetCurrentProcess();
1423 DuplicateHandle(cp, GetStdHandle(STD_INPUT_HANDLE), cp, &dos_handles[0],
1424 0, TRUE, DUPLICATE_SAME_ACCESS);
1425 DuplicateHandle(cp, GetStdHandle(STD_OUTPUT_HANDLE), cp, &dos_handles[1],
1426 0, TRUE, DUPLICATE_SAME_ACCESS);
1427 DuplicateHandle(cp, GetStdHandle(STD_ERROR_HANDLE), cp, &dos_handles[2],
1428 0, TRUE, DUPLICATE_SAME_ACCESS);
1429 DuplicateHandle(cp, GetStdHandle(STD_ERROR_HANDLE), cp, &dos_handles[3],
1430 0, TRUE, DUPLICATE_SAME_ACCESS);
1431 DuplicateHandle(cp, GetStdHandle(STD_ERROR_HANDLE), cp, &dos_handles[4],
1432 0, TRUE, DUPLICATE_SAME_ACCESS);
1435 /***********************************************************************
1436 * Win32HandleToDosFileHandle (KERNEL32.21)
1438 * Allocate a DOS handle for a Win32 handle. The Win32 handle is no
1439 * longer valid after this function (even on failure).
1441 * Note: this is not exactly right, since on Win95 the Win32 handles
1442 * are on top of DOS handles and we do it the other way
1443 * around. Should be good enough though.
1445 HFILE WINAPI Win32HandleToDosFileHandle( HANDLE handle )
1447 int i;
1449 if (!handle || (handle == INVALID_HANDLE_VALUE))
1450 return HFILE_ERROR;
1452 for (i = 5; i < DOS_TABLE_SIZE; i++)
1453 if (!dos_handles[i])
1455 dos_handles[i] = handle;
1456 TRACE("Got %d for h32 %p\n", i, handle );
1457 return (HFILE)i;
1459 CloseHandle( handle );
1460 SetLastError( ERROR_TOO_MANY_OPEN_FILES );
1461 return HFILE_ERROR;
1465 /***********************************************************************
1466 * DosFileHandleToWin32Handle (KERNEL32.20)
1468 * Return the Win32 handle for a DOS handle.
1470 * Note: this is not exactly right, since on Win95 the Win32 handles
1471 * are on top of DOS handles and we do it the other way
1472 * around. Should be good enough though.
1474 HANDLE WINAPI DosFileHandleToWin32Handle( HFILE handle )
1476 HFILE16 hfile = (HFILE16)handle;
1477 if (hfile < 5 && !dos_handles[hfile]) FILE_InitProcessDosHandles();
1478 if ((hfile >= DOS_TABLE_SIZE) || !dos_handles[hfile])
1480 SetLastError( ERROR_INVALID_HANDLE );
1481 return INVALID_HANDLE_VALUE;
1483 return dos_handles[hfile];
1487 /***********************************************************************
1488 * DisposeLZ32Handle (KERNEL32.22)
1490 * Note: this is not entirely correct, we should only close the
1491 * 32-bit handle and not the 16-bit one, but we cannot do
1492 * this because of the way our DOS handles are implemented.
1493 * It shouldn't break anything though.
1495 void WINAPI DisposeLZ32Handle( HANDLE handle )
1497 int i;
1499 if (!handle || (handle == INVALID_HANDLE_VALUE)) return;
1501 for (i = 5; i < DOS_TABLE_SIZE; i++)
1502 if (dos_handles[i] == handle)
1504 dos_handles[i] = 0;
1505 CloseHandle( handle );
1506 break;
1511 /***********************************************************************
1512 * FILE_Dup2
1514 * dup2() function for DOS handles.
1516 HFILE16 FILE_Dup2( HFILE16 hFile1, HFILE16 hFile2 )
1518 HANDLE new_handle;
1520 if (hFile1 < 5 && !dos_handles[hFile1]) FILE_InitProcessDosHandles();
1522 if ((hFile1 >= DOS_TABLE_SIZE) || (hFile2 >= DOS_TABLE_SIZE) || !dos_handles[hFile1])
1524 SetLastError( ERROR_INVALID_HANDLE );
1525 return HFILE_ERROR16;
1527 if (!DuplicateHandle( GetCurrentProcess(), dos_handles[hFile1],
1528 GetCurrentProcess(), &new_handle,
1529 0, FALSE, DUPLICATE_SAME_ACCESS ))
1530 return HFILE_ERROR16;
1531 if (dos_handles[hFile2]) CloseHandle( dos_handles[hFile2] );
1532 dos_handles[hFile2] = new_handle;
1533 return hFile2;
1537 /***********************************************************************
1538 * _lclose (KERNEL.81)
1540 HFILE16 WINAPI _lclose16( HFILE16 hFile )
1542 if ((hFile >= DOS_TABLE_SIZE) || !dos_handles[hFile])
1544 SetLastError( ERROR_INVALID_HANDLE );
1545 return HFILE_ERROR16;
1547 TRACE("%d (handle32=%p)\n", hFile, dos_handles[hFile] );
1548 CloseHandle( dos_handles[hFile] );
1549 dos_handles[hFile] = 0;
1550 return 0;
1554 /***********************************************************************
1555 * _lclose (KERNEL32.@)
1557 HFILE WINAPI _lclose( HFILE hFile )
1559 TRACE("handle %d\n", hFile );
1560 return CloseHandle( (HANDLE)hFile ) ? 0 : HFILE_ERROR;
1563 /***********************************************************************
1564 * GetOverlappedResult (KERNEL32.@)
1566 * Check the result of an Asynchronous data transfer from a file.
1568 * RETURNS
1569 * TRUE on success
1570 * FALSE on failure
1572 * If successful (and relevant) lpTransferred will hold the number of
1573 * bytes transferred during the async operation.
1575 * BUGS
1577 * Currently only works for WaitCommEvent, ReadFile, WriteFile
1578 * with communications ports.
1581 BOOL WINAPI GetOverlappedResult(
1582 HANDLE hFile, /* [in] handle of file to check on */
1583 LPOVERLAPPED lpOverlapped, /* [in/out] pointer to overlapped */
1584 LPDWORD lpTransferred, /* [in/out] number of bytes transferred */
1585 BOOL bWait /* [in] wait for the transfer to complete ? */
1587 DWORD r;
1589 TRACE("(%p %p %p %x)\n", hFile, lpOverlapped, lpTransferred, bWait);
1591 if(lpOverlapped==NULL)
1593 ERR("lpOverlapped was null\n");
1594 return FALSE;
1596 if(!lpOverlapped->hEvent)
1598 ERR("lpOverlapped->hEvent was null\n");
1599 return FALSE;
1602 if ( bWait )
1604 do {
1605 TRACE("waiting on %p\n",lpOverlapped);
1606 r = WaitForSingleObjectEx(lpOverlapped->hEvent, INFINITE, TRUE);
1607 TRACE("wait on %p returned %ld\n",lpOverlapped,r);
1608 } while (r==STATUS_USER_APC);
1610 else if ( lpOverlapped->Internal == STATUS_PENDING )
1612 /* Wait in order to give APCs a chance to run. */
1613 /* This is cheating, so we must set the event again in case of success -
1614 it may be a non-manual reset event. */
1615 do {
1616 TRACE("waiting on %p\n",lpOverlapped);
1617 r = WaitForSingleObjectEx(lpOverlapped->hEvent, 0, TRUE);
1618 TRACE("wait on %p returned %ld\n",lpOverlapped,r);
1619 } while (r==STATUS_USER_APC);
1620 if ( r == WAIT_OBJECT_0 )
1621 NtSetEvent ( lpOverlapped->hEvent, NULL );
1624 if(lpTransferred)
1625 *lpTransferred = lpOverlapped->InternalHigh;
1627 switch ( lpOverlapped->Internal )
1629 case STATUS_SUCCESS:
1630 return TRUE;
1631 case STATUS_PENDING:
1632 SetLastError ( ERROR_IO_INCOMPLETE );
1633 if ( bWait ) ERR ("PENDING status after waiting!\n");
1634 return FALSE;
1635 default:
1636 SetLastError ( RtlNtStatusToDosError ( lpOverlapped->Internal ) );
1637 return FALSE;
1641 /***********************************************************************
1642 * CancelIo (KERNEL32.@)
1644 BOOL WINAPI CancelIo(HANDLE handle)
1646 async_private *ovp,*t;
1648 TRACE("handle = %p\n",handle);
1650 for (ovp = NtCurrentTeb()->pending_list; ovp; ovp = t)
1652 t = ovp->next;
1653 if ( ovp->handle == handle )
1654 cancel_async ( ovp );
1656 WaitForMultipleObjectsEx(0,NULL,FALSE,1,TRUE);
1657 return TRUE;
1660 /***********************************************************************
1661 * FILE_AsyncReadService (INTERNAL)
1663 * This function is called while the client is waiting on the
1664 * server, so we can't make any server calls here.
1666 static void FILE_AsyncReadService(async_private *ovp)
1668 async_fileio *fileio = (async_fileio*) ovp;
1669 LPOVERLAPPED lpOverlapped = fileio->lpOverlapped;
1670 int result, r;
1671 int already = lpOverlapped->InternalHigh;
1673 TRACE("%p %p\n", lpOverlapped, fileio->buffer );
1675 /* check to see if the data is ready (non-blocking) */
1677 if ( fileio->fd_type == FD_TYPE_SOCKET )
1678 result = read (ovp->fd, &fileio->buffer[already], fileio->count - already);
1679 else
1681 result = pread (ovp->fd, &fileio->buffer[already], fileio->count - already,
1682 OVERLAPPED_OFFSET (lpOverlapped) + already);
1683 if ((result < 0) && (errno == ESPIPE))
1684 result = read (ovp->fd, &fileio->buffer[already], fileio->count - already);
1687 if ( (result<0) && ((errno == EAGAIN) || (errno == EINTR)))
1689 TRACE("Deferred read %d\n",errno);
1690 r = STATUS_PENDING;
1691 goto async_end;
1694 /* check to see if the transfer is complete */
1695 if(result<0)
1697 r = FILE_GetNtStatus ();
1698 goto async_end;
1700 else if ( result == 0 )
1702 r = ( lpOverlapped->InternalHigh ? STATUS_SUCCESS : STATUS_END_OF_FILE );
1703 goto async_end;
1706 lpOverlapped->InternalHigh += result;
1707 TRACE("read %d more bytes %ld/%d so far\n",result,lpOverlapped->InternalHigh,fileio->count);
1709 if(lpOverlapped->InternalHigh >= fileio->count || fileio->fd_type == FD_TYPE_SOCKET )
1710 r = STATUS_SUCCESS;
1711 else
1712 r = STATUS_PENDING;
1714 async_end:
1715 lpOverlapped->Internal = r;
1718 /***********************************************************************
1719 * FILE_ReadFileEx (INTERNAL)
1721 static BOOL FILE_ReadFileEx(HANDLE hFile, LPVOID buffer, DWORD bytesToRead,
1722 LPOVERLAPPED overlapped,
1723 LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine,
1724 HANDLE hEvent)
1726 async_fileio *ovp;
1727 int fd;
1728 int flags;
1729 enum fd_type type;
1731 TRACE("file %p to buf %p num %ld %p func %p\n",
1732 hFile, buffer, bytesToRead, overlapped, lpCompletionRoutine);
1734 /* check that there is an overlapped struct */
1735 if (overlapped==NULL)
1737 SetLastError(ERROR_INVALID_PARAMETER);
1738 return FALSE;
1741 fd = FILE_GetUnixHandleType ( hFile, GENERIC_READ, &type, &flags);
1742 if ( fd < 0 )
1744 WARN ( "Couldn't get FD\n" );
1745 return FALSE;
1748 ovp = (async_fileio*) HeapAlloc(GetProcessHeap(), 0, sizeof (async_fileio));
1749 if(!ovp)
1751 TRACE("HeapAlloc Failed\n");
1752 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1753 goto error;
1756 ovp->async.ops = ( lpCompletionRoutine ? &fileio_async_ops : &fileio_nocomp_async_ops );
1757 ovp->async.handle = hFile;
1758 ovp->async.fd = fd;
1759 ovp->async.type = ASYNC_TYPE_READ;
1760 ovp->async.func = FILE_AsyncReadService;
1761 ovp->async.event = hEvent;
1762 ovp->lpOverlapped = overlapped;
1763 ovp->count = bytesToRead;
1764 ovp->completion_func = lpCompletionRoutine;
1765 ovp->buffer = buffer;
1766 ovp->fd_type = type;
1768 return !register_new_async (&ovp->async);
1770 error:
1771 close (fd);
1772 return FALSE;
1776 /***********************************************************************
1777 * ReadFileEx (KERNEL32.@)
1779 BOOL WINAPI ReadFileEx(HANDLE hFile, LPVOID buffer, DWORD bytesToRead,
1780 LPOVERLAPPED overlapped,
1781 LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine)
1783 overlapped->InternalHigh = 0;
1784 return FILE_ReadFileEx(hFile,buffer,bytesToRead,overlapped,lpCompletionRoutine, INVALID_HANDLE_VALUE);
1787 static BOOL FILE_TimeoutRead(HANDLE hFile, LPVOID buffer, DWORD bytesToRead, LPDWORD bytesRead)
1789 OVERLAPPED ov;
1790 BOOL r = FALSE;
1792 TRACE("%p %p %ld %p\n", hFile, buffer, bytesToRead, bytesRead );
1794 ZeroMemory(&ov, sizeof (OVERLAPPED));
1795 if(STATUS_SUCCESS==NtCreateEvent(&ov.hEvent, SYNCHRONIZE, NULL, 0, 0))
1797 if(FILE_ReadFileEx(hFile, buffer, bytesToRead, &ov, NULL, ov.hEvent))
1799 r = GetOverlappedResult(hFile, &ov, bytesRead, TRUE);
1802 CloseHandle(ov.hEvent);
1803 return r;
1806 /***********************************************************************
1807 * ReadFile (KERNEL32.@)
1809 BOOL WINAPI ReadFile( HANDLE hFile, LPVOID buffer, DWORD bytesToRead,
1810 LPDWORD bytesRead, LPOVERLAPPED overlapped )
1812 int unix_handle, result, flags;
1813 enum fd_type type;
1815 TRACE("%p %p %ld %p %p\n", hFile, buffer, bytesToRead,
1816 bytesRead, overlapped );
1818 if (bytesRead) *bytesRead = 0; /* Do this before anything else */
1819 if (!bytesToRead) return TRUE;
1821 unix_handle = FILE_GetUnixHandleType( hFile, GENERIC_READ, &type, &flags );
1823 if (flags & FD_FLAG_OVERLAPPED)
1825 if (unix_handle == -1) return FALSE;
1826 if ( (overlapped==NULL) || NtResetEvent( overlapped->hEvent, NULL ) )
1828 TRACE("Overlapped not specified or invalid event flag\n");
1829 close(unix_handle);
1830 SetLastError(ERROR_INVALID_PARAMETER);
1831 return FALSE;
1834 close(unix_handle);
1835 overlapped->InternalHigh = 0;
1837 if(!FILE_ReadFileEx(hFile, buffer, bytesToRead, overlapped, NULL, overlapped->hEvent))
1838 return FALSE;
1840 if ( !GetOverlappedResult (hFile, overlapped, bytesRead, FALSE) )
1842 if ( GetLastError() == ERROR_IO_INCOMPLETE )
1843 SetLastError ( ERROR_IO_PENDING );
1844 return FALSE;
1847 return TRUE;
1849 if (flags & FD_FLAG_TIMEOUT)
1851 close(unix_handle);
1852 return FILE_TimeoutRead(hFile, buffer, bytesToRead, bytesRead);
1854 switch(type)
1856 case FD_TYPE_SMB:
1857 return SMB_ReadFile(hFile, buffer, bytesToRead, bytesRead, NULL);
1859 case FD_TYPE_CONSOLE:
1860 return FILE_ReadConsole(hFile, buffer, bytesToRead, bytesRead, NULL);
1862 case FD_TYPE_DEFAULT:
1863 /* normal unix files */
1864 if (unix_handle == -1) return FALSE;
1865 if (overlapped)
1867 DWORD highOffset = overlapped->OffsetHigh;
1868 if ( (INVALID_SET_FILE_POINTER == SetFilePointer(hFile, overlapped->Offset,
1869 &highOffset, FILE_BEGIN)) &&
1870 (GetLastError() != NO_ERROR) )
1872 close(unix_handle);
1873 return FALSE;
1876 break;
1878 default:
1879 if (unix_handle == -1)
1880 return FALSE;
1883 if(overlapped)
1885 off_t offset = OVERLAPPED_OFFSET(overlapped);
1886 if(lseek(unix_handle, offset, SEEK_SET) == -1)
1888 close(unix_handle);
1889 SetLastError(ERROR_INVALID_PARAMETER);
1890 return FALSE;
1894 /* code for synchronous reads */
1895 while ((result = read( unix_handle, buffer, bytesToRead )) == -1)
1897 if ((errno == EAGAIN) || (errno == EINTR)) continue;
1898 if ((errno == EFAULT) && !IsBadWritePtr( buffer, bytesToRead )) continue;
1899 FILE_SetDosError();
1900 break;
1902 close( unix_handle );
1903 if (result == -1) return FALSE;
1904 if (bytesRead) *bytesRead = result;
1905 return TRUE;
1909 /***********************************************************************
1910 * FILE_AsyncWriteService (INTERNAL)
1912 * This function is called while the client is waiting on the
1913 * server, so we can't make any server calls here.
1915 static void FILE_AsyncWriteService(struct async_private *ovp)
1917 async_fileio *fileio = (async_fileio *) ovp;
1918 LPOVERLAPPED lpOverlapped = fileio->lpOverlapped;
1919 int result, r;
1920 int already = lpOverlapped->InternalHigh;
1922 TRACE("(%p %p)\n",lpOverlapped,fileio->buffer);
1924 /* write some data (non-blocking) */
1926 if ( fileio->fd_type == FD_TYPE_SOCKET )
1927 result = write(ovp->fd, &fileio->buffer[already], fileio->count - already);
1928 else
1930 result = pwrite(ovp->fd, &fileio->buffer[already], fileio->count - already,
1931 OVERLAPPED_OFFSET (lpOverlapped) + already);
1932 if ((result < 0) && (errno == ESPIPE))
1933 result = write(ovp->fd, &fileio->buffer[already], fileio->count - already);
1936 if ( (result<0) && ((errno == EAGAIN) || (errno == EINTR)))
1938 r = STATUS_PENDING;
1939 goto async_end;
1942 /* check to see if the transfer is complete */
1943 if(result<0)
1945 r = FILE_GetNtStatus ();
1946 goto async_end;
1949 lpOverlapped->InternalHigh += result;
1951 TRACE("wrote %d more bytes %ld/%d so far\n",result,lpOverlapped->InternalHigh,fileio->count);
1953 if(lpOverlapped->InternalHigh < fileio->count)
1954 r = STATUS_PENDING;
1955 else
1956 r = STATUS_SUCCESS;
1958 async_end:
1959 lpOverlapped->Internal = r;
1962 /***********************************************************************
1963 * FILE_WriteFileEx
1965 static BOOL FILE_WriteFileEx(HANDLE hFile, LPCVOID buffer, DWORD bytesToWrite,
1966 LPOVERLAPPED overlapped,
1967 LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine,
1968 HANDLE hEvent)
1970 async_fileio *ovp;
1971 int fd;
1972 int flags;
1973 enum fd_type type;
1975 TRACE("file %p to buf %p num %ld %p func %p handle %p\n",
1976 hFile, buffer, bytesToWrite, overlapped, lpCompletionRoutine, hEvent);
1978 if (overlapped == NULL)
1980 SetLastError(ERROR_INVALID_PARAMETER);
1981 return FALSE;
1984 fd = FILE_GetUnixHandleType ( hFile, GENERIC_WRITE, &type, &flags );
1985 if ( fd < 0 )
1987 TRACE( "Couldn't get FD\n" );
1988 return FALSE;
1991 ovp = (async_fileio*) HeapAlloc(GetProcessHeap(), 0, sizeof (async_fileio));
1992 if(!ovp)
1994 TRACE("HeapAlloc Failed\n");
1995 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1996 goto error;
1999 ovp->async.ops = ( lpCompletionRoutine ? &fileio_async_ops : &fileio_nocomp_async_ops );
2000 ovp->async.handle = hFile;
2001 ovp->async.fd = fd;
2002 ovp->async.type = ASYNC_TYPE_WRITE;
2003 ovp->async.func = FILE_AsyncWriteService;
2004 ovp->lpOverlapped = overlapped;
2005 ovp->async.event = hEvent;
2006 ovp->buffer = (LPVOID) buffer;
2007 ovp->count = bytesToWrite;
2008 ovp->completion_func = lpCompletionRoutine;
2009 ovp->fd_type = type;
2011 return !register_new_async (&ovp->async);
2013 error:
2014 close (fd);
2015 return FALSE;
2018 /***********************************************************************
2019 * WriteFileEx (KERNEL32.@)
2021 BOOL WINAPI WriteFileEx(HANDLE hFile, LPCVOID buffer, DWORD bytesToWrite,
2022 LPOVERLAPPED overlapped,
2023 LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine)
2025 overlapped->InternalHigh = 0;
2027 return FILE_WriteFileEx(hFile, buffer, bytesToWrite, overlapped, lpCompletionRoutine, INVALID_HANDLE_VALUE);
2030 /***********************************************************************
2031 * WriteFile (KERNEL32.@)
2033 BOOL WINAPI WriteFile( HANDLE hFile, LPCVOID buffer, DWORD bytesToWrite,
2034 LPDWORD bytesWritten, LPOVERLAPPED overlapped )
2036 int unix_handle, result, flags;
2037 enum fd_type type;
2039 TRACE("%p %p %ld %p %p\n", hFile, buffer, bytesToWrite,
2040 bytesWritten, overlapped );
2042 if (bytesWritten) *bytesWritten = 0; /* Do this before anything else */
2043 if (!bytesToWrite) return TRUE;
2045 unix_handle = FILE_GetUnixHandleType( hFile, GENERIC_WRITE, &type, &flags );
2047 if (flags & FD_FLAG_OVERLAPPED)
2049 if (unix_handle == -1) return FALSE;
2050 if ( (overlapped==NULL) || NtResetEvent( overlapped->hEvent, NULL ) )
2052 TRACE("Overlapped not specified or invalid event flag\n");
2053 close(unix_handle);
2054 SetLastError(ERROR_INVALID_PARAMETER);
2055 return FALSE;
2058 close(unix_handle);
2059 overlapped->InternalHigh = 0;
2061 if(!FILE_WriteFileEx(hFile, buffer, bytesToWrite, overlapped, NULL, overlapped->hEvent))
2062 return FALSE;
2064 if ( !GetOverlappedResult (hFile, overlapped, bytesWritten, FALSE) )
2066 if ( GetLastError() == ERROR_IO_INCOMPLETE )
2067 SetLastError ( ERROR_IO_PENDING );
2068 return FALSE;
2071 return TRUE;
2074 switch(type)
2076 case FD_TYPE_CONSOLE:
2077 TRACE("%p %s %ld %p %p\n", hFile, debugstr_an(buffer, bytesToWrite), bytesToWrite,
2078 bytesWritten, overlapped );
2079 return FILE_WriteConsole(hFile, buffer, bytesToWrite, bytesWritten, NULL);
2081 case FD_TYPE_DEFAULT:
2082 if (unix_handle == -1) return FALSE;
2084 if(overlapped)
2086 DWORD highOffset = overlapped->OffsetHigh;
2087 if ( (INVALID_SET_FILE_POINTER == SetFilePointer(hFile, overlapped->Offset,
2088 &highOffset, FILE_BEGIN)) &&
2089 (GetLastError() != NO_ERROR) )
2091 close(unix_handle);
2092 return FALSE;
2095 break;
2097 default:
2098 if (unix_handle == -1)
2099 return FALSE;
2100 if (overlapped)
2102 close(unix_handle);
2103 SetLastError(ERROR_INVALID_PARAMETER);
2104 return FALSE;
2106 break;
2109 if(overlapped)
2111 off_t offset = OVERLAPPED_OFFSET(overlapped);
2112 if(lseek(unix_handle, offset, SEEK_SET) == -1)
2114 close(unix_handle);
2115 SetLastError(ERROR_INVALID_PARAMETER);
2116 return FALSE;
2120 /* synchronous file write */
2121 while ((result = write( unix_handle, buffer, bytesToWrite )) == -1)
2123 if ((errno == EAGAIN) || (errno == EINTR)) continue;
2124 if ((errno == EFAULT) && !IsBadReadPtr( buffer, bytesToWrite )) continue;
2125 if (errno == ENOSPC)
2126 SetLastError( ERROR_DISK_FULL );
2127 else
2128 FILE_SetDosError();
2129 break;
2131 close( unix_handle );
2132 if (result == -1) return FALSE;
2133 if (bytesWritten) *bytesWritten = result;
2134 return TRUE;
2138 /***********************************************************************
2139 * _hread (KERNEL.349)
2141 LONG WINAPI WIN16_hread( HFILE16 hFile, SEGPTR buffer, LONG count )
2143 LONG maxlen;
2145 TRACE("%d %08lx %ld\n",
2146 hFile, (DWORD)buffer, count );
2148 /* Some programs pass a count larger than the allocated buffer */
2149 maxlen = GetSelectorLimit16( SELECTOROF(buffer) ) - OFFSETOF(buffer) + 1;
2150 if (count > maxlen) count = maxlen;
2151 return _lread((HFILE)DosFileHandleToWin32Handle(hFile), MapSL(buffer), count );
2155 /***********************************************************************
2156 * _lread (KERNEL.82)
2158 UINT16 WINAPI WIN16_lread( HFILE16 hFile, SEGPTR buffer, UINT16 count )
2160 return (UINT16)WIN16_hread( hFile, buffer, (LONG)count );
2164 /***********************************************************************
2165 * _lread (KERNEL32.@)
2167 UINT WINAPI _lread( HFILE handle, LPVOID buffer, UINT count )
2169 DWORD result;
2170 if (!ReadFile( (HANDLE)handle, buffer, count, &result, NULL )) return -1;
2171 return result;
2175 /***********************************************************************
2176 * _lread16 (KERNEL.82)
2178 UINT16 WINAPI _lread16( HFILE16 hFile, LPVOID buffer, UINT16 count )
2180 return (UINT16)_lread((HFILE)DosFileHandleToWin32Handle(hFile), buffer, (LONG)count );
2184 /***********************************************************************
2185 * _lcreat (KERNEL.83)
2187 HFILE16 WINAPI _lcreat16( LPCSTR path, INT16 attr )
2189 return Win32HandleToDosFileHandle( (HANDLE)_lcreat( path, attr ) );
2193 /***********************************************************************
2194 * _lcreat (KERNEL32.@)
2196 HFILE WINAPI _lcreat( LPCSTR path, INT attr )
2198 /* Mask off all flags not explicitly allowed by the doc */
2199 attr &= FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM;
2200 TRACE("%s %02x\n", path, attr );
2201 return (HFILE)CreateFileA( path, GENERIC_READ | GENERIC_WRITE,
2202 FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
2203 CREATE_ALWAYS, attr, 0 );
2207 /***********************************************************************
2208 * SetFilePointer (KERNEL32.@)
2210 DWORD WINAPI SetFilePointer( HANDLE hFile, LONG distance, LONG *highword,
2211 DWORD method )
2213 DWORD ret = INVALID_SET_FILE_POINTER;
2215 TRACE("handle %p offset %ld high %ld origin %ld\n",
2216 hFile, distance, highword?*highword:0, method );
2218 SERVER_START_REQ( set_file_pointer )
2220 req->handle = hFile;
2221 req->low = distance;
2222 req->high = highword ? *highword : (distance >= 0) ? 0 : -1;
2223 /* FIXME: assumes 1:1 mapping between Windows and Unix seek constants */
2224 req->whence = method;
2225 SetLastError( 0 );
2226 if (!wine_server_call_err( req ))
2228 ret = reply->new_low;
2229 if (highword) *highword = reply->new_high;
2232 SERVER_END_REQ;
2233 return ret;
2237 /***********************************************************************
2238 * _llseek (KERNEL.84)
2240 * FIXME:
2241 * Seeking before the start of the file should be allowed for _llseek16,
2242 * but cause subsequent I/O operations to fail (cf. interrupt list)
2245 LONG WINAPI _llseek16( HFILE16 hFile, LONG lOffset, INT16 nOrigin )
2247 return SetFilePointer( DosFileHandleToWin32Handle(hFile), lOffset, NULL, nOrigin );
2251 /***********************************************************************
2252 * _llseek (KERNEL32.@)
2254 LONG WINAPI _llseek( HFILE hFile, LONG lOffset, INT nOrigin )
2256 return SetFilePointer( (HANDLE)hFile, lOffset, NULL, nOrigin );
2260 /***********************************************************************
2261 * _lopen (KERNEL.85)
2263 HFILE16 WINAPI _lopen16( LPCSTR path, INT16 mode )
2265 return Win32HandleToDosFileHandle( (HANDLE)_lopen( path, mode ) );
2269 /***********************************************************************
2270 * _lopen (KERNEL32.@)
2272 HFILE WINAPI _lopen( LPCSTR path, INT mode )
2274 DWORD access, sharing;
2276 TRACE("('%s',%04x)\n", path, mode );
2277 FILE_ConvertOFMode( mode, &access, &sharing );
2278 return (HFILE)CreateFileA( path, access, sharing, NULL, OPEN_EXISTING, 0, 0 );
2282 /***********************************************************************
2283 * _lwrite (KERNEL.86)
2285 UINT16 WINAPI _lwrite16( HFILE16 hFile, LPCSTR buffer, UINT16 count )
2287 return (UINT16)_hwrite( (HFILE)DosFileHandleToWin32Handle(hFile), buffer, (LONG)count );
2290 /***********************************************************************
2291 * _lwrite (KERNEL32.@)
2293 UINT WINAPI _lwrite( HFILE hFile, LPCSTR buffer, UINT count )
2295 return (UINT)_hwrite( hFile, buffer, (LONG)count );
2299 /***********************************************************************
2300 * _hread16 (KERNEL.349)
2302 LONG WINAPI _hread16( HFILE16 hFile, LPVOID buffer, LONG count)
2304 return _lread( (HFILE)DosFileHandleToWin32Handle(hFile), buffer, count );
2308 /***********************************************************************
2309 * _hread (KERNEL32.@)
2311 LONG WINAPI _hread( HFILE hFile, LPVOID buffer, LONG count)
2313 return _lread( hFile, buffer, count );
2317 /***********************************************************************
2318 * _hwrite (KERNEL.350)
2320 LONG WINAPI _hwrite16( HFILE16 hFile, LPCSTR buffer, LONG count )
2322 return _hwrite( (HFILE)DosFileHandleToWin32Handle(hFile), buffer, count );
2326 /***********************************************************************
2327 * _hwrite (KERNEL32.@)
2329 * experimentation yields that _lwrite:
2330 * o truncates the file at the current position with
2331 * a 0 len write
2332 * o returns 0 on a 0 length write
2333 * o works with console handles
2336 LONG WINAPI _hwrite( HFILE handle, LPCSTR buffer, LONG count )
2338 DWORD result;
2340 TRACE("%d %p %ld\n", handle, buffer, count );
2342 if (!count)
2344 /* Expand or truncate at current position */
2345 if (!SetEndOfFile( (HANDLE)handle )) return HFILE_ERROR;
2346 return 0;
2348 if (!WriteFile( (HANDLE)handle, buffer, count, &result, NULL ))
2349 return HFILE_ERROR;
2350 return result;
2354 /***********************************************************************
2355 * SetHandleCount (KERNEL.199)
2357 UINT16 WINAPI SetHandleCount16( UINT16 count )
2359 return SetHandleCount( count );
2363 /*************************************************************************
2364 * SetHandleCount (KERNEL32.@)
2366 UINT WINAPI SetHandleCount( UINT count )
2368 return min( 256, count );
2372 /***********************************************************************
2373 * FlushFileBuffers (KERNEL32.@)
2375 BOOL WINAPI FlushFileBuffers( HANDLE hFile )
2377 BOOL ret;
2378 SERVER_START_REQ( flush_file )
2380 req->handle = hFile;
2381 ret = !wine_server_call_err( req );
2383 SERVER_END_REQ;
2384 return ret;
2388 /**************************************************************************
2389 * SetEndOfFile (KERNEL32.@)
2391 BOOL WINAPI SetEndOfFile( HANDLE hFile )
2393 BOOL ret;
2394 SERVER_START_REQ( truncate_file )
2396 req->handle = hFile;
2397 ret = !wine_server_call_err( req );
2399 SERVER_END_REQ;
2400 return ret;
2404 /***********************************************************************
2405 * DeleteFile (KERNEL.146)
2407 BOOL16 WINAPI DeleteFile16( LPCSTR path )
2409 return DeleteFileA( path );
2413 /***********************************************************************
2414 * DeleteFileW (KERNEL32.@)
2416 BOOL WINAPI DeleteFileW( LPCWSTR path )
2418 DOS_FULL_NAME full_name;
2419 HANDLE hFile;
2421 TRACE("%s\n", debugstr_w(path) );
2422 if (!path || !*path)
2424 SetLastError(ERROR_PATH_NOT_FOUND);
2425 return FALSE;
2427 if (DOSFS_GetDevice( path ))
2429 WARN("cannot remove DOS device %s!\n", debugstr_w(path));
2430 SetLastError( ERROR_FILE_NOT_FOUND );
2431 return FALSE;
2434 if (!DOSFS_GetFullName( path, TRUE, &full_name )) return FALSE;
2436 /* check if we are allowed to delete the source */
2437 hFile = FILE_CreateFile( full_name.long_name, GENERIC_READ|GENERIC_WRITE, 0,
2438 NULL, OPEN_EXISTING, 0, 0, TRUE,
2439 GetDriveTypeW( full_name.short_name ) );
2440 if (!hFile) return FALSE;
2442 if (unlink( full_name.long_name ) == -1)
2444 FILE_SetDosError();
2445 CloseHandle(hFile);
2446 return FALSE;
2448 CloseHandle(hFile);
2449 return TRUE;
2453 /***********************************************************************
2454 * DeleteFileA (KERNEL32.@)
2456 BOOL WINAPI DeleteFileA( LPCSTR path )
2458 UNICODE_STRING pathW;
2459 BOOL ret = FALSE;
2461 if (!path)
2463 SetLastError(ERROR_INVALID_PARAMETER);
2464 return FALSE;
2467 if (RtlCreateUnicodeStringFromAsciiz(&pathW, path))
2469 ret = DeleteFileW(pathW.Buffer);
2470 RtlFreeUnicodeString(&pathW);
2472 else
2473 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
2474 return ret;
2478 /***********************************************************************
2479 * GetFileType (KERNEL32.@)
2481 DWORD WINAPI GetFileType( HANDLE hFile )
2483 DWORD ret = FILE_TYPE_UNKNOWN;
2484 SERVER_START_REQ( get_file_info )
2486 req->handle = hFile;
2487 if (!wine_server_call_err( req )) ret = reply->type;
2489 SERVER_END_REQ;
2490 return ret;
2494 /* check if a file name is for an executable file (.exe or .com) */
2495 inline static BOOL is_executable( const char *name )
2497 int len = strlen(name);
2499 if (len < 4) return FALSE;
2500 return (!strcasecmp( name + len - 4, ".exe" ) ||
2501 !strcasecmp( name + len - 4, ".com" ));
2505 /***********************************************************************
2506 * FILE_AddBootRenameEntry
2508 * Adds an entry to the registry that is loaded when windows boots and
2509 * checks if there are some files to be removed or renamed/moved.
2510 * <fn1> has to be valid and <fn2> may be NULL. If both pointers are
2511 * non-NULL then the file is moved, otherwise it is deleted. The
2512 * entry of the registrykey is always appended with two zero
2513 * terminated strings. If <fn2> is NULL then the second entry is
2514 * simply a single 0-byte. Otherwise the second filename goes
2515 * there. The entries are prepended with \??\ before the path and the
2516 * second filename gets also a '!' as the first character if
2517 * MOVEFILE_REPLACE_EXISTING is set. After the final string another
2518 * 0-byte follows to indicate the end of the strings.
2519 * i.e.:
2520 * \??\D:\test\file1[0]
2521 * !\??\D:\test\file1_renamed[0]
2522 * \??\D:\Test|delete[0]
2523 * [0] <- file is to be deleted, second string empty
2524 * \??\D:\test\file2[0]
2525 * !\??\D:\test\file2_renamed[0]
2526 * [0] <- indicates end of strings
2528 * or:
2529 * \??\D:\test\file1[0]
2530 * !\??\D:\test\file1_renamed[0]
2531 * \??\D:\Test|delete[0]
2532 * [0] <- file is to be deleted, second string empty
2533 * [0] <- indicates end of strings
2536 static BOOL FILE_AddBootRenameEntry( LPCWSTR fn1, LPCWSTR fn2, DWORD flags )
2538 static const WCHAR PreString[] = {'\\','?','?','\\',0};
2539 static const WCHAR ValueName[] = {'P','e','n','d','i','n','g',
2540 'F','i','l','e','R','e','n','a','m','e',
2541 'O','p','e','r','a','t','i','o','n','s',0};
2542 static const WCHAR SessionW[] = {'M','a','c','h','i','n','e','\\',
2543 'S','y','s','t','e','m','\\',
2544 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
2545 'C','o','n','t','r','o','l','\\',
2546 'S','e','s','s','i','o','n',' ','M','a','n','a','g','e','r',0};
2547 static const int info_size = FIELD_OFFSET( KEY_VALUE_PARTIAL_INFORMATION, Data );
2549 OBJECT_ATTRIBUTES attr;
2550 UNICODE_STRING nameW;
2551 KEY_VALUE_PARTIAL_INFORMATION *info;
2552 BOOL rc = FALSE;
2553 HKEY Reboot = 0;
2554 DWORD len0, len1, len2;
2555 DWORD DataSize = 0;
2556 BYTE *Buffer = NULL;
2557 WCHAR *p;
2559 attr.Length = sizeof(attr);
2560 attr.RootDirectory = 0;
2561 attr.ObjectName = &nameW;
2562 attr.Attributes = 0;
2563 attr.SecurityDescriptor = NULL;
2564 attr.SecurityQualityOfService = NULL;
2565 RtlInitUnicodeString( &nameW, SessionW );
2567 if (NtCreateKey( &Reboot, KEY_ALL_ACCESS, &attr, 0, NULL, 0, NULL ) != STATUS_SUCCESS)
2569 WARN("Error creating key for reboot managment [%s]\n",
2570 "SYSTEM\\CurrentControlSet\\Control\\Session Manager");
2571 return FALSE;
2574 len0 = strlenW(PreString);
2575 len1 = strlenW(fn1) + len0 + 1;
2576 if (fn2)
2578 len2 = strlenW(fn2) + len0 + 1;
2579 if (flags & MOVEFILE_REPLACE_EXISTING) len2++; /* Plus 1 because of the leading '!' */
2581 else len2 = 1; /* minimum is the 0 characters for the empty second string */
2583 /* convert characters to bytes */
2584 len0 *= sizeof(WCHAR);
2585 len1 *= sizeof(WCHAR);
2586 len2 *= sizeof(WCHAR);
2588 RtlInitUnicodeString( &nameW, ValueName );
2590 /* First we check if the key exists and if so how many bytes it already contains. */
2591 if (NtQueryValueKey( Reboot, &nameW, KeyValuePartialInformation,
2592 NULL, 0, &DataSize ) == STATUS_BUFFER_OVERFLOW)
2594 if (!(Buffer = HeapAlloc( GetProcessHeap(), 0, DataSize + len1 + len2 + sizeof(WCHAR) )))
2595 goto Quit;
2596 if (NtQueryValueKey( Reboot, &nameW, KeyValuePartialInformation,
2597 Buffer, DataSize, &DataSize )) goto Quit;
2598 info = (KEY_VALUE_PARTIAL_INFORMATION *)Buffer;
2599 if (info->Type != REG_MULTI_SZ) goto Quit;
2600 if (DataSize > sizeof(info)) DataSize -= sizeof(WCHAR); /* remove terminating null (will be added back later) */
2602 else
2604 DataSize = info_size;
2605 if (!(Buffer = HeapAlloc( GetProcessHeap(), 0, DataSize + len1 + len2 + sizeof(WCHAR) )))
2606 goto Quit;
2609 p = (WCHAR *)(Buffer + DataSize);
2610 strcpyW( p, PreString );
2611 strcatW( p, fn1 );
2612 DataSize += len1;
2613 if (fn2)
2615 p = (WCHAR *)(Buffer + DataSize);
2616 if (flags & MOVEFILE_REPLACE_EXISTING)
2617 *p++ = '!';
2618 strcpyW( p, PreString );
2619 strcatW( p, fn2 );
2620 DataSize += len2;
2622 else
2624 p = (WCHAR *)(Buffer + DataSize);
2625 *p = 0;
2626 DataSize += sizeof(WCHAR);
2629 /* add final null */
2630 p = (WCHAR *)(Buffer + DataSize);
2631 *p = 0;
2632 DataSize += sizeof(WCHAR);
2634 rc = !NtSetValueKey(Reboot, &nameW, 0, REG_MULTI_SZ, Buffer + info_size, DataSize - info_size);
2636 Quit:
2637 if (Reboot) NtClose(Reboot);
2638 if (Buffer) HeapFree( GetProcessHeap(), 0, Buffer );
2639 return(rc);
2643 /**************************************************************************
2644 * MoveFileExW (KERNEL32.@)
2646 BOOL WINAPI MoveFileExW( LPCWSTR fn1, LPCWSTR fn2, DWORD flag )
2648 DOS_FULL_NAME full_name1, full_name2;
2649 HANDLE hFile;
2650 DWORD attr = INVALID_FILE_ATTRIBUTES;
2652 TRACE("(%s,%s,%04lx)\n", debugstr_w(fn1), debugstr_w(fn2), flag);
2654 /* FIXME: <Gerhard W. Gruber>sparhawk@gmx.at
2655 In case of W9x and lesser this function should return 120 (ERROR_CALL_NOT_IMPLEMENTED)
2656 to be really compatible. Most programs wont have any problems though. In case
2657 you encounter one, this is what you should return here. I don't know what's up
2658 with NT 3.5. Is this function available there or not?
2659 Does anybody really care about 3.5? :)
2662 /* Filename1 has to be always set to a valid path. Filename2 may be NULL
2663 if the source file has to be deleted.
2665 if (!fn1) {
2666 SetLastError(ERROR_INVALID_PARAMETER);
2667 return FALSE;
2670 /* This function has to be run through in order to process the name properly.
2671 If the BOOTDELAY flag is set, the file doesn't need to exist though. At least
2672 that is the behaviour on NT 4.0. The operation accepts the filenames as
2673 they are given but it can't reply with a reasonable returncode. Success
2674 means in that case success for entering the values into the registry.
2676 if(!DOSFS_GetFullName( fn1, TRUE, &full_name1 ))
2678 if(!(flag & MOVEFILE_DELAY_UNTIL_REBOOT))
2679 return FALSE;
2682 if (fn2) /* !fn2 means delete fn1 */
2684 if (DOSFS_GetFullName( fn2, TRUE, &full_name2 ))
2686 if(!(flag & MOVEFILE_DELAY_UNTIL_REBOOT))
2688 /* target exists, check if we may overwrite */
2689 if (!(flag & MOVEFILE_REPLACE_EXISTING))
2691 SetLastError( ERROR_FILE_EXISTS );
2692 return FALSE;
2696 else
2698 if (!DOSFS_GetFullName( fn2, FALSE, &full_name2 ))
2700 if(!(flag & MOVEFILE_DELAY_UNTIL_REBOOT))
2701 return FALSE;
2705 /* Source name and target path are valid */
2707 if (flag & MOVEFILE_DELAY_UNTIL_REBOOT)
2709 /* FIXME: (bon@elektron.ikp.physik.th-darmstadt.de 970706)
2710 Perhaps we should queue these command and execute it
2711 when exiting... What about using on_exit(2)
2713 FIXME("Please move existing file %s to file %s when Wine has finished\n",
2714 debugstr_w(fn1), debugstr_w(fn2));
2715 return FILE_AddBootRenameEntry( fn1, fn2, flag );
2718 attr = GetFileAttributesW( fn1 );
2719 if ( attr == INVALID_FILE_ATTRIBUTES ) return FALSE;
2721 /* check if we are allowed to rename the source */
2722 hFile = FILE_CreateFile( full_name1.long_name, 0, 0,
2723 NULL, OPEN_EXISTING, 0, 0, TRUE,
2724 GetDriveTypeW( full_name1.short_name ) );
2725 if (!hFile)
2727 if (GetLastError() != ERROR_ACCESS_DENIED) return FALSE;
2728 if ( !(attr & FILE_ATTRIBUTE_DIRECTORY) ) return FALSE;
2729 /* if it's a directory we can continue */
2731 else CloseHandle(hFile);
2733 /* check, if we are allowed to delete the destination,
2734 ** (but the file not being there is fine) */
2735 hFile = FILE_CreateFile( full_name2.long_name, GENERIC_READ|GENERIC_WRITE, 0,
2736 NULL, OPEN_EXISTING, 0, 0, TRUE,
2737 GetDriveTypeW( full_name2.short_name ) );
2738 if(!hFile && GetLastError() != ERROR_FILE_NOT_FOUND) return FALSE;
2739 CloseHandle(hFile);
2741 if (full_name1.drive != full_name2.drive)
2743 if (!(flag & MOVEFILE_COPY_ALLOWED))
2745 SetLastError( ERROR_NOT_SAME_DEVICE );
2746 return FALSE;
2748 else if ( attr & FILE_ATTRIBUTE_DIRECTORY )
2750 /* Strange, but that's what Windows returns */
2751 SetLastError ( ERROR_ACCESS_DENIED );
2752 return FALSE;
2755 if (rename( full_name1.long_name, full_name2.long_name ) == -1)
2756 /* Try copy/delete unless it's a directory. */
2757 /* FIXME: This does not handle the (unlikely) case that the two locations
2758 are on the same Wine drive, but on different Unix file systems. */
2760 if ( attr & FILE_ATTRIBUTE_DIRECTORY )
2762 FILE_SetDosError();
2763 return FALSE;
2765 else
2767 if ( ! CopyFileW( fn1, fn2, !(flag & MOVEFILE_REPLACE_EXISTING) ))
2768 return FALSE;
2769 if ( ! DeleteFileW ( fn1 ) )
2770 return FALSE;
2773 if (is_executable( full_name1.long_name ) != is_executable( full_name2.long_name ))
2775 struct stat fstat;
2776 if (stat( full_name2.long_name, &fstat ) != -1)
2778 if (is_executable( full_name2.long_name ))
2779 /* set executable bit where read bit is set */
2780 fstat.st_mode |= (fstat.st_mode & 0444) >> 2;
2781 else
2782 fstat.st_mode &= ~0111;
2783 chmod( full_name2.long_name, fstat.st_mode );
2786 return TRUE;
2788 else /* fn2 == NULL means delete source */
2790 if (flag & MOVEFILE_DELAY_UNTIL_REBOOT)
2792 if (flag & MOVEFILE_COPY_ALLOWED) {
2793 WARN("Illegal flag\n");
2794 SetLastError( ERROR_GEN_FAILURE );
2795 return FALSE;
2797 /* FIXME: (bon@elektron.ikp.physik.th-darmstadt.de 970706)
2798 Perhaps we should queue these command and execute it
2799 when exiting... What about using on_exit(2)
2801 FIXME("Please delete file %s when Wine has finished\n", debugstr_w(fn1));
2802 return FILE_AddBootRenameEntry( fn1, NULL, flag );
2805 if (unlink( full_name1.long_name ) == -1)
2807 FILE_SetDosError();
2808 return FALSE;
2810 return TRUE; /* successfully deleted */
2814 /**************************************************************************
2815 * MoveFileExA (KERNEL32.@)
2817 BOOL WINAPI MoveFileExA( LPCSTR fn1, LPCSTR fn2, DWORD flag )
2819 UNICODE_STRING fn1W, fn2W;
2820 BOOL ret;
2822 if (!fn1)
2824 SetLastError(ERROR_INVALID_PARAMETER);
2825 return FALSE;
2828 RtlCreateUnicodeStringFromAsciiz(&fn1W, fn1);
2829 if (fn2) RtlCreateUnicodeStringFromAsciiz(&fn2W, fn2);
2830 else fn2W.Buffer = NULL;
2832 ret = MoveFileExW( fn1W.Buffer, fn2W.Buffer, flag );
2834 RtlFreeUnicodeString(&fn1W);
2835 RtlFreeUnicodeString(&fn2W);
2836 return ret;
2840 /**************************************************************************
2841 * MoveFileW (KERNEL32.@)
2843 * Move file or directory
2845 BOOL WINAPI MoveFileW( LPCWSTR fn1, LPCWSTR fn2 )
2847 DOS_FULL_NAME full_name1, full_name2;
2848 struct stat fstat;
2850 if (!fn1 || !fn2)
2852 SetLastError(ERROR_INVALID_PARAMETER);
2853 return FALSE;
2856 TRACE("(%s,%s)\n", debugstr_w(fn1), debugstr_w(fn2) );
2858 if (!DOSFS_GetFullName( fn1, TRUE, &full_name1 )) return FALSE;
2859 if (DOSFS_GetFullName( fn2, TRUE, &full_name2 )) {
2860 /* The new name must not already exist */
2861 SetLastError(ERROR_ALREADY_EXISTS);
2862 return FALSE;
2864 if (!DOSFS_GetFullName( fn2, FALSE, &full_name2 )) return FALSE;
2866 if (full_name1.drive == full_name2.drive) /* move */
2867 return MoveFileExW( fn1, fn2, MOVEFILE_COPY_ALLOWED );
2869 /* copy */
2870 if (stat( full_name1.long_name, &fstat ))
2872 WARN("Invalid source file %s\n",
2873 full_name1.long_name);
2874 FILE_SetDosError();
2875 return FALSE;
2877 if (S_ISDIR(fstat.st_mode)) {
2878 /* No Move for directories across file systems */
2879 /* FIXME: Use right error code */
2880 SetLastError( ERROR_GEN_FAILURE );
2881 return FALSE;
2883 return CopyFileW(fn1, fn2, TRUE); /*fail, if exist */
2887 /**************************************************************************
2888 * MoveFileA (KERNEL32.@)
2890 BOOL WINAPI MoveFileA( LPCSTR fn1, LPCSTR fn2 )
2892 UNICODE_STRING fn1W, fn2W;
2893 BOOL ret;
2895 if (!fn1 || !fn2)
2897 SetLastError(ERROR_INVALID_PARAMETER);
2898 return FALSE;
2901 RtlCreateUnicodeStringFromAsciiz(&fn1W, fn1);
2902 RtlCreateUnicodeStringFromAsciiz(&fn2W, fn2);
2904 ret = MoveFileW( fn1W.Buffer, fn2W.Buffer );
2906 RtlFreeUnicodeString(&fn1W);
2907 RtlFreeUnicodeString(&fn2W);
2908 return ret;
2912 /**************************************************************************
2913 * CopyFileW (KERNEL32.@)
2915 BOOL WINAPI CopyFileW( LPCWSTR source, LPCWSTR dest, BOOL fail_if_exists )
2917 HANDLE h1, h2;
2918 BY_HANDLE_FILE_INFORMATION info;
2919 DWORD count;
2920 BOOL ret = FALSE;
2921 char buffer[2048];
2923 if (!source || !dest)
2925 SetLastError(ERROR_INVALID_PARAMETER);
2926 return FALSE;
2929 TRACE("%s -> %s\n", debugstr_w(source), debugstr_w(dest));
2931 if ((h1 = CreateFileW(source, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE,
2932 NULL, OPEN_EXISTING, 0, 0)) == INVALID_HANDLE_VALUE)
2934 WARN("Unable to open source %s\n", debugstr_w(source));
2935 return FALSE;
2938 if (!GetFileInformationByHandle( h1, &info ))
2940 WARN("GetFileInformationByHandle returned error for %s\n", debugstr_w(source));
2941 CloseHandle( h1 );
2942 return FALSE;
2945 if ((h2 = CreateFileW( dest, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
2946 fail_if_exists ? CREATE_NEW : CREATE_ALWAYS,
2947 info.dwFileAttributes, h1 )) == INVALID_HANDLE_VALUE)
2949 WARN("Unable to open dest %s\n", debugstr_w(dest));
2950 CloseHandle( h1 );
2951 return FALSE;
2954 while (ReadFile( h1, buffer, sizeof(buffer), &count, NULL ) && count)
2956 char *p = buffer;
2957 while (count != 0)
2959 DWORD res;
2960 if (!WriteFile( h2, p, count, &res, NULL ) || !res) goto done;
2961 p += res;
2962 count -= res;
2965 ret = TRUE;
2966 done:
2967 CloseHandle( h1 );
2968 CloseHandle( h2 );
2969 return ret;
2973 /**************************************************************************
2974 * CopyFileA (KERNEL32.@)
2976 BOOL WINAPI CopyFileA( LPCSTR source, LPCSTR dest, BOOL fail_if_exists)
2978 UNICODE_STRING sourceW, destW;
2979 BOOL ret;
2981 if (!source || !dest)
2983 SetLastError(ERROR_INVALID_PARAMETER);
2984 return FALSE;
2987 RtlCreateUnicodeStringFromAsciiz(&sourceW, source);
2988 RtlCreateUnicodeStringFromAsciiz(&destW, dest);
2990 ret = CopyFileW(sourceW.Buffer, destW.Buffer, fail_if_exists);
2992 RtlFreeUnicodeString(&sourceW);
2993 RtlFreeUnicodeString(&destW);
2994 return ret;
2998 /**************************************************************************
2999 * CopyFileExW (KERNEL32.@)
3001 * This implementation ignores most of the extra parameters passed-in into
3002 * the "ex" version of the method and calls the CopyFile method.
3003 * It will have to be fixed eventually.
3005 BOOL WINAPI CopyFileExW(LPCWSTR sourceFilename, LPCWSTR destFilename,
3006 LPPROGRESS_ROUTINE progressRoutine, LPVOID appData,
3007 LPBOOL cancelFlagPointer, DWORD copyFlags)
3010 * Interpret the only flag that CopyFile can interpret.
3012 return CopyFileW(sourceFilename, destFilename, (copyFlags & COPY_FILE_FAIL_IF_EXISTS) != 0);
3015 /**************************************************************************
3016 * CopyFileExA (KERNEL32.@)
3018 BOOL WINAPI CopyFileExA(LPCSTR sourceFilename, LPCSTR destFilename,
3019 LPPROGRESS_ROUTINE progressRoutine, LPVOID appData,
3020 LPBOOL cancelFlagPointer, DWORD copyFlags)
3022 UNICODE_STRING sourceW, destW;
3023 BOOL ret;
3025 if (!sourceFilename || !destFilename)
3027 SetLastError(ERROR_INVALID_PARAMETER);
3028 return FALSE;
3031 RtlCreateUnicodeStringFromAsciiz(&sourceW, sourceFilename);
3032 RtlCreateUnicodeStringFromAsciiz(&destW, destFilename);
3034 ret = CopyFileExW(sourceW.Buffer, destW.Buffer, progressRoutine, appData,
3035 cancelFlagPointer, copyFlags);
3037 RtlFreeUnicodeString(&sourceW);
3038 RtlFreeUnicodeString(&destW);
3039 return ret;
3043 /***********************************************************************
3044 * SetFileTime (KERNEL32.@)
3046 BOOL WINAPI SetFileTime( HANDLE hFile,
3047 const FILETIME *lpCreationTime,
3048 const FILETIME *lpLastAccessTime,
3049 const FILETIME *lpLastWriteTime )
3051 BOOL ret;
3052 SERVER_START_REQ( set_file_time )
3054 req->handle = hFile;
3055 if (lpLastAccessTime)
3056 RtlTimeToSecondsSince1970( (PLARGE_INTEGER) lpLastAccessTime, (DWORD *)&req->access_time );
3057 else
3058 req->access_time = 0; /* FIXME */
3059 if (lpLastWriteTime)
3060 RtlTimeToSecondsSince1970( (PLARGE_INTEGER) lpLastWriteTime, (DWORD *)&req->write_time );
3061 else
3062 req->write_time = 0; /* FIXME */
3063 ret = !wine_server_call_err( req );
3065 SERVER_END_REQ;
3066 return ret;
3070 /**************************************************************************
3071 * LockFile (KERNEL32.@)
3073 BOOL WINAPI LockFile( HANDLE hFile, DWORD dwFileOffsetLow, DWORD dwFileOffsetHigh,
3074 DWORD nNumberOfBytesToLockLow, DWORD nNumberOfBytesToLockHigh )
3076 BOOL ret;
3078 FIXME("not implemented in server\n");
3080 SERVER_START_REQ( lock_file )
3082 req->handle = hFile;
3083 req->offset_low = dwFileOffsetLow;
3084 req->offset_high = dwFileOffsetHigh;
3085 req->count_low = nNumberOfBytesToLockLow;
3086 req->count_high = nNumberOfBytesToLockHigh;
3087 ret = !wine_server_call_err( req );
3089 SERVER_END_REQ;
3090 return ret;
3093 /**************************************************************************
3094 * LockFileEx [KERNEL32.@]
3096 * Locks a byte range within an open file for shared or exclusive access.
3098 * RETURNS
3099 * success: TRUE
3100 * failure: FALSE
3102 * NOTES
3103 * Per Microsoft docs, the third parameter (reserved) must be set to 0.
3105 BOOL WINAPI LockFileEx( HANDLE hFile, DWORD flags, DWORD reserved,
3106 DWORD nNumberOfBytesToLockLow, DWORD nNumberOfBytesToLockHigh,
3107 LPOVERLAPPED pOverlapped )
3109 FIXME("hFile=%p,flags=%ld,reserved=%ld,lowbytes=%ld,highbytes=%ld,overlapped=%p: stub.\n",
3110 hFile, flags, reserved, nNumberOfBytesToLockLow, nNumberOfBytesToLockHigh,
3111 pOverlapped);
3112 if (reserved == 0)
3113 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
3114 else
3116 ERR("reserved == %ld: Supposed to be 0??\n", reserved);
3117 SetLastError(ERROR_INVALID_PARAMETER);
3120 return FALSE;
3124 /**************************************************************************
3125 * UnlockFile (KERNEL32.@)
3127 BOOL WINAPI UnlockFile( HANDLE hFile, DWORD dwFileOffsetLow, DWORD dwFileOffsetHigh,
3128 DWORD nNumberOfBytesToUnlockLow, DWORD nNumberOfBytesToUnlockHigh )
3130 BOOL ret;
3132 FIXME("not implemented in server\n");
3134 SERVER_START_REQ( unlock_file )
3136 req->handle = hFile;
3137 req->offset_low = dwFileOffsetLow;
3138 req->offset_high = dwFileOffsetHigh;
3139 req->count_low = nNumberOfBytesToUnlockLow;
3140 req->count_high = nNumberOfBytesToUnlockHigh;
3141 ret = !wine_server_call_err( req );
3143 SERVER_END_REQ;
3144 return ret;
3148 /**************************************************************************
3149 * UnlockFileEx (KERNEL32.@)
3151 BOOL WINAPI UnlockFileEx(
3152 HANDLE hFile,
3153 DWORD dwReserved,
3154 DWORD nNumberOfBytesToUnlockLow,
3155 DWORD nNumberOfBytesToUnlockHigh,
3156 LPOVERLAPPED lpOverlapped
3159 FIXME("hFile=%p,reserved=%ld,lowbytes=%ld,highbytes=%ld,overlapped=%p: stub.\n",
3160 hFile, dwReserved, nNumberOfBytesToUnlockLow, nNumberOfBytesToUnlockHigh,
3161 lpOverlapped);
3162 if (dwReserved == 0)
3163 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
3164 else
3166 ERR("reserved == %ld: Supposed to be 0??\n", dwReserved);
3167 SetLastError(ERROR_INVALID_PARAMETER);
3170 return FALSE;
3174 #if 0
3176 struct DOS_FILE_LOCK {
3177 struct DOS_FILE_LOCK * next;
3178 DWORD base;
3179 DWORD len;
3180 DWORD processId;
3181 FILE_OBJECT * dos_file;
3182 /* char * unix_name;*/
3185 typedef struct DOS_FILE_LOCK DOS_FILE_LOCK;
3187 static DOS_FILE_LOCK *locks = NULL;
3188 static void DOS_RemoveFileLocks(FILE_OBJECT *file);
3191 /* Locks need to be mirrored because unix file locking is based
3192 * on the pid. Inside of wine there can be multiple WINE processes
3193 * that share the same unix pid.
3194 * Read's and writes should check these locks also - not sure
3195 * how critical that is at this point (FIXME).
3198 static BOOL DOS_AddLock(FILE_OBJECT *file, struct flock *f)
3200 DOS_FILE_LOCK *curr;
3201 DWORD processId;
3203 processId = GetCurrentProcessId();
3205 /* check if lock overlaps a current lock for the same file */
3206 #if 0
3207 for (curr = locks; curr; curr = curr->next) {
3208 if (strcmp(curr->unix_name, file->unix_name) == 0) {
3209 if ((f->l_start == curr->base) && (f->l_len == curr->len))
3210 return TRUE;/* region is identic */
3211 if ((f->l_start < (curr->base + curr->len)) &&
3212 ((f->l_start + f->l_len) > curr->base)) {
3213 /* region overlaps */
3214 return FALSE;
3218 #endif
3220 curr = HeapAlloc( GetProcessHeap(), 0, sizeof(DOS_FILE_LOCK) );
3221 curr->processId = GetCurrentProcessId();
3222 curr->base = f->l_start;
3223 curr->len = f->l_len;
3224 /* curr->unix_name = HEAP_strdupA( GetProcessHeap(), 0, file->unix_name);*/
3225 curr->next = locks;
3226 curr->dos_file = file;
3227 locks = curr;
3228 return TRUE;
3231 static void DOS_RemoveFileLocks(FILE_OBJECT *file)
3233 DWORD processId;
3234 DOS_FILE_LOCK **curr;
3235 DOS_FILE_LOCK *rem;
3237 processId = GetCurrentProcessId();
3238 curr = &locks;
3239 while (*curr) {
3240 if ((*curr)->dos_file == file) {
3241 rem = *curr;
3242 *curr = (*curr)->next;
3243 /* HeapFree( GetProcessHeap(), 0, rem->unix_name );*/
3244 HeapFree( GetProcessHeap(), 0, rem );
3246 else
3247 curr = &(*curr)->next;
3251 static BOOL DOS_RemoveLock(FILE_OBJECT *file, struct flock *f)
3253 DWORD processId;
3254 DOS_FILE_LOCK **curr;
3255 DOS_FILE_LOCK *rem;
3257 processId = GetCurrentProcessId();
3258 for (curr = &locks; *curr; curr = &(*curr)->next) {
3259 if ((*curr)->processId == processId &&
3260 (*curr)->dos_file == file &&
3261 (*curr)->base == f->l_start &&
3262 (*curr)->len == f->l_len) {
3263 /* this is the same lock */
3264 rem = *curr;
3265 *curr = (*curr)->next;
3266 /* HeapFree( GetProcessHeap(), 0, rem->unix_name );*/
3267 HeapFree( GetProcessHeap(), 0, rem );
3268 return TRUE;
3271 /* no matching lock found */
3272 return FALSE;
3276 /**************************************************************************
3277 * LockFile (KERNEL32.@)
3279 BOOL WINAPI LockFile(
3280 HANDLE hFile,DWORD dwFileOffsetLow,DWORD dwFileOffsetHigh,
3281 DWORD nNumberOfBytesToLockLow,DWORD nNumberOfBytesToLockHigh )
3283 struct flock f;
3284 FILE_OBJECT *file;
3286 TRACE("handle %d offsetlow=%ld offsethigh=%ld nbyteslow=%ld nbyteshigh=%ld\n",
3287 hFile, dwFileOffsetLow, dwFileOffsetHigh,
3288 nNumberOfBytesToLockLow, nNumberOfBytesToLockHigh);
3290 if (dwFileOffsetHigh || nNumberOfBytesToLockHigh) {
3291 FIXME("Unimplemented bytes > 32bits\n");
3292 return FALSE;
3295 f.l_start = dwFileOffsetLow;
3296 f.l_len = nNumberOfBytesToLockLow;
3297 f.l_whence = SEEK_SET;
3298 f.l_pid = 0;
3299 f.l_type = F_WRLCK;
3301 if (!(file = FILE_GetFile(hFile,0,NULL))) return FALSE;
3303 /* shadow locks internally */
3304 if (!DOS_AddLock(file, &f)) {
3305 SetLastError( ERROR_LOCK_VIOLATION );
3306 return FALSE;
3309 /* FIXME: Unix locking commented out for now, doesn't work with Excel */
3310 #ifdef USE_UNIX_LOCKS
3311 if (fcntl(file->unix_handle, F_SETLK, &f) == -1) {
3312 if (errno == EACCES || errno == EAGAIN) {
3313 SetLastError( ERROR_LOCK_VIOLATION );
3315 else {
3316 FILE_SetDosError();
3318 /* remove our internal copy of the lock */
3319 DOS_RemoveLock(file, &f);
3320 return FALSE;
3322 #endif
3323 return TRUE;
3327 /**************************************************************************
3328 * UnlockFile (KERNEL32.@)
3330 BOOL WINAPI UnlockFile(
3331 HANDLE hFile,DWORD dwFileOffsetLow,DWORD dwFileOffsetHigh,
3332 DWORD nNumberOfBytesToUnlockLow,DWORD nNumberOfBytesToUnlockHigh )
3334 FILE_OBJECT *file;
3335 struct flock f;
3337 TRACE("handle %d offsetlow=%ld offsethigh=%ld nbyteslow=%ld nbyteshigh=%ld\n",
3338 hFile, dwFileOffsetLow, dwFileOffsetHigh,
3339 nNumberOfBytesToUnlockLow, nNumberOfBytesToUnlockHigh);
3341 if (dwFileOffsetHigh || nNumberOfBytesToUnlockHigh) {
3342 WARN("Unimplemented bytes > 32bits\n");
3343 return FALSE;
3346 f.l_start = dwFileOffsetLow;
3347 f.l_len = nNumberOfBytesToUnlockLow;
3348 f.l_whence = SEEK_SET;
3349 f.l_pid = 0;
3350 f.l_type = F_UNLCK;
3352 if (!(file = FILE_GetFile(hFile,0,NULL))) return FALSE;
3354 DOS_RemoveLock(file, &f); /* ok if fails - may be another wine */
3356 /* FIXME: Unix locking commented out for now, doesn't work with Excel */
3357 #ifdef USE_UNIX_LOCKS
3358 if (fcntl(file->unix_handle, F_SETLK, &f) == -1) {
3359 FILE_SetDosError();
3360 return FALSE;
3362 #endif
3363 return TRUE;
3365 #endif
3367 /**************************************************************************
3368 * GetFileAttributesExW (KERNEL32.@)
3370 BOOL WINAPI GetFileAttributesExW(
3371 LPCWSTR lpFileName, GET_FILEEX_INFO_LEVELS fInfoLevelId,
3372 LPVOID lpFileInformation)
3374 DOS_FULL_NAME full_name;
3375 BY_HANDLE_FILE_INFORMATION info;
3377 if (!lpFileName || !lpFileInformation)
3379 SetLastError(ERROR_INVALID_PARAMETER);
3380 return FALSE;
3383 if (fInfoLevelId == GetFileExInfoStandard) {
3384 LPWIN32_FILE_ATTRIBUTE_DATA lpFad =
3385 (LPWIN32_FILE_ATTRIBUTE_DATA) lpFileInformation;
3386 if (!DOSFS_GetFullName( lpFileName, TRUE, &full_name )) return FALSE;
3387 if (!FILE_Stat( full_name.long_name, &info, NULL )) return FALSE;
3389 lpFad->dwFileAttributes = info.dwFileAttributes;
3390 lpFad->ftCreationTime = info.ftCreationTime;
3391 lpFad->ftLastAccessTime = info.ftLastAccessTime;
3392 lpFad->ftLastWriteTime = info.ftLastWriteTime;
3393 lpFad->nFileSizeHigh = info.nFileSizeHigh;
3394 lpFad->nFileSizeLow = info.nFileSizeLow;
3396 else {
3397 FIXME("invalid info level %d!\n", fInfoLevelId);
3398 return FALSE;
3401 return TRUE;
3405 /**************************************************************************
3406 * GetFileAttributesExA (KERNEL32.@)
3408 BOOL WINAPI GetFileAttributesExA(
3409 LPCSTR filename, GET_FILEEX_INFO_LEVELS fInfoLevelId,
3410 LPVOID lpFileInformation)
3412 UNICODE_STRING filenameW;
3413 BOOL ret = FALSE;
3415 if (!filename || !lpFileInformation)
3417 SetLastError(ERROR_INVALID_PARAMETER);
3418 return FALSE;
3421 if (RtlCreateUnicodeStringFromAsciiz(&filenameW, filename))
3423 ret = GetFileAttributesExW(filenameW.Buffer, fInfoLevelId, lpFileInformation);
3424 RtlFreeUnicodeString(&filenameW);
3426 else
3427 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
3428 return ret;