Added TIME_KILL_SYNCHRONOUS.
[wine/gsoc_dplay.git] / files / file.c
blob0031281423bc6de0fd24c4dbafddd5a60fc6bcbe
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 * FILE_GetTempFileName : utility for GetTempFileName
1043 static UINT FILE_GetTempFileName( LPCWSTR path, LPCWSTR prefix, UINT unique,
1044 LPWSTR buffer )
1046 static UINT unique_temp;
1047 DOS_FULL_NAME full_name;
1048 int i;
1049 LPWSTR p;
1050 UINT num;
1051 char buf[20];
1053 if ( !path || !prefix || !buffer )
1055 SetLastError( ERROR_INVALID_PARAMETER );
1056 return 0;
1059 if (!unique_temp) unique_temp = time(NULL) & 0xffff;
1060 num = unique ? (unique & 0xffff) : (unique_temp++ & 0xffff);
1062 strcpyW( buffer, path );
1063 p = buffer + strlenW(buffer);
1065 /* add a \, if there isn't one and path is more than just the drive letter ... */
1066 if ( !((strlenW(buffer) == 2) && (buffer[1] == ':'))
1067 && ((p == buffer) || (p[-1] != '\\'))) *p++ = '\\';
1069 for (i = 3; (i > 0) && (*prefix); i--) *p++ = *prefix++;
1071 sprintf( buf, "%04x.tmp", num );
1072 MultiByteToWideChar(CP_ACP, 0, buf, -1, p, 20);
1074 /* Now try to create it */
1076 if (!unique)
1080 HANDLE handle = CreateFileW( buffer, GENERIC_WRITE, 0, NULL,
1081 CREATE_NEW, FILE_ATTRIBUTE_NORMAL, 0 );
1082 if (handle != INVALID_HANDLE_VALUE)
1083 { /* We created it */
1084 TRACE("created %s\n", debugstr_w(buffer) );
1085 CloseHandle( handle );
1086 break;
1088 if (GetLastError() != ERROR_FILE_EXISTS)
1089 break; /* No need to go on */
1090 num++;
1091 sprintf( buf, "%04x.tmp", num );
1092 MultiByteToWideChar(CP_ACP, 0, buf, -1, p, 20);
1093 } while (num != (unique & 0xffff));
1096 /* Get the full path name */
1098 if (DOSFS_GetFullName( buffer, FALSE, &full_name ))
1100 char *slash;
1101 /* Check if we have write access in the directory */
1102 if ((slash = strrchr( full_name.long_name, '/' ))) *slash = '\0';
1103 if (access( full_name.long_name, W_OK ) == -1)
1104 WARN("returns %s, which doesn't seem to be writeable.\n",
1105 debugstr_w(buffer) );
1107 TRACE("returning %s\n", debugstr_w(buffer) );
1108 return unique ? unique : num;
1112 /***********************************************************************
1113 * GetTempFileNameA (KERNEL32.@)
1115 UINT WINAPI GetTempFileNameA( LPCSTR path, LPCSTR prefix, UINT unique,
1116 LPSTR buffer)
1118 UNICODE_STRING pathW, prefixW;
1119 WCHAR bufferW[MAX_PATH];
1120 UINT ret;
1122 if ( !path || !prefix || !buffer )
1124 SetLastError( ERROR_INVALID_PARAMETER );
1125 return 0;
1128 RtlCreateUnicodeStringFromAsciiz(&pathW, path);
1129 RtlCreateUnicodeStringFromAsciiz(&prefixW, prefix);
1131 ret = GetTempFileNameW(pathW.Buffer, prefixW.Buffer, unique, bufferW);
1132 if (ret)
1133 WideCharToMultiByte(CP_ACP, 0, bufferW, -1, buffer, MAX_PATH, NULL, NULL);
1135 RtlFreeUnicodeString(&pathW);
1136 RtlFreeUnicodeString(&prefixW);
1137 return ret;
1140 /***********************************************************************
1141 * GetTempFileNameW (KERNEL32.@)
1143 UINT WINAPI GetTempFileNameW( LPCWSTR path, LPCWSTR prefix, UINT unique,
1144 LPWSTR buffer )
1146 return FILE_GetTempFileName( path, prefix, unique, buffer );
1150 /***********************************************************************
1151 * GetTempFileName (KERNEL.97)
1153 UINT16 WINAPI GetTempFileName16( BYTE drive, LPCSTR prefix, UINT16 unique,
1154 LPSTR buffer )
1156 char temppath[MAX_PATH];
1157 char *prefix16 = NULL;
1158 UINT16 ret;
1160 if (!(drive & ~TF_FORCEDRIVE)) /* drive 0 means current default drive */
1161 drive |= DRIVE_GetCurrentDrive() + 'A';
1163 if ((drive & TF_FORCEDRIVE) &&
1164 !DRIVE_IsValid( toupper(drive & ~TF_FORCEDRIVE) - 'A' ))
1166 drive &= ~TF_FORCEDRIVE;
1167 WARN("invalid drive %d specified\n", drive );
1170 if (drive & TF_FORCEDRIVE)
1171 sprintf(temppath,"%c:", drive & ~TF_FORCEDRIVE );
1172 else
1173 GetTempPathA( MAX_PATH, temppath );
1175 if (prefix)
1177 prefix16 = HeapAlloc(GetProcessHeap(), 0, strlen(prefix) + 2);
1178 *prefix16 = '~';
1179 strcpy(prefix16 + 1, prefix);
1182 ret = GetTempFileNameA( temppath, prefix16, unique, buffer );
1184 if (prefix16) HeapFree(GetProcessHeap(), 0, prefix16);
1185 return ret;
1188 /***********************************************************************
1189 * FILE_DoOpenFile
1191 * Implementation of OpenFile16() and OpenFile32().
1193 static HFILE FILE_DoOpenFile( LPCSTR name, OFSTRUCT *ofs, UINT mode,
1194 BOOL win32 )
1196 HFILE hFileRet;
1197 HANDLE handle;
1198 FILETIME filetime;
1199 WORD filedatetime[2];
1200 DOS_FULL_NAME full_name;
1201 DWORD access, sharing;
1202 WCHAR *p;
1203 WCHAR buffer[MAX_PATH];
1204 LPWSTR nameW;
1206 if (!ofs) return HFILE_ERROR;
1208 TRACE("%s %s %s %s%s%s%s%s%s%s%s%s\n",name,
1209 ((mode & 0x3 )==OF_READ)?"OF_READ":
1210 ((mode & 0x3 )==OF_WRITE)?"OF_WRITE":
1211 ((mode & 0x3 )==OF_READWRITE)?"OF_READWRITE":"unknown",
1212 ((mode & 0x70 )==OF_SHARE_COMPAT)?"OF_SHARE_COMPAT":
1213 ((mode & 0x70 )==OF_SHARE_DENY_NONE)?"OF_SHARE_DENY_NONE":
1214 ((mode & 0x70 )==OF_SHARE_DENY_READ)?"OF_SHARE_DENY_READ":
1215 ((mode & 0x70 )==OF_SHARE_DENY_WRITE)?"OF_SHARE_DENY_WRITE":
1216 ((mode & 0x70 )==OF_SHARE_EXCLUSIVE)?"OF_SHARE_EXCLUSIVE":"unknown",
1217 ((mode & OF_PARSE )==OF_PARSE)?"OF_PARSE ":"",
1218 ((mode & OF_DELETE )==OF_DELETE)?"OF_DELETE ":"",
1219 ((mode & OF_VERIFY )==OF_VERIFY)?"OF_VERIFY ":"",
1220 ((mode & OF_SEARCH )==OF_SEARCH)?"OF_SEARCH ":"",
1221 ((mode & OF_CANCEL )==OF_CANCEL)?"OF_CANCEL ":"",
1222 ((mode & OF_CREATE )==OF_CREATE)?"OF_CREATE ":"",
1223 ((mode & OF_PROMPT )==OF_PROMPT)?"OF_PROMPT ":"",
1224 ((mode & OF_EXIST )==OF_EXIST)?"OF_EXIST ":"",
1225 ((mode & OF_REOPEN )==OF_REOPEN)?"OF_REOPEN ":""
1229 ofs->cBytes = sizeof(OFSTRUCT);
1230 ofs->nErrCode = 0;
1231 if (mode & OF_REOPEN) name = ofs->szPathName;
1233 if (!name) {
1234 ERR("called with `name' set to NULL ! Please debug.\n");
1235 return HFILE_ERROR;
1238 TRACE("%s %04x\n", name, mode );
1240 /* the watcom 10.6 IDE relies on a valid path returned in ofs->szPathName
1241 Are there any cases where getting the path here is wrong?
1242 Uwe Bonnes 1997 Apr 2 */
1243 if (!GetFullPathNameA( name, sizeof(ofs->szPathName),
1244 ofs->szPathName, NULL )) goto error;
1245 FILE_ConvertOFMode( mode, &access, &sharing );
1247 /* OF_PARSE simply fills the structure */
1249 if (mode & OF_PARSE)
1251 ofs->fFixedDisk = (GetDriveType16( ofs->szPathName[0]-'A' )
1252 != DRIVE_REMOVABLE);
1253 TRACE("(%s): OF_PARSE, res = '%s'\n",
1254 name, ofs->szPathName );
1255 return 0;
1258 /* OF_CREATE is completely different from all other options, so
1259 handle it first */
1261 if (mode & OF_CREATE)
1263 if ((handle = CreateFileA( name, GENERIC_READ | GENERIC_WRITE,
1264 sharing, NULL, CREATE_ALWAYS,
1265 FILE_ATTRIBUTE_NORMAL, 0 ))== INVALID_HANDLE_VALUE)
1266 goto error;
1267 goto success;
1270 MultiByteToWideChar(CP_ACP, 0, name, -1, buffer, MAX_PATH);
1271 nameW = buffer;
1273 /* If OF_SEARCH is set, ignore the given path */
1275 if ((mode & OF_SEARCH) && !(mode & OF_REOPEN))
1277 /* First try the file name as is */
1278 if (DOSFS_GetFullName( nameW, TRUE, &full_name )) goto found;
1279 /* Now remove the path */
1280 if (nameW[0] && (nameW[1] == ':')) nameW += 2;
1281 if ((p = strrchrW( nameW, '\\' ))) nameW = p + 1;
1282 if ((p = strrchrW( nameW, '/' ))) nameW = p + 1;
1283 if (!nameW[0]) goto not_found;
1286 /* Now look for the file */
1288 if (!DIR_SearchPath( NULL, nameW, NULL, &full_name, win32 )) goto not_found;
1290 found:
1291 TRACE("found %s = %s\n",
1292 full_name.long_name, debugstr_w(full_name.short_name) );
1293 WideCharToMultiByte(CP_ACP, 0, full_name.short_name, -1,
1294 ofs->szPathName, sizeof(ofs->szPathName), NULL, NULL);
1296 if (mode & OF_SHARE_EXCLUSIVE)
1297 /* Some InstallShield version uses OF_SHARE_EXCLUSIVE
1298 on the file <tempdir>/_ins0432._mp to determine how
1299 far installation has proceeded.
1300 _ins0432._mp is an executable and while running the
1301 application expects the open with OF_SHARE_ to fail*/
1302 /* Probable FIXME:
1303 As our loader closes the files after loading the executable,
1304 we can't find the running executable with FILE_InUse.
1305 The loader should keep the file open, as Windows does that, too.
1308 char *last = strrchr(full_name.long_name,'/');
1309 if (!last)
1310 last = full_name.long_name - 1;
1311 if (GetModuleHandle16(last+1))
1313 TRACE("Denying shared open for %s\n",full_name.long_name);
1314 return HFILE_ERROR;
1318 if (mode & OF_DELETE)
1320 if (unlink( full_name.long_name ) == -1) goto not_found;
1321 TRACE("(%s): OF_DELETE return = OK\n", name);
1322 return 1;
1325 handle = FILE_CreateFile( full_name.long_name, access, sharing,
1326 NULL, OPEN_EXISTING, 0, 0,
1327 DRIVE_GetFlags(full_name.drive) & DRIVE_FAIL_READ_ONLY,
1328 GetDriveTypeW( full_name.short_name ) );
1329 if (!handle) goto not_found;
1331 GetFileTime( handle, NULL, NULL, &filetime );
1332 FileTimeToDosDateTime( &filetime, &filedatetime[0], &filedatetime[1] );
1333 if ((mode & OF_VERIFY) && (mode & OF_REOPEN))
1335 if (ofs->Reserved1 != filedatetime[0] || ofs->Reserved2 != filedatetime[1] )
1337 CloseHandle( handle );
1338 WARN("(%s): OF_VERIFY failed\n", name );
1339 /* FIXME: what error here? */
1340 SetLastError( ERROR_FILE_NOT_FOUND );
1341 goto error;
1344 ofs->Reserved1 = filedatetime[0];
1345 ofs->Reserved2 = filedatetime[1];
1347 success: /* We get here if the open was successful */
1348 TRACE("(%s): OK, return = %p\n", name, handle );
1349 if (win32)
1351 hFileRet = (HFILE)handle;
1352 if (mode & OF_EXIST) /* Return the handle, but close it first */
1353 CloseHandle( handle );
1355 else
1357 hFileRet = Win32HandleToDosFileHandle( handle );
1358 if (hFileRet == HFILE_ERROR16) goto error;
1359 if (mode & OF_EXIST) /* Return the handle, but close it first */
1360 _lclose16( hFileRet );
1362 return hFileRet;
1364 not_found: /* We get here if the file does not exist */
1365 WARN("'%s' not found or sharing violation\n", name );
1366 SetLastError( ERROR_FILE_NOT_FOUND );
1367 /* fall through */
1369 error: /* We get here if there was an error opening the file */
1370 ofs->nErrCode = GetLastError();
1371 WARN("(%s): return = HFILE_ERROR error= %d\n",
1372 name,ofs->nErrCode );
1373 return HFILE_ERROR;
1377 /***********************************************************************
1378 * OpenFile (KERNEL.74)
1379 * OpenFileEx (KERNEL.360)
1381 HFILE16 WINAPI OpenFile16( LPCSTR name, OFSTRUCT *ofs, UINT16 mode )
1383 return FILE_DoOpenFile( name, ofs, mode, FALSE );
1387 /***********************************************************************
1388 * OpenFile (KERNEL32.@)
1390 HFILE WINAPI OpenFile( LPCSTR name, OFSTRUCT *ofs, UINT mode )
1392 return FILE_DoOpenFile( name, ofs, mode, TRUE );
1396 /***********************************************************************
1397 * FILE_InitProcessDosHandles
1399 * Allocates the default DOS handles for a process. Called either by
1400 * Win32HandleToDosFileHandle below or by the DOSVM stuff.
1402 static void FILE_InitProcessDosHandles( void )
1404 HANDLE cp = GetCurrentProcess();
1405 DuplicateHandle(cp, GetStdHandle(STD_INPUT_HANDLE), cp, &dos_handles[0],
1406 0, TRUE, DUPLICATE_SAME_ACCESS);
1407 DuplicateHandle(cp, GetStdHandle(STD_OUTPUT_HANDLE), cp, &dos_handles[1],
1408 0, TRUE, DUPLICATE_SAME_ACCESS);
1409 DuplicateHandle(cp, GetStdHandle(STD_ERROR_HANDLE), cp, &dos_handles[2],
1410 0, TRUE, DUPLICATE_SAME_ACCESS);
1411 DuplicateHandle(cp, GetStdHandle(STD_ERROR_HANDLE), cp, &dos_handles[3],
1412 0, TRUE, DUPLICATE_SAME_ACCESS);
1413 DuplicateHandle(cp, GetStdHandle(STD_ERROR_HANDLE), cp, &dos_handles[4],
1414 0, TRUE, DUPLICATE_SAME_ACCESS);
1417 /***********************************************************************
1418 * Win32HandleToDosFileHandle (KERNEL32.21)
1420 * Allocate a DOS handle for a Win32 handle. The Win32 handle is no
1421 * longer valid after this function (even on failure).
1423 * Note: this is not exactly right, since on Win95 the Win32 handles
1424 * are on top of DOS handles and we do it the other way
1425 * around. Should be good enough though.
1427 HFILE WINAPI Win32HandleToDosFileHandle( HANDLE handle )
1429 int i;
1431 if (!handle || (handle == INVALID_HANDLE_VALUE))
1432 return HFILE_ERROR;
1434 for (i = 5; i < DOS_TABLE_SIZE; i++)
1435 if (!dos_handles[i])
1437 dos_handles[i] = handle;
1438 TRACE("Got %d for h32 %p\n", i, handle );
1439 return (HFILE)i;
1441 CloseHandle( handle );
1442 SetLastError( ERROR_TOO_MANY_OPEN_FILES );
1443 return HFILE_ERROR;
1447 /***********************************************************************
1448 * DosFileHandleToWin32Handle (KERNEL32.20)
1450 * Return the Win32 handle for a DOS handle.
1452 * Note: this is not exactly right, since on Win95 the Win32 handles
1453 * are on top of DOS handles and we do it the other way
1454 * around. Should be good enough though.
1456 HANDLE WINAPI DosFileHandleToWin32Handle( HFILE handle )
1458 HFILE16 hfile = (HFILE16)handle;
1459 if (hfile < 5 && !dos_handles[hfile]) FILE_InitProcessDosHandles();
1460 if ((hfile >= DOS_TABLE_SIZE) || !dos_handles[hfile])
1462 SetLastError( ERROR_INVALID_HANDLE );
1463 return INVALID_HANDLE_VALUE;
1465 return dos_handles[hfile];
1469 /***********************************************************************
1470 * DisposeLZ32Handle (KERNEL32.22)
1472 * Note: this is not entirely correct, we should only close the
1473 * 32-bit handle and not the 16-bit one, but we cannot do
1474 * this because of the way our DOS handles are implemented.
1475 * It shouldn't break anything though.
1477 void WINAPI DisposeLZ32Handle( HANDLE handle )
1479 int i;
1481 if (!handle || (handle == INVALID_HANDLE_VALUE)) return;
1483 for (i = 5; i < DOS_TABLE_SIZE; i++)
1484 if (dos_handles[i] == handle)
1486 dos_handles[i] = 0;
1487 CloseHandle( handle );
1488 break;
1493 /***********************************************************************
1494 * FILE_Dup2
1496 * dup2() function for DOS handles.
1498 HFILE16 FILE_Dup2( HFILE16 hFile1, HFILE16 hFile2 )
1500 HANDLE new_handle;
1502 if (hFile1 < 5 && !dos_handles[hFile1]) FILE_InitProcessDosHandles();
1504 if ((hFile1 >= DOS_TABLE_SIZE) || (hFile2 >= DOS_TABLE_SIZE) || !dos_handles[hFile1])
1506 SetLastError( ERROR_INVALID_HANDLE );
1507 return HFILE_ERROR16;
1509 if (!DuplicateHandle( GetCurrentProcess(), dos_handles[hFile1],
1510 GetCurrentProcess(), &new_handle,
1511 0, FALSE, DUPLICATE_SAME_ACCESS ))
1512 return HFILE_ERROR16;
1513 if (dos_handles[hFile2]) CloseHandle( dos_handles[hFile2] );
1514 dos_handles[hFile2] = new_handle;
1515 return hFile2;
1519 /***********************************************************************
1520 * _lclose (KERNEL.81)
1522 HFILE16 WINAPI _lclose16( HFILE16 hFile )
1524 if ((hFile >= DOS_TABLE_SIZE) || !dos_handles[hFile])
1526 SetLastError( ERROR_INVALID_HANDLE );
1527 return HFILE_ERROR16;
1529 TRACE("%d (handle32=%p)\n", hFile, dos_handles[hFile] );
1530 CloseHandle( dos_handles[hFile] );
1531 dos_handles[hFile] = 0;
1532 return 0;
1536 /***********************************************************************
1537 * _lclose (KERNEL32.@)
1539 HFILE WINAPI _lclose( HFILE hFile )
1541 TRACE("handle %d\n", hFile );
1542 return CloseHandle( (HANDLE)hFile ) ? 0 : HFILE_ERROR;
1545 /***********************************************************************
1546 * GetOverlappedResult (KERNEL32.@)
1548 * Check the result of an Asynchronous data transfer from a file.
1550 * RETURNS
1551 * TRUE on success
1552 * FALSE on failure
1554 * If successful (and relevant) lpTransferred will hold the number of
1555 * bytes transferred during the async operation.
1557 * BUGS
1559 * Currently only works for WaitCommEvent, ReadFile, WriteFile
1560 * with communications ports.
1563 BOOL WINAPI GetOverlappedResult(
1564 HANDLE hFile, /* [in] handle of file to check on */
1565 LPOVERLAPPED lpOverlapped, /* [in/out] pointer to overlapped */
1566 LPDWORD lpTransferred, /* [in/out] number of bytes transferred */
1567 BOOL bWait /* [in] wait for the transfer to complete ? */
1569 DWORD r;
1571 TRACE("(%p %p %p %x)\n", hFile, lpOverlapped, lpTransferred, bWait);
1573 if(lpOverlapped==NULL)
1575 ERR("lpOverlapped was null\n");
1576 return FALSE;
1578 if(!lpOverlapped->hEvent)
1580 ERR("lpOverlapped->hEvent was null\n");
1581 return FALSE;
1584 if ( bWait )
1586 do {
1587 TRACE("waiting on %p\n",lpOverlapped);
1588 r = WaitForSingleObjectEx(lpOverlapped->hEvent, INFINITE, TRUE);
1589 TRACE("wait on %p returned %ld\n",lpOverlapped,r);
1590 } while (r==STATUS_USER_APC);
1592 else if ( lpOverlapped->Internal == STATUS_PENDING )
1594 /* Wait in order to give APCs a chance to run. */
1595 /* This is cheating, so we must set the event again in case of success -
1596 it may be a non-manual reset event. */
1597 do {
1598 TRACE("waiting on %p\n",lpOverlapped);
1599 r = WaitForSingleObjectEx(lpOverlapped->hEvent, 0, TRUE);
1600 TRACE("wait on %p returned %ld\n",lpOverlapped,r);
1601 } while (r==STATUS_USER_APC);
1602 if ( r == WAIT_OBJECT_0 )
1603 NtSetEvent ( lpOverlapped->hEvent, NULL );
1606 if(lpTransferred)
1607 *lpTransferred = lpOverlapped->InternalHigh;
1609 switch ( lpOverlapped->Internal )
1611 case STATUS_SUCCESS:
1612 return TRUE;
1613 case STATUS_PENDING:
1614 SetLastError ( ERROR_IO_INCOMPLETE );
1615 if ( bWait ) ERR ("PENDING status after waiting!\n");
1616 return FALSE;
1617 default:
1618 SetLastError ( RtlNtStatusToDosError ( lpOverlapped->Internal ) );
1619 return FALSE;
1623 /***********************************************************************
1624 * CancelIo (KERNEL32.@)
1626 BOOL WINAPI CancelIo(HANDLE handle)
1628 async_private *ovp,*t;
1630 TRACE("handle = %p\n",handle);
1632 for (ovp = NtCurrentTeb()->pending_list; ovp; ovp = t)
1634 t = ovp->next;
1635 if ( ovp->handle == handle )
1636 cancel_async ( ovp );
1638 WaitForMultipleObjectsEx(0,NULL,FALSE,1,TRUE);
1639 return TRUE;
1642 /***********************************************************************
1643 * FILE_AsyncReadService (INTERNAL)
1645 * This function is called while the client is waiting on the
1646 * server, so we can't make any server calls here.
1648 static void FILE_AsyncReadService(async_private *ovp)
1650 async_fileio *fileio = (async_fileio*) ovp;
1651 LPOVERLAPPED lpOverlapped = fileio->lpOverlapped;
1652 int result, r;
1653 int already = lpOverlapped->InternalHigh;
1655 TRACE("%p %p\n", lpOverlapped, fileio->buffer );
1657 /* check to see if the data is ready (non-blocking) */
1659 if ( fileio->fd_type == FD_TYPE_SOCKET )
1660 result = read (ovp->fd, &fileio->buffer[already], fileio->count - already);
1661 else
1663 result = pread (ovp->fd, &fileio->buffer[already], fileio->count - already,
1664 OVERLAPPED_OFFSET (lpOverlapped) + already);
1665 if ((result < 0) && (errno == ESPIPE))
1666 result = read (ovp->fd, &fileio->buffer[already], fileio->count - already);
1669 if ( (result<0) && ((errno == EAGAIN) || (errno == EINTR)))
1671 TRACE("Deferred read %d\n",errno);
1672 r = STATUS_PENDING;
1673 goto async_end;
1676 /* check to see if the transfer is complete */
1677 if(result<0)
1679 r = FILE_GetNtStatus ();
1680 goto async_end;
1682 else if ( result == 0 )
1684 r = ( lpOverlapped->InternalHigh ? STATUS_SUCCESS : STATUS_END_OF_FILE );
1685 goto async_end;
1688 lpOverlapped->InternalHigh += result;
1689 TRACE("read %d more bytes %ld/%d so far\n",result,lpOverlapped->InternalHigh,fileio->count);
1691 if(lpOverlapped->InternalHigh >= fileio->count || fileio->fd_type == FD_TYPE_SOCKET )
1692 r = STATUS_SUCCESS;
1693 else
1694 r = STATUS_PENDING;
1696 async_end:
1697 lpOverlapped->Internal = r;
1700 /***********************************************************************
1701 * FILE_ReadFileEx (INTERNAL)
1703 static BOOL FILE_ReadFileEx(HANDLE hFile, LPVOID buffer, DWORD bytesToRead,
1704 LPOVERLAPPED overlapped,
1705 LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine,
1706 HANDLE hEvent)
1708 async_fileio *ovp;
1709 int fd;
1710 int flags;
1711 enum fd_type type;
1713 TRACE("file %p to buf %p num %ld %p func %p\n",
1714 hFile, buffer, bytesToRead, overlapped, lpCompletionRoutine);
1716 /* check that there is an overlapped struct */
1717 if (overlapped==NULL)
1719 SetLastError(ERROR_INVALID_PARAMETER);
1720 return FALSE;
1723 fd = FILE_GetUnixHandleType ( hFile, GENERIC_READ, &type, &flags);
1724 if ( fd < 0 )
1726 WARN ( "Couldn't get FD\n" );
1727 return FALSE;
1730 ovp = (async_fileio*) HeapAlloc(GetProcessHeap(), 0, sizeof (async_fileio));
1731 if(!ovp)
1733 TRACE("HeapAlloc Failed\n");
1734 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1735 goto error;
1738 ovp->async.ops = ( lpCompletionRoutine ? &fileio_async_ops : &fileio_nocomp_async_ops );
1739 ovp->async.handle = hFile;
1740 ovp->async.fd = fd;
1741 ovp->async.type = ASYNC_TYPE_READ;
1742 ovp->async.func = FILE_AsyncReadService;
1743 ovp->async.event = hEvent;
1744 ovp->lpOverlapped = overlapped;
1745 ovp->count = bytesToRead;
1746 ovp->completion_func = lpCompletionRoutine;
1747 ovp->buffer = buffer;
1748 ovp->fd_type = type;
1750 return !register_new_async (&ovp->async);
1752 error:
1753 close (fd);
1754 return FALSE;
1758 /***********************************************************************
1759 * ReadFileEx (KERNEL32.@)
1761 BOOL WINAPI ReadFileEx(HANDLE hFile, LPVOID buffer, DWORD bytesToRead,
1762 LPOVERLAPPED overlapped,
1763 LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine)
1765 overlapped->InternalHigh = 0;
1766 return FILE_ReadFileEx(hFile,buffer,bytesToRead,overlapped,lpCompletionRoutine, INVALID_HANDLE_VALUE);
1769 static BOOL FILE_TimeoutRead(HANDLE hFile, LPVOID buffer, DWORD bytesToRead, LPDWORD bytesRead)
1771 OVERLAPPED ov;
1772 BOOL r = FALSE;
1774 TRACE("%p %p %ld %p\n", hFile, buffer, bytesToRead, bytesRead );
1776 ZeroMemory(&ov, sizeof (OVERLAPPED));
1777 if(STATUS_SUCCESS==NtCreateEvent(&ov.hEvent, SYNCHRONIZE, NULL, 0, 0))
1779 if(FILE_ReadFileEx(hFile, buffer, bytesToRead, &ov, NULL, ov.hEvent))
1781 r = GetOverlappedResult(hFile, &ov, bytesRead, TRUE);
1784 CloseHandle(ov.hEvent);
1785 return r;
1788 /***********************************************************************
1789 * ReadFile (KERNEL32.@)
1791 BOOL WINAPI ReadFile( HANDLE hFile, LPVOID buffer, DWORD bytesToRead,
1792 LPDWORD bytesRead, LPOVERLAPPED overlapped )
1794 int unix_handle, result, flags;
1795 enum fd_type type;
1797 TRACE("%p %p %ld %p %p\n", hFile, buffer, bytesToRead,
1798 bytesRead, overlapped );
1800 if (bytesRead) *bytesRead = 0; /* Do this before anything else */
1801 if (!bytesToRead) return TRUE;
1803 unix_handle = FILE_GetUnixHandleType( hFile, GENERIC_READ, &type, &flags );
1805 if (flags & FD_FLAG_OVERLAPPED)
1807 if (unix_handle == -1) return FALSE;
1808 if ( (overlapped==NULL) || NtResetEvent( overlapped->hEvent, NULL ) )
1810 TRACE("Overlapped not specified or invalid event flag\n");
1811 close(unix_handle);
1812 SetLastError(ERROR_INVALID_PARAMETER);
1813 return FALSE;
1816 close(unix_handle);
1817 overlapped->InternalHigh = 0;
1819 if(!FILE_ReadFileEx(hFile, buffer, bytesToRead, overlapped, NULL, overlapped->hEvent))
1820 return FALSE;
1822 if ( !GetOverlappedResult (hFile, overlapped, bytesRead, FALSE) )
1824 if ( GetLastError() == ERROR_IO_INCOMPLETE )
1825 SetLastError ( ERROR_IO_PENDING );
1826 return FALSE;
1829 return TRUE;
1831 if (flags & FD_FLAG_TIMEOUT)
1833 close(unix_handle);
1834 return FILE_TimeoutRead(hFile, buffer, bytesToRead, bytesRead);
1836 switch(type)
1838 case FD_TYPE_SMB:
1839 return SMB_ReadFile(hFile, buffer, bytesToRead, bytesRead, NULL);
1841 case FD_TYPE_CONSOLE:
1842 return FILE_ReadConsole(hFile, buffer, bytesToRead, bytesRead, NULL);
1844 case FD_TYPE_DEFAULT:
1845 /* normal unix files */
1846 if (unix_handle == -1) return FALSE;
1847 if (overlapped)
1849 DWORD highOffset = overlapped->OffsetHigh;
1850 if ( (INVALID_SET_FILE_POINTER == SetFilePointer(hFile, overlapped->Offset,
1851 &highOffset, FILE_BEGIN)) &&
1852 (GetLastError() != NO_ERROR) )
1854 close(unix_handle);
1855 return FALSE;
1858 break;
1860 default:
1861 if (unix_handle == -1)
1862 return FALSE;
1865 if(overlapped)
1867 off_t offset = OVERLAPPED_OFFSET(overlapped);
1868 if(lseek(unix_handle, offset, SEEK_SET) == -1)
1870 close(unix_handle);
1871 SetLastError(ERROR_INVALID_PARAMETER);
1872 return FALSE;
1876 /* code for synchronous reads */
1877 while ((result = read( unix_handle, buffer, bytesToRead )) == -1)
1879 if ((errno == EAGAIN) || (errno == EINTR)) continue;
1880 if ((errno == EFAULT) && !IsBadWritePtr( buffer, bytesToRead )) continue;
1881 FILE_SetDosError();
1882 break;
1884 close( unix_handle );
1885 if (result == -1) return FALSE;
1886 if (bytesRead) *bytesRead = result;
1887 return TRUE;
1891 /***********************************************************************
1892 * FILE_AsyncWriteService (INTERNAL)
1894 * This function is called while the client is waiting on the
1895 * server, so we can't make any server calls here.
1897 static void FILE_AsyncWriteService(struct async_private *ovp)
1899 async_fileio *fileio = (async_fileio *) ovp;
1900 LPOVERLAPPED lpOverlapped = fileio->lpOverlapped;
1901 int result, r;
1902 int already = lpOverlapped->InternalHigh;
1904 TRACE("(%p %p)\n",lpOverlapped,fileio->buffer);
1906 /* write some data (non-blocking) */
1908 if ( fileio->fd_type == FD_TYPE_SOCKET )
1909 result = write(ovp->fd, &fileio->buffer[already], fileio->count - already);
1910 else
1912 result = pwrite(ovp->fd, &fileio->buffer[already], fileio->count - already,
1913 OVERLAPPED_OFFSET (lpOverlapped) + already);
1914 if ((result < 0) && (errno == ESPIPE))
1915 result = write(ovp->fd, &fileio->buffer[already], fileio->count - already);
1918 if ( (result<0) && ((errno == EAGAIN) || (errno == EINTR)))
1920 r = STATUS_PENDING;
1921 goto async_end;
1924 /* check to see if the transfer is complete */
1925 if(result<0)
1927 r = FILE_GetNtStatus ();
1928 goto async_end;
1931 lpOverlapped->InternalHigh += result;
1933 TRACE("wrote %d more bytes %ld/%d so far\n",result,lpOverlapped->InternalHigh,fileio->count);
1935 if(lpOverlapped->InternalHigh < fileio->count)
1936 r = STATUS_PENDING;
1937 else
1938 r = STATUS_SUCCESS;
1940 async_end:
1941 lpOverlapped->Internal = r;
1944 /***********************************************************************
1945 * FILE_WriteFileEx
1947 static BOOL FILE_WriteFileEx(HANDLE hFile, LPCVOID buffer, DWORD bytesToWrite,
1948 LPOVERLAPPED overlapped,
1949 LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine,
1950 HANDLE hEvent)
1952 async_fileio *ovp;
1953 int fd;
1954 int flags;
1955 enum fd_type type;
1957 TRACE("file %p to buf %p num %ld %p func %p handle %p\n",
1958 hFile, buffer, bytesToWrite, overlapped, lpCompletionRoutine, hEvent);
1960 if (overlapped == NULL)
1962 SetLastError(ERROR_INVALID_PARAMETER);
1963 return FALSE;
1966 fd = FILE_GetUnixHandleType ( hFile, GENERIC_WRITE, &type, &flags );
1967 if ( fd < 0 )
1969 TRACE( "Couldn't get FD\n" );
1970 return FALSE;
1973 ovp = (async_fileio*) HeapAlloc(GetProcessHeap(), 0, sizeof (async_fileio));
1974 if(!ovp)
1976 TRACE("HeapAlloc Failed\n");
1977 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1978 goto error;
1981 ovp->async.ops = ( lpCompletionRoutine ? &fileio_async_ops : &fileio_nocomp_async_ops );
1982 ovp->async.handle = hFile;
1983 ovp->async.fd = fd;
1984 ovp->async.type = ASYNC_TYPE_WRITE;
1985 ovp->async.func = FILE_AsyncWriteService;
1986 ovp->lpOverlapped = overlapped;
1987 ovp->async.event = hEvent;
1988 ovp->buffer = (LPVOID) buffer;
1989 ovp->count = bytesToWrite;
1990 ovp->completion_func = lpCompletionRoutine;
1991 ovp->fd_type = type;
1993 return !register_new_async (&ovp->async);
1995 error:
1996 close (fd);
1997 return FALSE;
2000 /***********************************************************************
2001 * WriteFileEx (KERNEL32.@)
2003 BOOL WINAPI WriteFileEx(HANDLE hFile, LPCVOID buffer, DWORD bytesToWrite,
2004 LPOVERLAPPED overlapped,
2005 LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine)
2007 overlapped->InternalHigh = 0;
2009 return FILE_WriteFileEx(hFile, buffer, bytesToWrite, overlapped, lpCompletionRoutine, INVALID_HANDLE_VALUE);
2012 /***********************************************************************
2013 * WriteFile (KERNEL32.@)
2015 BOOL WINAPI WriteFile( HANDLE hFile, LPCVOID buffer, DWORD bytesToWrite,
2016 LPDWORD bytesWritten, LPOVERLAPPED overlapped )
2018 int unix_handle, result, flags;
2019 enum fd_type type;
2021 TRACE("%p %p %ld %p %p\n", hFile, buffer, bytesToWrite,
2022 bytesWritten, overlapped );
2024 if (bytesWritten) *bytesWritten = 0; /* Do this before anything else */
2025 if (!bytesToWrite) return TRUE;
2027 unix_handle = FILE_GetUnixHandleType( hFile, GENERIC_WRITE, &type, &flags );
2029 if (flags & FD_FLAG_OVERLAPPED)
2031 if (unix_handle == -1) return FALSE;
2032 if ( (overlapped==NULL) || NtResetEvent( overlapped->hEvent, NULL ) )
2034 TRACE("Overlapped not specified or invalid event flag\n");
2035 close(unix_handle);
2036 SetLastError(ERROR_INVALID_PARAMETER);
2037 return FALSE;
2040 close(unix_handle);
2041 overlapped->InternalHigh = 0;
2043 if(!FILE_WriteFileEx(hFile, buffer, bytesToWrite, overlapped, NULL, overlapped->hEvent))
2044 return FALSE;
2046 if ( !GetOverlappedResult (hFile, overlapped, bytesWritten, FALSE) )
2048 if ( GetLastError() == ERROR_IO_INCOMPLETE )
2049 SetLastError ( ERROR_IO_PENDING );
2050 return FALSE;
2053 return TRUE;
2056 switch(type)
2058 case FD_TYPE_CONSOLE:
2059 TRACE("%p %s %ld %p %p\n", hFile, debugstr_an(buffer, bytesToWrite), bytesToWrite,
2060 bytesWritten, overlapped );
2061 return FILE_WriteConsole(hFile, buffer, bytesToWrite, bytesWritten, NULL);
2063 case FD_TYPE_DEFAULT:
2064 if (unix_handle == -1) return FALSE;
2066 if(overlapped)
2068 DWORD highOffset = overlapped->OffsetHigh;
2069 if ( (INVALID_SET_FILE_POINTER == SetFilePointer(hFile, overlapped->Offset,
2070 &highOffset, FILE_BEGIN)) &&
2071 (GetLastError() != NO_ERROR) )
2073 close(unix_handle);
2074 return FALSE;
2077 break;
2079 default:
2080 if (unix_handle == -1)
2081 return FALSE;
2082 if (overlapped)
2084 close(unix_handle);
2085 SetLastError(ERROR_INVALID_PARAMETER);
2086 return FALSE;
2088 break;
2091 if(overlapped)
2093 off_t offset = OVERLAPPED_OFFSET(overlapped);
2094 if(lseek(unix_handle, offset, SEEK_SET) == -1)
2096 close(unix_handle);
2097 SetLastError(ERROR_INVALID_PARAMETER);
2098 return FALSE;
2102 /* synchronous file write */
2103 while ((result = write( unix_handle, buffer, bytesToWrite )) == -1)
2105 if ((errno == EAGAIN) || (errno == EINTR)) continue;
2106 if ((errno == EFAULT) && !IsBadReadPtr( buffer, bytesToWrite )) continue;
2107 if (errno == ENOSPC)
2108 SetLastError( ERROR_DISK_FULL );
2109 else
2110 FILE_SetDosError();
2111 break;
2113 close( unix_handle );
2114 if (result == -1) return FALSE;
2115 if (bytesWritten) *bytesWritten = result;
2116 return TRUE;
2120 /***********************************************************************
2121 * _hread (KERNEL.349)
2123 LONG WINAPI WIN16_hread( HFILE16 hFile, SEGPTR buffer, LONG count )
2125 LONG maxlen;
2127 TRACE("%d %08lx %ld\n",
2128 hFile, (DWORD)buffer, count );
2130 /* Some programs pass a count larger than the allocated buffer */
2131 maxlen = GetSelectorLimit16( SELECTOROF(buffer) ) - OFFSETOF(buffer) + 1;
2132 if (count > maxlen) count = maxlen;
2133 return _lread((HFILE)DosFileHandleToWin32Handle(hFile), MapSL(buffer), count );
2137 /***********************************************************************
2138 * _lread (KERNEL.82)
2140 UINT16 WINAPI WIN16_lread( HFILE16 hFile, SEGPTR buffer, UINT16 count )
2142 return (UINT16)WIN16_hread( hFile, buffer, (LONG)count );
2146 /***********************************************************************
2147 * _lread (KERNEL32.@)
2149 UINT WINAPI _lread( HFILE handle, LPVOID buffer, UINT count )
2151 DWORD result;
2152 if (!ReadFile( (HANDLE)handle, buffer, count, &result, NULL )) return -1;
2153 return result;
2157 /***********************************************************************
2158 * _lread16 (KERNEL.82)
2160 UINT16 WINAPI _lread16( HFILE16 hFile, LPVOID buffer, UINT16 count )
2162 return (UINT16)_lread((HFILE)DosFileHandleToWin32Handle(hFile), buffer, (LONG)count );
2166 /***********************************************************************
2167 * _lcreat (KERNEL.83)
2169 HFILE16 WINAPI _lcreat16( LPCSTR path, INT16 attr )
2171 return Win32HandleToDosFileHandle( (HANDLE)_lcreat( path, attr ) );
2175 /***********************************************************************
2176 * _lcreat (KERNEL32.@)
2178 HFILE WINAPI _lcreat( LPCSTR path, INT attr )
2180 /* Mask off all flags not explicitly allowed by the doc */
2181 attr &= FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM;
2182 TRACE("%s %02x\n", path, attr );
2183 return (HFILE)CreateFileA( path, GENERIC_READ | GENERIC_WRITE,
2184 FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
2185 CREATE_ALWAYS, attr, 0 );
2189 /***********************************************************************
2190 * SetFilePointer (KERNEL32.@)
2192 DWORD WINAPI SetFilePointer( HANDLE hFile, LONG distance, LONG *highword,
2193 DWORD method )
2195 DWORD ret = INVALID_SET_FILE_POINTER;
2197 TRACE("handle %p offset %ld high %ld origin %ld\n",
2198 hFile, distance, highword?*highword:0, method );
2200 SERVER_START_REQ( set_file_pointer )
2202 req->handle = hFile;
2203 req->low = distance;
2204 req->high = highword ? *highword : (distance >= 0) ? 0 : -1;
2205 /* FIXME: assumes 1:1 mapping between Windows and Unix seek constants */
2206 req->whence = method;
2207 SetLastError( 0 );
2208 if (!wine_server_call_err( req ))
2210 ret = reply->new_low;
2211 if (highword) *highword = reply->new_high;
2214 SERVER_END_REQ;
2215 return ret;
2219 /***********************************************************************
2220 * _llseek (KERNEL.84)
2222 * FIXME:
2223 * Seeking before the start of the file should be allowed for _llseek16,
2224 * but cause subsequent I/O operations to fail (cf. interrupt list)
2227 LONG WINAPI _llseek16( HFILE16 hFile, LONG lOffset, INT16 nOrigin )
2229 return SetFilePointer( DosFileHandleToWin32Handle(hFile), lOffset, NULL, nOrigin );
2233 /***********************************************************************
2234 * _llseek (KERNEL32.@)
2236 LONG WINAPI _llseek( HFILE hFile, LONG lOffset, INT nOrigin )
2238 return SetFilePointer( (HANDLE)hFile, lOffset, NULL, nOrigin );
2242 /***********************************************************************
2243 * _lopen (KERNEL.85)
2245 HFILE16 WINAPI _lopen16( LPCSTR path, INT16 mode )
2247 return Win32HandleToDosFileHandle( (HANDLE)_lopen( path, mode ) );
2251 /***********************************************************************
2252 * _lopen (KERNEL32.@)
2254 HFILE WINAPI _lopen( LPCSTR path, INT mode )
2256 DWORD access, sharing;
2258 TRACE("('%s',%04x)\n", path, mode );
2259 FILE_ConvertOFMode( mode, &access, &sharing );
2260 return (HFILE)CreateFileA( path, access, sharing, NULL, OPEN_EXISTING, 0, 0 );
2264 /***********************************************************************
2265 * _lwrite (KERNEL.86)
2267 UINT16 WINAPI _lwrite16( HFILE16 hFile, LPCSTR buffer, UINT16 count )
2269 return (UINT16)_hwrite( (HFILE)DosFileHandleToWin32Handle(hFile), buffer, (LONG)count );
2272 /***********************************************************************
2273 * _lwrite (KERNEL32.@)
2275 UINT WINAPI _lwrite( HFILE hFile, LPCSTR buffer, UINT count )
2277 return (UINT)_hwrite( hFile, buffer, (LONG)count );
2281 /***********************************************************************
2282 * _hread16 (KERNEL.349)
2284 LONG WINAPI _hread16( HFILE16 hFile, LPVOID buffer, LONG count)
2286 return _lread( (HFILE)DosFileHandleToWin32Handle(hFile), buffer, count );
2290 /***********************************************************************
2291 * _hread (KERNEL32.@)
2293 LONG WINAPI _hread( HFILE hFile, LPVOID buffer, LONG count)
2295 return _lread( hFile, buffer, count );
2299 /***********************************************************************
2300 * _hwrite (KERNEL.350)
2302 LONG WINAPI _hwrite16( HFILE16 hFile, LPCSTR buffer, LONG count )
2304 return _hwrite( (HFILE)DosFileHandleToWin32Handle(hFile), buffer, count );
2308 /***********************************************************************
2309 * _hwrite (KERNEL32.@)
2311 * experimentation yields that _lwrite:
2312 * o truncates the file at the current position with
2313 * a 0 len write
2314 * o returns 0 on a 0 length write
2315 * o works with console handles
2318 LONG WINAPI _hwrite( HFILE handle, LPCSTR buffer, LONG count )
2320 DWORD result;
2322 TRACE("%d %p %ld\n", handle, buffer, count );
2324 if (!count)
2326 /* Expand or truncate at current position */
2327 if (!SetEndOfFile( (HANDLE)handle )) return HFILE_ERROR;
2328 return 0;
2330 if (!WriteFile( (HANDLE)handle, buffer, count, &result, NULL ))
2331 return HFILE_ERROR;
2332 return result;
2336 /***********************************************************************
2337 * SetHandleCount (KERNEL.199)
2339 UINT16 WINAPI SetHandleCount16( UINT16 count )
2341 return SetHandleCount( count );
2345 /*************************************************************************
2346 * SetHandleCount (KERNEL32.@)
2348 UINT WINAPI SetHandleCount( UINT count )
2350 return min( 256, count );
2354 /***********************************************************************
2355 * FlushFileBuffers (KERNEL32.@)
2357 BOOL WINAPI FlushFileBuffers( HANDLE hFile )
2359 BOOL ret;
2360 SERVER_START_REQ( flush_file )
2362 req->handle = hFile;
2363 ret = !wine_server_call_err( req );
2365 SERVER_END_REQ;
2366 return ret;
2370 /**************************************************************************
2371 * SetEndOfFile (KERNEL32.@)
2373 BOOL WINAPI SetEndOfFile( HANDLE hFile )
2375 BOOL ret;
2376 SERVER_START_REQ( truncate_file )
2378 req->handle = hFile;
2379 ret = !wine_server_call_err( req );
2381 SERVER_END_REQ;
2382 return ret;
2386 /***********************************************************************
2387 * DeleteFile (KERNEL.146)
2389 BOOL16 WINAPI DeleteFile16( LPCSTR path )
2391 return DeleteFileA( path );
2395 /***********************************************************************
2396 * DeleteFileW (KERNEL32.@)
2398 BOOL WINAPI DeleteFileW( LPCWSTR path )
2400 DOS_FULL_NAME full_name;
2401 HANDLE hFile;
2403 TRACE("%s\n", debugstr_w(path) );
2404 if (!path || !*path)
2406 SetLastError(ERROR_PATH_NOT_FOUND);
2407 return FALSE;
2409 if (DOSFS_GetDevice( path ))
2411 WARN("cannot remove DOS device %s!\n", debugstr_w(path));
2412 SetLastError( ERROR_FILE_NOT_FOUND );
2413 return FALSE;
2416 if (!DOSFS_GetFullName( path, TRUE, &full_name )) return FALSE;
2418 /* check if we are allowed to delete the source */
2419 hFile = FILE_CreateFile( full_name.long_name, GENERIC_READ|GENERIC_WRITE, 0,
2420 NULL, OPEN_EXISTING, 0, 0, TRUE,
2421 GetDriveTypeW( full_name.short_name ) );
2422 if (!hFile) return FALSE;
2424 if (unlink( full_name.long_name ) == -1)
2426 FILE_SetDosError();
2427 CloseHandle(hFile);
2428 return FALSE;
2430 CloseHandle(hFile);
2431 return TRUE;
2435 /***********************************************************************
2436 * DeleteFileA (KERNEL32.@)
2438 BOOL WINAPI DeleteFileA( LPCSTR path )
2440 UNICODE_STRING pathW;
2441 BOOL ret = FALSE;
2443 if (!path)
2445 SetLastError(ERROR_INVALID_PARAMETER);
2446 return FALSE;
2449 if (RtlCreateUnicodeStringFromAsciiz(&pathW, path))
2451 ret = DeleteFileW(pathW.Buffer);
2452 RtlFreeUnicodeString(&pathW);
2454 else
2455 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
2456 return ret;
2460 /***********************************************************************
2461 * GetFileType (KERNEL32.@)
2463 DWORD WINAPI GetFileType( HANDLE hFile )
2465 DWORD ret = FILE_TYPE_UNKNOWN;
2466 SERVER_START_REQ( get_file_info )
2468 req->handle = hFile;
2469 if (!wine_server_call_err( req )) ret = reply->type;
2471 SERVER_END_REQ;
2472 return ret;
2476 /* check if a file name is for an executable file (.exe or .com) */
2477 inline static BOOL is_executable( const char *name )
2479 int len = strlen(name);
2481 if (len < 4) return FALSE;
2482 return (!strcasecmp( name + len - 4, ".exe" ) ||
2483 !strcasecmp( name + len - 4, ".com" ));
2487 /***********************************************************************
2488 * FILE_AddBootRenameEntry
2490 * Adds an entry to the registry that is loaded when windows boots and
2491 * checks if there are some files to be removed or renamed/moved.
2492 * <fn1> has to be valid and <fn2> may be NULL. If both pointers are
2493 * non-NULL then the file is moved, otherwise it is deleted. The
2494 * entry of the registrykey is always appended with two zero
2495 * terminated strings. If <fn2> is NULL then the second entry is
2496 * simply a single 0-byte. Otherwise the second filename goes
2497 * there. The entries are prepended with \??\ before the path and the
2498 * second filename gets also a '!' as the first character if
2499 * MOVEFILE_REPLACE_EXISTING is set. After the final string another
2500 * 0-byte follows to indicate the end of the strings.
2501 * i.e.:
2502 * \??\D:\test\file1[0]
2503 * !\??\D:\test\file1_renamed[0]
2504 * \??\D:\Test|delete[0]
2505 * [0] <- file is to be deleted, second string empty
2506 * \??\D:\test\file2[0]
2507 * !\??\D:\test\file2_renamed[0]
2508 * [0] <- indicates end of strings
2510 * or:
2511 * \??\D:\test\file1[0]
2512 * !\??\D:\test\file1_renamed[0]
2513 * \??\D:\Test|delete[0]
2514 * [0] <- file is to be deleted, second string empty
2515 * [0] <- indicates end of strings
2518 static BOOL FILE_AddBootRenameEntry( LPCWSTR fn1, LPCWSTR fn2, DWORD flags )
2520 static const WCHAR PreString[] = {'\\','?','?','\\',0};
2521 static const WCHAR ValueName[] = {'P','e','n','d','i','n','g',
2522 'F','i','l','e','R','e','n','a','m','e',
2523 'O','p','e','r','a','t','i','o','n','s',0};
2524 static const WCHAR SessionW[] = {'M','a','c','h','i','n','e','\\',
2525 'S','y','s','t','e','m','\\',
2526 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
2527 'C','o','n','t','r','o','l','\\',
2528 'S','e','s','s','i','o','n',' ','M','a','n','a','g','e','r',0};
2529 static const int info_size = FIELD_OFFSET( KEY_VALUE_PARTIAL_INFORMATION, Data );
2531 OBJECT_ATTRIBUTES attr;
2532 UNICODE_STRING nameW;
2533 KEY_VALUE_PARTIAL_INFORMATION *info;
2534 BOOL rc = FALSE;
2535 HKEY Reboot = 0;
2536 DWORD len0, len1, len2;
2537 DWORD DataSize = 0;
2538 BYTE *Buffer = NULL;
2539 WCHAR *p;
2541 attr.Length = sizeof(attr);
2542 attr.RootDirectory = 0;
2543 attr.ObjectName = &nameW;
2544 attr.Attributes = 0;
2545 attr.SecurityDescriptor = NULL;
2546 attr.SecurityQualityOfService = NULL;
2547 RtlInitUnicodeString( &nameW, SessionW );
2549 if (NtCreateKey( &Reboot, KEY_ALL_ACCESS, &attr, 0, NULL, 0, NULL ) != STATUS_SUCCESS)
2551 WARN("Error creating key for reboot managment [%s]\n",
2552 "SYSTEM\\CurrentControlSet\\Control\\Session Manager");
2553 return FALSE;
2556 len0 = strlenW(PreString);
2557 len1 = strlenW(fn1) + len0 + 1;
2558 if (fn2)
2560 len2 = strlenW(fn2) + len0 + 1;
2561 if (flags & MOVEFILE_REPLACE_EXISTING) len2++; /* Plus 1 because of the leading '!' */
2563 else len2 = 1; /* minimum is the 0 characters for the empty second string */
2565 /* convert characters to bytes */
2566 len0 *= sizeof(WCHAR);
2567 len1 *= sizeof(WCHAR);
2568 len2 *= sizeof(WCHAR);
2570 RtlInitUnicodeString( &nameW, ValueName );
2572 /* First we check if the key exists and if so how many bytes it already contains. */
2573 if (NtQueryValueKey( Reboot, &nameW, KeyValuePartialInformation,
2574 NULL, 0, &DataSize ) == STATUS_BUFFER_OVERFLOW)
2576 if (!(Buffer = HeapAlloc( GetProcessHeap(), 0, DataSize + len1 + len2 + sizeof(WCHAR) )))
2577 goto Quit;
2578 if (NtQueryValueKey( Reboot, &nameW, KeyValuePartialInformation,
2579 Buffer, DataSize, &DataSize )) goto Quit;
2580 info = (KEY_VALUE_PARTIAL_INFORMATION *)Buffer;
2581 if (info->Type != REG_MULTI_SZ) goto Quit;
2582 if (DataSize > sizeof(info)) DataSize -= sizeof(WCHAR); /* remove terminating null (will be added back later) */
2584 else
2586 DataSize = info_size;
2587 if (!(Buffer = HeapAlloc( GetProcessHeap(), 0, DataSize + len1 + len2 + sizeof(WCHAR) )))
2588 goto Quit;
2591 p = (WCHAR *)(Buffer + DataSize);
2592 strcpyW( p, PreString );
2593 strcatW( p, fn1 );
2594 DataSize += len1;
2595 if (fn2)
2597 p = (WCHAR *)(Buffer + DataSize);
2598 if (flags & MOVEFILE_REPLACE_EXISTING)
2599 *p++ = '!';
2600 strcpyW( p, PreString );
2601 strcatW( p, fn2 );
2602 DataSize += len2;
2604 else
2606 p = (WCHAR *)(Buffer + DataSize);
2607 *p = 0;
2608 DataSize += sizeof(WCHAR);
2611 /* add final null */
2612 p = (WCHAR *)(Buffer + DataSize);
2613 *p = 0;
2614 DataSize += sizeof(WCHAR);
2616 rc = !NtSetValueKey(Reboot, &nameW, 0, REG_MULTI_SZ, Buffer + info_size, DataSize - info_size);
2618 Quit:
2619 if (Reboot) NtClose(Reboot);
2620 if (Buffer) HeapFree( GetProcessHeap(), 0, Buffer );
2621 return(rc);
2625 /**************************************************************************
2626 * MoveFileExW (KERNEL32.@)
2628 BOOL WINAPI MoveFileExW( LPCWSTR fn1, LPCWSTR fn2, DWORD flag )
2630 DOS_FULL_NAME full_name1, full_name2;
2631 HANDLE hFile;
2632 DWORD attr = INVALID_FILE_ATTRIBUTES;
2634 TRACE("(%s,%s,%04lx)\n", debugstr_w(fn1), debugstr_w(fn2), flag);
2636 /* FIXME: <Gerhard W. Gruber>sparhawk@gmx.at
2637 In case of W9x and lesser this function should return 120 (ERROR_CALL_NOT_IMPLEMENTED)
2638 to be really compatible. Most programs wont have any problems though. In case
2639 you encounter one, this is what you should return here. I don't know what's up
2640 with NT 3.5. Is this function available there or not?
2641 Does anybody really care about 3.5? :)
2644 /* Filename1 has to be always set to a valid path. Filename2 may be NULL
2645 if the source file has to be deleted.
2647 if (!fn1) {
2648 SetLastError(ERROR_INVALID_PARAMETER);
2649 return FALSE;
2652 /* This function has to be run through in order to process the name properly.
2653 If the BOOTDELAY flag is set, the file doesn't need to exist though. At least
2654 that is the behaviour on NT 4.0. The operation accepts the filenames as
2655 they are given but it can't reply with a reasonable returncode. Success
2656 means in that case success for entering the values into the registry.
2658 if(!DOSFS_GetFullName( fn1, TRUE, &full_name1 ))
2660 if(!(flag & MOVEFILE_DELAY_UNTIL_REBOOT))
2661 return FALSE;
2664 if (fn2) /* !fn2 means delete fn1 */
2666 if (DOSFS_GetFullName( fn2, TRUE, &full_name2 ))
2668 if(!(flag & MOVEFILE_DELAY_UNTIL_REBOOT))
2670 /* target exists, check if we may overwrite */
2671 if (!(flag & MOVEFILE_REPLACE_EXISTING))
2673 SetLastError( ERROR_FILE_EXISTS );
2674 return FALSE;
2678 else
2680 if (!DOSFS_GetFullName( fn2, FALSE, &full_name2 ))
2682 if(!(flag & MOVEFILE_DELAY_UNTIL_REBOOT))
2683 return FALSE;
2687 /* Source name and target path are valid */
2689 if (flag & MOVEFILE_DELAY_UNTIL_REBOOT)
2691 /* FIXME: (bon@elektron.ikp.physik.th-darmstadt.de 970706)
2692 Perhaps we should queue these command and execute it
2693 when exiting... What about using on_exit(2)
2695 FIXME("Please move existing file %s to file %s when Wine has finished\n",
2696 debugstr_w(fn1), debugstr_w(fn2));
2697 return FILE_AddBootRenameEntry( fn1, fn2, flag );
2700 attr = GetFileAttributesW( fn1 );
2701 if ( attr == INVALID_FILE_ATTRIBUTES ) return FALSE;
2703 /* check if we are allowed to rename the source */
2704 hFile = FILE_CreateFile( full_name1.long_name, 0, 0,
2705 NULL, OPEN_EXISTING, 0, 0, TRUE,
2706 GetDriveTypeW( full_name1.short_name ) );
2707 if (!hFile)
2709 if (GetLastError() != ERROR_ACCESS_DENIED) return FALSE;
2710 if ( !(attr & FILE_ATTRIBUTE_DIRECTORY) ) return FALSE;
2711 /* if it's a directory we can continue */
2713 else CloseHandle(hFile);
2715 /* check, if we are allowed to delete the destination,
2716 ** (but the file not being there is fine) */
2717 hFile = FILE_CreateFile( full_name2.long_name, GENERIC_READ|GENERIC_WRITE, 0,
2718 NULL, OPEN_EXISTING, 0, 0, TRUE,
2719 GetDriveTypeW( full_name2.short_name ) );
2720 if(!hFile && GetLastError() != ERROR_FILE_NOT_FOUND) return FALSE;
2721 CloseHandle(hFile);
2723 if (full_name1.drive != full_name2.drive)
2725 if (!(flag & MOVEFILE_COPY_ALLOWED))
2727 SetLastError( ERROR_NOT_SAME_DEVICE );
2728 return FALSE;
2730 else if ( attr & FILE_ATTRIBUTE_DIRECTORY )
2732 /* Strange, but that's what Windows returns */
2733 SetLastError ( ERROR_ACCESS_DENIED );
2734 return FALSE;
2737 if (rename( full_name1.long_name, full_name2.long_name ) == -1)
2738 /* Try copy/delete unless it's a directory. */
2739 /* FIXME: This does not handle the (unlikely) case that the two locations
2740 are on the same Wine drive, but on different Unix file systems. */
2742 if ( attr & FILE_ATTRIBUTE_DIRECTORY )
2744 FILE_SetDosError();
2745 return FALSE;
2747 else
2749 if ( ! CopyFileW( fn1, fn2, !(flag & MOVEFILE_REPLACE_EXISTING) ))
2750 return FALSE;
2751 if ( ! DeleteFileW ( fn1 ) )
2752 return FALSE;
2755 if (is_executable( full_name1.long_name ) != is_executable( full_name2.long_name ))
2757 struct stat fstat;
2758 if (stat( full_name2.long_name, &fstat ) != -1)
2760 if (is_executable( full_name2.long_name ))
2761 /* set executable bit where read bit is set */
2762 fstat.st_mode |= (fstat.st_mode & 0444) >> 2;
2763 else
2764 fstat.st_mode &= ~0111;
2765 chmod( full_name2.long_name, fstat.st_mode );
2768 return TRUE;
2770 else /* fn2 == NULL means delete source */
2772 if (flag & MOVEFILE_DELAY_UNTIL_REBOOT)
2774 if (flag & MOVEFILE_COPY_ALLOWED) {
2775 WARN("Illegal flag\n");
2776 SetLastError( ERROR_GEN_FAILURE );
2777 return FALSE;
2779 /* FIXME: (bon@elektron.ikp.physik.th-darmstadt.de 970706)
2780 Perhaps we should queue these command and execute it
2781 when exiting... What about using on_exit(2)
2783 FIXME("Please delete file %s when Wine has finished\n", debugstr_w(fn1));
2784 return FILE_AddBootRenameEntry( fn1, NULL, flag );
2787 if (unlink( full_name1.long_name ) == -1)
2789 FILE_SetDosError();
2790 return FALSE;
2792 return TRUE; /* successfully deleted */
2796 /**************************************************************************
2797 * MoveFileExA (KERNEL32.@)
2799 BOOL WINAPI MoveFileExA( LPCSTR fn1, LPCSTR fn2, DWORD flag )
2801 UNICODE_STRING fn1W, fn2W;
2802 BOOL ret;
2804 if (!fn1)
2806 SetLastError(ERROR_INVALID_PARAMETER);
2807 return FALSE;
2810 RtlCreateUnicodeStringFromAsciiz(&fn1W, fn1);
2811 if (fn2) RtlCreateUnicodeStringFromAsciiz(&fn2W, fn2);
2812 else fn2W.Buffer = NULL;
2814 ret = MoveFileExW( fn1W.Buffer, fn2W.Buffer, flag );
2816 RtlFreeUnicodeString(&fn1W);
2817 RtlFreeUnicodeString(&fn2W);
2818 return ret;
2822 /**************************************************************************
2823 * MoveFileW (KERNEL32.@)
2825 * Move file or directory
2827 BOOL WINAPI MoveFileW( LPCWSTR fn1, LPCWSTR fn2 )
2829 DOS_FULL_NAME full_name1, full_name2;
2830 struct stat fstat;
2832 if (!fn1 || !fn2)
2834 SetLastError(ERROR_INVALID_PARAMETER);
2835 return FALSE;
2838 TRACE("(%s,%s)\n", debugstr_w(fn1), debugstr_w(fn2) );
2840 if (!DOSFS_GetFullName( fn1, TRUE, &full_name1 )) return FALSE;
2841 if (DOSFS_GetFullName( fn2, TRUE, &full_name2 )) {
2842 /* The new name must not already exist */
2843 SetLastError(ERROR_ALREADY_EXISTS);
2844 return FALSE;
2846 if (!DOSFS_GetFullName( fn2, FALSE, &full_name2 )) return FALSE;
2848 if (full_name1.drive == full_name2.drive) /* move */
2849 return MoveFileExW( fn1, fn2, MOVEFILE_COPY_ALLOWED );
2851 /* copy */
2852 if (stat( full_name1.long_name, &fstat ))
2854 WARN("Invalid source file %s\n",
2855 full_name1.long_name);
2856 FILE_SetDosError();
2857 return FALSE;
2859 if (S_ISDIR(fstat.st_mode)) {
2860 /* No Move for directories across file systems */
2861 /* FIXME: Use right error code */
2862 SetLastError( ERROR_GEN_FAILURE );
2863 return FALSE;
2865 return CopyFileW(fn1, fn2, TRUE); /*fail, if exist */
2869 /**************************************************************************
2870 * MoveFileA (KERNEL32.@)
2872 BOOL WINAPI MoveFileA( LPCSTR fn1, LPCSTR fn2 )
2874 UNICODE_STRING fn1W, fn2W;
2875 BOOL ret;
2877 if (!fn1 || !fn2)
2879 SetLastError(ERROR_INVALID_PARAMETER);
2880 return FALSE;
2883 RtlCreateUnicodeStringFromAsciiz(&fn1W, fn1);
2884 RtlCreateUnicodeStringFromAsciiz(&fn2W, fn2);
2886 ret = MoveFileW( fn1W.Buffer, fn2W.Buffer );
2888 RtlFreeUnicodeString(&fn1W);
2889 RtlFreeUnicodeString(&fn2W);
2890 return ret;
2894 /**************************************************************************
2895 * CopyFileW (KERNEL32.@)
2897 BOOL WINAPI CopyFileW( LPCWSTR source, LPCWSTR dest, BOOL fail_if_exists )
2899 HANDLE h1, h2;
2900 BY_HANDLE_FILE_INFORMATION info;
2901 DWORD count;
2902 BOOL ret = FALSE;
2903 char buffer[2048];
2905 if (!source || !dest)
2907 SetLastError(ERROR_INVALID_PARAMETER);
2908 return FALSE;
2911 TRACE("%s -> %s\n", debugstr_w(source), debugstr_w(dest));
2913 if ((h1 = CreateFileW(source, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE,
2914 NULL, OPEN_EXISTING, 0, 0)) == INVALID_HANDLE_VALUE)
2916 WARN("Unable to open source %s\n", debugstr_w(source));
2917 return FALSE;
2920 if (!GetFileInformationByHandle( h1, &info ))
2922 WARN("GetFileInformationByHandle returned error for %s\n", debugstr_w(source));
2923 CloseHandle( h1 );
2924 return FALSE;
2927 if ((h2 = CreateFileW( dest, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
2928 fail_if_exists ? CREATE_NEW : CREATE_ALWAYS,
2929 info.dwFileAttributes, h1 )) == INVALID_HANDLE_VALUE)
2931 WARN("Unable to open dest %s\n", debugstr_w(dest));
2932 CloseHandle( h1 );
2933 return FALSE;
2936 while (ReadFile( h1, buffer, sizeof(buffer), &count, NULL ) && count)
2938 char *p = buffer;
2939 while (count != 0)
2941 DWORD res;
2942 if (!WriteFile( h2, p, count, &res, NULL ) || !res) goto done;
2943 p += res;
2944 count -= res;
2947 ret = TRUE;
2948 done:
2949 CloseHandle( h1 );
2950 CloseHandle( h2 );
2951 return ret;
2955 /**************************************************************************
2956 * CopyFileA (KERNEL32.@)
2958 BOOL WINAPI CopyFileA( LPCSTR source, LPCSTR dest, BOOL fail_if_exists)
2960 UNICODE_STRING sourceW, destW;
2961 BOOL ret;
2963 if (!source || !dest)
2965 SetLastError(ERROR_INVALID_PARAMETER);
2966 return FALSE;
2969 RtlCreateUnicodeStringFromAsciiz(&sourceW, source);
2970 RtlCreateUnicodeStringFromAsciiz(&destW, dest);
2972 ret = CopyFileW(sourceW.Buffer, destW.Buffer, fail_if_exists);
2974 RtlFreeUnicodeString(&sourceW);
2975 RtlFreeUnicodeString(&destW);
2976 return ret;
2980 /**************************************************************************
2981 * CopyFileExW (KERNEL32.@)
2983 * This implementation ignores most of the extra parameters passed-in into
2984 * the "ex" version of the method and calls the CopyFile method.
2985 * It will have to be fixed eventually.
2987 BOOL WINAPI CopyFileExW(LPCWSTR sourceFilename, LPCWSTR destFilename,
2988 LPPROGRESS_ROUTINE progressRoutine, LPVOID appData,
2989 LPBOOL cancelFlagPointer, DWORD copyFlags)
2992 * Interpret the only flag that CopyFile can interpret.
2994 return CopyFileW(sourceFilename, destFilename, (copyFlags & COPY_FILE_FAIL_IF_EXISTS) != 0);
2997 /**************************************************************************
2998 * CopyFileExA (KERNEL32.@)
3000 BOOL WINAPI CopyFileExA(LPCSTR sourceFilename, LPCSTR destFilename,
3001 LPPROGRESS_ROUTINE progressRoutine, LPVOID appData,
3002 LPBOOL cancelFlagPointer, DWORD copyFlags)
3004 UNICODE_STRING sourceW, destW;
3005 BOOL ret;
3007 if (!sourceFilename || !destFilename)
3009 SetLastError(ERROR_INVALID_PARAMETER);
3010 return FALSE;
3013 RtlCreateUnicodeStringFromAsciiz(&sourceW, sourceFilename);
3014 RtlCreateUnicodeStringFromAsciiz(&destW, destFilename);
3016 ret = CopyFileExW(sourceW.Buffer, destW.Buffer, progressRoutine, appData,
3017 cancelFlagPointer, copyFlags);
3019 RtlFreeUnicodeString(&sourceW);
3020 RtlFreeUnicodeString(&destW);
3021 return ret;
3025 /***********************************************************************
3026 * SetFileTime (KERNEL32.@)
3028 BOOL WINAPI SetFileTime( HANDLE hFile,
3029 const FILETIME *lpCreationTime,
3030 const FILETIME *lpLastAccessTime,
3031 const FILETIME *lpLastWriteTime )
3033 BOOL ret;
3034 SERVER_START_REQ( set_file_time )
3036 req->handle = hFile;
3037 if (lpLastAccessTime)
3038 RtlTimeToSecondsSince1970( (PLARGE_INTEGER) lpLastAccessTime, (DWORD *)&req->access_time );
3039 else
3040 req->access_time = 0; /* FIXME */
3041 if (lpLastWriteTime)
3042 RtlTimeToSecondsSince1970( (PLARGE_INTEGER) lpLastWriteTime, (DWORD *)&req->write_time );
3043 else
3044 req->write_time = 0; /* FIXME */
3045 ret = !wine_server_call_err( req );
3047 SERVER_END_REQ;
3048 return ret;
3052 /**************************************************************************
3053 * LockFile (KERNEL32.@)
3055 BOOL WINAPI LockFile( HANDLE hFile, DWORD dwFileOffsetLow, DWORD dwFileOffsetHigh,
3056 DWORD nNumberOfBytesToLockLow, DWORD nNumberOfBytesToLockHigh )
3058 BOOL ret;
3060 FIXME("not implemented in server\n");
3062 SERVER_START_REQ( lock_file )
3064 req->handle = hFile;
3065 req->offset_low = dwFileOffsetLow;
3066 req->offset_high = dwFileOffsetHigh;
3067 req->count_low = nNumberOfBytesToLockLow;
3068 req->count_high = nNumberOfBytesToLockHigh;
3069 ret = !wine_server_call_err( req );
3071 SERVER_END_REQ;
3072 return ret;
3075 /**************************************************************************
3076 * LockFileEx [KERNEL32.@]
3078 * Locks a byte range within an open file for shared or exclusive access.
3080 * RETURNS
3081 * success: TRUE
3082 * failure: FALSE
3084 * NOTES
3085 * Per Microsoft docs, the third parameter (reserved) must be set to 0.
3087 BOOL WINAPI LockFileEx( HANDLE hFile, DWORD flags, DWORD reserved,
3088 DWORD nNumberOfBytesToLockLow, DWORD nNumberOfBytesToLockHigh,
3089 LPOVERLAPPED pOverlapped )
3091 FIXME("hFile=%p,flags=%ld,reserved=%ld,lowbytes=%ld,highbytes=%ld,overlapped=%p: stub.\n",
3092 hFile, flags, reserved, nNumberOfBytesToLockLow, nNumberOfBytesToLockHigh,
3093 pOverlapped);
3094 if (reserved == 0)
3095 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
3096 else
3098 ERR("reserved == %ld: Supposed to be 0??\n", reserved);
3099 SetLastError(ERROR_INVALID_PARAMETER);
3102 return FALSE;
3106 /**************************************************************************
3107 * UnlockFile (KERNEL32.@)
3109 BOOL WINAPI UnlockFile( HANDLE hFile, DWORD dwFileOffsetLow, DWORD dwFileOffsetHigh,
3110 DWORD nNumberOfBytesToUnlockLow, DWORD nNumberOfBytesToUnlockHigh )
3112 BOOL ret;
3114 FIXME("not implemented in server\n");
3116 SERVER_START_REQ( unlock_file )
3118 req->handle = hFile;
3119 req->offset_low = dwFileOffsetLow;
3120 req->offset_high = dwFileOffsetHigh;
3121 req->count_low = nNumberOfBytesToUnlockLow;
3122 req->count_high = nNumberOfBytesToUnlockHigh;
3123 ret = !wine_server_call_err( req );
3125 SERVER_END_REQ;
3126 return ret;
3130 /**************************************************************************
3131 * UnlockFileEx (KERNEL32.@)
3133 BOOL WINAPI UnlockFileEx(
3134 HANDLE hFile,
3135 DWORD dwReserved,
3136 DWORD nNumberOfBytesToUnlockLow,
3137 DWORD nNumberOfBytesToUnlockHigh,
3138 LPOVERLAPPED lpOverlapped
3141 FIXME("hFile=%p,reserved=%ld,lowbytes=%ld,highbytes=%ld,overlapped=%p: stub.\n",
3142 hFile, dwReserved, nNumberOfBytesToUnlockLow, nNumberOfBytesToUnlockHigh,
3143 lpOverlapped);
3144 if (dwReserved == 0)
3145 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
3146 else
3148 ERR("reserved == %ld: Supposed to be 0??\n", dwReserved);
3149 SetLastError(ERROR_INVALID_PARAMETER);
3152 return FALSE;
3156 #if 0
3158 struct DOS_FILE_LOCK {
3159 struct DOS_FILE_LOCK * next;
3160 DWORD base;
3161 DWORD len;
3162 DWORD processId;
3163 FILE_OBJECT * dos_file;
3164 /* char * unix_name;*/
3167 typedef struct DOS_FILE_LOCK DOS_FILE_LOCK;
3169 static DOS_FILE_LOCK *locks = NULL;
3170 static void DOS_RemoveFileLocks(FILE_OBJECT *file);
3173 /* Locks need to be mirrored because unix file locking is based
3174 * on the pid. Inside of wine there can be multiple WINE processes
3175 * that share the same unix pid.
3176 * Read's and writes should check these locks also - not sure
3177 * how critical that is at this point (FIXME).
3180 static BOOL DOS_AddLock(FILE_OBJECT *file, struct flock *f)
3182 DOS_FILE_LOCK *curr;
3183 DWORD processId;
3185 processId = GetCurrentProcessId();
3187 /* check if lock overlaps a current lock for the same file */
3188 #if 0
3189 for (curr = locks; curr; curr = curr->next) {
3190 if (strcmp(curr->unix_name, file->unix_name) == 0) {
3191 if ((f->l_start == curr->base) && (f->l_len == curr->len))
3192 return TRUE;/* region is identic */
3193 if ((f->l_start < (curr->base + curr->len)) &&
3194 ((f->l_start + f->l_len) > curr->base)) {
3195 /* region overlaps */
3196 return FALSE;
3200 #endif
3202 curr = HeapAlloc( GetProcessHeap(), 0, sizeof(DOS_FILE_LOCK) );
3203 curr->processId = GetCurrentProcessId();
3204 curr->base = f->l_start;
3205 curr->len = f->l_len;
3206 /* curr->unix_name = HEAP_strdupA( GetProcessHeap(), 0, file->unix_name);*/
3207 curr->next = locks;
3208 curr->dos_file = file;
3209 locks = curr;
3210 return TRUE;
3213 static void DOS_RemoveFileLocks(FILE_OBJECT *file)
3215 DWORD processId;
3216 DOS_FILE_LOCK **curr;
3217 DOS_FILE_LOCK *rem;
3219 processId = GetCurrentProcessId();
3220 curr = &locks;
3221 while (*curr) {
3222 if ((*curr)->dos_file == file) {
3223 rem = *curr;
3224 *curr = (*curr)->next;
3225 /* HeapFree( GetProcessHeap(), 0, rem->unix_name );*/
3226 HeapFree( GetProcessHeap(), 0, rem );
3228 else
3229 curr = &(*curr)->next;
3233 static BOOL DOS_RemoveLock(FILE_OBJECT *file, struct flock *f)
3235 DWORD processId;
3236 DOS_FILE_LOCK **curr;
3237 DOS_FILE_LOCK *rem;
3239 processId = GetCurrentProcessId();
3240 for (curr = &locks; *curr; curr = &(*curr)->next) {
3241 if ((*curr)->processId == processId &&
3242 (*curr)->dos_file == file &&
3243 (*curr)->base == f->l_start &&
3244 (*curr)->len == f->l_len) {
3245 /* this is the same lock */
3246 rem = *curr;
3247 *curr = (*curr)->next;
3248 /* HeapFree( GetProcessHeap(), 0, rem->unix_name );*/
3249 HeapFree( GetProcessHeap(), 0, rem );
3250 return TRUE;
3253 /* no matching lock found */
3254 return FALSE;
3258 /**************************************************************************
3259 * LockFile (KERNEL32.@)
3261 BOOL WINAPI LockFile(
3262 HANDLE hFile,DWORD dwFileOffsetLow,DWORD dwFileOffsetHigh,
3263 DWORD nNumberOfBytesToLockLow,DWORD nNumberOfBytesToLockHigh )
3265 struct flock f;
3266 FILE_OBJECT *file;
3268 TRACE("handle %d offsetlow=%ld offsethigh=%ld nbyteslow=%ld nbyteshigh=%ld\n",
3269 hFile, dwFileOffsetLow, dwFileOffsetHigh,
3270 nNumberOfBytesToLockLow, nNumberOfBytesToLockHigh);
3272 if (dwFileOffsetHigh || nNumberOfBytesToLockHigh) {
3273 FIXME("Unimplemented bytes > 32bits\n");
3274 return FALSE;
3277 f.l_start = dwFileOffsetLow;
3278 f.l_len = nNumberOfBytesToLockLow;
3279 f.l_whence = SEEK_SET;
3280 f.l_pid = 0;
3281 f.l_type = F_WRLCK;
3283 if (!(file = FILE_GetFile(hFile,0,NULL))) return FALSE;
3285 /* shadow locks internally */
3286 if (!DOS_AddLock(file, &f)) {
3287 SetLastError( ERROR_LOCK_VIOLATION );
3288 return FALSE;
3291 /* FIXME: Unix locking commented out for now, doesn't work with Excel */
3292 #ifdef USE_UNIX_LOCKS
3293 if (fcntl(file->unix_handle, F_SETLK, &f) == -1) {
3294 if (errno == EACCES || errno == EAGAIN) {
3295 SetLastError( ERROR_LOCK_VIOLATION );
3297 else {
3298 FILE_SetDosError();
3300 /* remove our internal copy of the lock */
3301 DOS_RemoveLock(file, &f);
3302 return FALSE;
3304 #endif
3305 return TRUE;
3309 /**************************************************************************
3310 * UnlockFile (KERNEL32.@)
3312 BOOL WINAPI UnlockFile(
3313 HANDLE hFile,DWORD dwFileOffsetLow,DWORD dwFileOffsetHigh,
3314 DWORD nNumberOfBytesToUnlockLow,DWORD nNumberOfBytesToUnlockHigh )
3316 FILE_OBJECT *file;
3317 struct flock f;
3319 TRACE("handle %d offsetlow=%ld offsethigh=%ld nbyteslow=%ld nbyteshigh=%ld\n",
3320 hFile, dwFileOffsetLow, dwFileOffsetHigh,
3321 nNumberOfBytesToUnlockLow, nNumberOfBytesToUnlockHigh);
3323 if (dwFileOffsetHigh || nNumberOfBytesToUnlockHigh) {
3324 WARN("Unimplemented bytes > 32bits\n");
3325 return FALSE;
3328 f.l_start = dwFileOffsetLow;
3329 f.l_len = nNumberOfBytesToUnlockLow;
3330 f.l_whence = SEEK_SET;
3331 f.l_pid = 0;
3332 f.l_type = F_UNLCK;
3334 if (!(file = FILE_GetFile(hFile,0,NULL))) return FALSE;
3336 DOS_RemoveLock(file, &f); /* ok if fails - may be another wine */
3338 /* FIXME: Unix locking commented out for now, doesn't work with Excel */
3339 #ifdef USE_UNIX_LOCKS
3340 if (fcntl(file->unix_handle, F_SETLK, &f) == -1) {
3341 FILE_SetDosError();
3342 return FALSE;
3344 #endif
3345 return TRUE;
3347 #endif
3349 /**************************************************************************
3350 * GetFileAttributesExW (KERNEL32.@)
3352 BOOL WINAPI GetFileAttributesExW(
3353 LPCWSTR lpFileName, GET_FILEEX_INFO_LEVELS fInfoLevelId,
3354 LPVOID lpFileInformation)
3356 DOS_FULL_NAME full_name;
3357 BY_HANDLE_FILE_INFORMATION info;
3359 if (!lpFileName || !lpFileInformation)
3361 SetLastError(ERROR_INVALID_PARAMETER);
3362 return FALSE;
3365 if (fInfoLevelId == GetFileExInfoStandard) {
3366 LPWIN32_FILE_ATTRIBUTE_DATA lpFad =
3367 (LPWIN32_FILE_ATTRIBUTE_DATA) lpFileInformation;
3368 if (!DOSFS_GetFullName( lpFileName, TRUE, &full_name )) return FALSE;
3369 if (!FILE_Stat( full_name.long_name, &info, NULL )) return FALSE;
3371 lpFad->dwFileAttributes = info.dwFileAttributes;
3372 lpFad->ftCreationTime = info.ftCreationTime;
3373 lpFad->ftLastAccessTime = info.ftLastAccessTime;
3374 lpFad->ftLastWriteTime = info.ftLastWriteTime;
3375 lpFad->nFileSizeHigh = info.nFileSizeHigh;
3376 lpFad->nFileSizeLow = info.nFileSizeLow;
3378 else {
3379 FIXME("invalid info level %d!\n", fInfoLevelId);
3380 return FALSE;
3383 return TRUE;
3387 /**************************************************************************
3388 * GetFileAttributesExA (KERNEL32.@)
3390 BOOL WINAPI GetFileAttributesExA(
3391 LPCSTR filename, GET_FILEEX_INFO_LEVELS fInfoLevelId,
3392 LPVOID lpFileInformation)
3394 UNICODE_STRING filenameW;
3395 BOOL ret = FALSE;
3397 if (!filename || !lpFileInformation)
3399 SetLastError(ERROR_INVALID_PARAMETER);
3400 return FALSE;
3403 if (RtlCreateUnicodeStringFromAsciiz(&filenameW, filename))
3405 ret = GetFileAttributesExW(filenameW.Buffer, fInfoLevelId, lpFileInformation);
3406 RtlFreeUnicodeString(&filenameW);
3408 else
3409 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
3410 return ret;
3413 /**************************************************************************
3414 * ReplaceFileW (KERNEL32.@)
3415 * ReplaceFile (KERNEL32.@)
3417 BOOL WINAPI ReplaceFileW(LPCWSTR lpReplacedFileName,LPCWSTR lpReplacementFileName,
3418 LPCWSTR lpBackupFileName, DWORD dwReplaceFlags,
3419 LPVOID lpExclude, LPVOID lpReserved)
3421 FIXME("(%s,%s,%s,%08lx,%p,%p) stub\n",debugstr_w(lpReplacedFileName),debugstr_w(lpReplacementFileName),
3422 debugstr_w(lpBackupFileName),dwReplaceFlags,lpExclude,lpReserved);
3423 SetLastError(ERROR_UNABLE_TO_MOVE_REPLACEMENT);
3424 return FALSE;
3427 /**************************************************************************
3428 * ReplaceFileA (KERNEL32.@)
3430 BOOL WINAPI ReplaceFileA(LPCSTR lpReplacedFileName,LPCSTR lpReplacementFileName,
3431 LPCSTR lpBackupFileName, DWORD dwReplaceFlags,
3432 LPVOID lpExclude, LPVOID lpReserved)
3434 FIXME("(%s,%s,%s,%08lx,%p,%p) stub\n",lpReplacedFileName,lpReplacementFileName,
3435 lpBackupFileName,dwReplaceFlags,lpExclude,lpReserved);
3436 SetLastError(ERROR_UNABLE_TO_MOVE_REPLACEMENT);
3437 return FALSE;