Define NONAMELESS{STRUCT,UNION} explicitly in the files that need them.
[wine/multimedia.git] / files / file.c
blob5c911b38c450eead016bf27ff65b7e7806522954
1 /*
2 * File handling functions
4 * Copyright 1993 John Burton
5 * Copyright 1996 Alexandre Julliard
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 * TODO:
22 * Fix the CopyFileEx methods to implement the "extended" functionality.
23 * Right now, they simply call the CopyFile method.
26 #include "config.h"
27 #include "wine/port.h"
29 #include <assert.h>
30 #include <ctype.h>
31 #include <errno.h>
32 #include <fcntl.h>
33 #include <stdlib.h>
34 #include <stdio.h>
35 #include <string.h>
36 #ifdef HAVE_SYS_ERRNO_H
37 #include <sys/errno.h>
38 #endif
39 #include <sys/types.h>
40 #include <sys/stat.h>
41 #ifdef HAVE_SYS_MMAN_H
42 #include <sys/mman.h>
43 #endif
44 #ifdef HAVE_SYS_TIME_H
45 # include <sys/time.h>
46 #endif
47 #ifdef HAVE_SYS_POLL_H
48 # include <sys/poll.h>
49 #endif
50 #include <time.h>
51 #ifdef HAVE_UNISTD_H
52 # include <unistd.h>
53 #endif
54 #ifdef HAVE_UTIME_H
55 # include <utime.h>
56 #endif
58 #define NONAMELESSUNION
59 #define NONAMELESSSTRUCT
60 #include "winerror.h"
61 #include "windef.h"
62 #include "winbase.h"
63 #include "winternl.h"
64 #include "wine/winbase16.h"
65 #include "wine/server.h"
67 #include "drive.h"
68 #include "file.h"
69 #include "async.h"
70 #include "heap.h"
71 #include "msdos.h"
72 #include "wincon.h"
74 #include "smb.h"
75 #include "wine/unicode.h"
76 #include "wine/debug.h"
78 WINE_DEFAULT_DEBUG_CHANNEL(file);
80 #if defined(MAP_ANONYMOUS) && !defined(MAP_ANON)
81 #define MAP_ANON MAP_ANONYMOUS
82 #endif
84 /* Size of per-process table of DOS handles */
85 #define DOS_TABLE_SIZE 256
87 /* Macro to derive file offset from OVERLAPPED struct */
88 #define OVERLAPPED_OFFSET(overlapped) ((off_t) (overlapped)->Offset + ((off_t) (overlapped)->OffsetHigh << 32))
90 static HANDLE dos_handles[DOS_TABLE_SIZE];
92 mode_t FILE_umask;
94 extern HANDLE WINAPI FILE_SmbOpen(LPCSTR name);
96 /***********************************************************************
97 * Asynchronous file I/O *
99 static DWORD fileio_get_async_status (const async_private *ovp);
100 static DWORD fileio_get_async_count (const async_private *ovp);
101 static void fileio_set_async_status (async_private *ovp, const DWORD status);
102 static void CALLBACK fileio_call_completion_func (ULONG_PTR data);
103 static void fileio_async_cleanup (async_private *ovp);
105 static async_ops fileio_async_ops =
107 fileio_get_async_status, /* get_status */
108 fileio_set_async_status, /* set_status */
109 fileio_get_async_count, /* get_count */
110 fileio_call_completion_func, /* call_completion */
111 fileio_async_cleanup /* cleanup */
114 static async_ops fileio_nocomp_async_ops =
116 fileio_get_async_status, /* get_status */
117 fileio_set_async_status, /* set_status */
118 fileio_get_async_count, /* get_count */
119 NULL, /* call_completion */
120 fileio_async_cleanup /* cleanup */
123 typedef struct async_fileio
125 struct async_private async;
126 LPOVERLAPPED lpOverlapped;
127 LPOVERLAPPED_COMPLETION_ROUTINE completion_func;
128 char *buffer;
129 unsigned int count;
130 enum fd_type fd_type;
131 } async_fileio;
133 static DWORD fileio_get_async_status (const struct async_private *ovp)
135 return ((async_fileio*) ovp)->lpOverlapped->Internal;
138 static void fileio_set_async_status (async_private *ovp, const DWORD status)
140 ((async_fileio*) ovp)->lpOverlapped->Internal = status;
143 static DWORD fileio_get_async_count (const struct async_private *ovp)
145 async_fileio *fileio = (async_fileio*) ovp;
147 if (fileio->count < fileio->lpOverlapped->InternalHigh)
148 return 0;
149 return fileio->count - fileio->lpOverlapped->InternalHigh;
152 static void CALLBACK fileio_call_completion_func (ULONG_PTR data)
154 async_fileio *ovp = (async_fileio*) data;
155 TRACE ("data: %p\n", ovp);
157 ovp->completion_func( RtlNtStatusToDosError ( ovp->lpOverlapped->Internal ),
158 ovp->lpOverlapped->InternalHigh,
159 ovp->lpOverlapped );
161 fileio_async_cleanup ( &ovp->async );
164 static void fileio_async_cleanup ( struct async_private *ovp )
166 HeapFree ( GetProcessHeap(), 0, ovp );
169 /***********************************************************************
170 * FILE_ConvertOFMode
172 * Convert OF_* mode into flags for CreateFile.
174 static void FILE_ConvertOFMode( INT mode, DWORD *access, DWORD *sharing )
176 switch(mode & 0x03)
178 case OF_READ: *access = GENERIC_READ; break;
179 case OF_WRITE: *access = GENERIC_WRITE; break;
180 case OF_READWRITE: *access = GENERIC_READ | GENERIC_WRITE; break;
181 default: *access = 0; break;
183 switch(mode & 0x70)
185 case OF_SHARE_EXCLUSIVE: *sharing = 0; break;
186 case OF_SHARE_DENY_WRITE: *sharing = FILE_SHARE_READ; break;
187 case OF_SHARE_DENY_READ: *sharing = FILE_SHARE_WRITE; break;
188 case OF_SHARE_DENY_NONE:
189 case OF_SHARE_COMPAT:
190 default: *sharing = FILE_SHARE_READ | FILE_SHARE_WRITE; break;
195 /***********************************************************************
196 * FILE_strcasecmp
198 * locale-independent case conversion for file I/O
200 int FILE_strcasecmp( const char *str1, const char *str2 )
202 int ret = 0;
203 for ( ; ; str1++, str2++)
204 if ((ret = FILE_toupper(*str1) - FILE_toupper(*str2)) || !*str1) break;
205 return ret;
209 /***********************************************************************
210 * FILE_strncasecmp
212 * locale-independent case conversion for file I/O
214 int FILE_strncasecmp( const char *str1, const char *str2, int len )
216 int ret = 0;
217 for ( ; len > 0; len--, str1++, str2++)
218 if ((ret = FILE_toupper(*str1) - FILE_toupper(*str2)) || !*str1) break;
219 return ret;
223 /***********************************************************************
224 * FILE_GetNtStatus(void)
226 * Retrieve the Nt Status code from errno.
227 * Try to be consistent with FILE_SetDosError().
229 DWORD FILE_GetNtStatus(void)
231 int err = errno;
232 DWORD nt;
233 TRACE ( "errno = %d\n", errno );
234 switch ( err )
236 case EAGAIN: nt = STATUS_SHARING_VIOLATION; break;
237 case EBADF: nt = STATUS_INVALID_HANDLE; break;
238 case ENOSPC: nt = STATUS_DISK_FULL; break;
239 case EPERM:
240 case EROFS:
241 case EACCES: nt = STATUS_ACCESS_DENIED; break;
242 case ENOENT: nt = STATUS_SHARING_VIOLATION; break;
243 case EISDIR: nt = STATUS_FILE_IS_A_DIRECTORY; break;
244 case EMFILE:
245 case ENFILE: nt = STATUS_NO_MORE_FILES; break;
246 case EINVAL:
247 case ENOTEMPTY: nt = STATUS_DIRECTORY_NOT_EMPTY; break;
248 case EPIPE: nt = STATUS_PIPE_BROKEN; break;
249 case ENOEXEC: /* ?? */
250 case ESPIPE: /* ?? */
251 case EEXIST: /* ?? */
252 default:
253 FIXME ( "Converting errno %d to STATUS_UNSUCCESSFUL\n", err );
254 nt = STATUS_UNSUCCESSFUL;
256 return nt;
259 /***********************************************************************
260 * FILE_SetDosError
262 * Set the DOS error code from errno.
264 void FILE_SetDosError(void)
266 int save_errno = errno; /* errno gets overwritten by printf */
268 TRACE("errno = %d %s\n", errno, strerror(errno));
269 switch (save_errno)
271 case EAGAIN:
272 SetLastError( ERROR_SHARING_VIOLATION );
273 break;
274 case EBADF:
275 SetLastError( ERROR_INVALID_HANDLE );
276 break;
277 case ENOSPC:
278 SetLastError( ERROR_HANDLE_DISK_FULL );
279 break;
280 case EACCES:
281 case EPERM:
282 case EROFS:
283 SetLastError( ERROR_ACCESS_DENIED );
284 break;
285 case EBUSY:
286 SetLastError( ERROR_LOCK_VIOLATION );
287 break;
288 case ENOENT:
289 SetLastError( ERROR_FILE_NOT_FOUND );
290 break;
291 case EISDIR:
292 SetLastError( ERROR_CANNOT_MAKE );
293 break;
294 case ENFILE:
295 case EMFILE:
296 SetLastError( ERROR_NO_MORE_FILES );
297 break;
298 case EEXIST:
299 SetLastError( ERROR_FILE_EXISTS );
300 break;
301 case EINVAL:
302 case ESPIPE:
303 SetLastError( ERROR_SEEK );
304 break;
305 case ENOTEMPTY:
306 SetLastError( ERROR_DIR_NOT_EMPTY );
307 break;
308 case ENOEXEC:
309 SetLastError( ERROR_BAD_FORMAT );
310 break;
311 default:
312 WARN("unknown file error: %s\n", strerror(save_errno) );
313 SetLastError( ERROR_GEN_FAILURE );
314 break;
316 errno = save_errno;
320 /***********************************************************************
321 * FILE_GetUnixHandleType
323 * Retrieve the Unix handle corresponding to a file handle.
324 * Returns -1 on failure.
326 static int FILE_GetUnixHandleType( HANDLE handle, DWORD access, enum fd_type *type, int *flags_ptr )
328 int ret, flags, fd = -1;
330 ret = wine_server_handle_to_fd( handle, access, &fd, type, &flags );
331 if (flags_ptr) *flags_ptr = flags;
332 if (ret) SetLastError( RtlNtStatusToDosError(ret) );
333 else if (((access & GENERIC_READ) && (flags & FD_FLAG_RECV_SHUTDOWN)) ||
334 ((access & GENERIC_WRITE) && (flags & FD_FLAG_SEND_SHUTDOWN)))
336 close (fd);
337 SetLastError ( ERROR_PIPE_NOT_CONNECTED );
338 return -1;
340 return fd;
343 /***********************************************************************
344 * FILE_GetUnixHandle
346 * Retrieve the Unix handle corresponding to a file handle.
347 * Returns -1 on failure.
349 int FILE_GetUnixHandle( HANDLE handle, DWORD access )
351 return FILE_GetUnixHandleType( handle, access, NULL, NULL );
354 /*************************************************************************
355 * FILE_OpenConsole
357 * Open a handle to the current process console.
358 * Returns 0 on failure.
360 static HANDLE FILE_OpenConsole( BOOL output, DWORD access, DWORD sharing, LPSECURITY_ATTRIBUTES sa )
362 HANDLE ret;
364 SERVER_START_REQ( open_console )
366 req->from = output;
367 req->access = access;
368 req->share = sharing;
369 req->inherit = (sa && (sa->nLength>=sizeof(*sa)) && sa->bInheritHandle);
370 SetLastError(0);
371 wine_server_call_err( req );
372 ret = reply->handle;
374 SERVER_END_REQ;
375 return ret;
378 /* FIXME: those routines defined as pointers are needed, because this file is
379 * currently compiled into NTDLL whereas it belongs to kernel32.
380 * this shall go away once all the DLL separation process is done
382 typedef BOOL (WINAPI* pRW)(HANDLE, const void*, DWORD, DWORD*, void*);
384 static BOOL FILE_ReadConsole(HANDLE hCon, void* buf, DWORD nb, DWORD* nr, void* p)
386 static HANDLE hKernel /* = 0 */;
387 static pRW pReadConsole /* = 0 */;
389 if ((!hKernel && !(hKernel = LoadLibraryA("kernel32"))) ||
390 (!pReadConsole &&
391 !(pReadConsole = GetProcAddress(hKernel, "ReadConsoleA"))))
393 *nr = 0;
394 return 0;
396 return (pReadConsole)(hCon, buf, nb, nr, p);
399 static BOOL FILE_WriteConsole(HANDLE hCon, const void* buf, DWORD nb, DWORD* nr, void* p)
401 static HANDLE hKernel /* = 0 */;
402 static pRW pWriteConsole /* = 0 */;
404 if ((!hKernel && !(hKernel = LoadLibraryA("kernel32"))) ||
405 (!pWriteConsole &&
406 !(pWriteConsole = GetProcAddress(hKernel, "WriteConsoleA"))))
408 *nr = 0;
409 return 0;
411 return (pWriteConsole)(hCon, buf, nb, nr, p);
413 /* end of FIXME */
415 /***********************************************************************
416 * FILE_CreateFile
418 * Implementation of CreateFile. Takes a Unix path name.
419 * Returns 0 on failure.
421 HANDLE FILE_CreateFile( LPCSTR filename, DWORD access, DWORD sharing,
422 LPSECURITY_ATTRIBUTES sa, DWORD creation,
423 DWORD attributes, HANDLE template, BOOL fail_read_only,
424 UINT drive_type )
426 unsigned int err;
427 HANDLE ret;
429 for (;;)
431 SERVER_START_REQ( create_file )
433 req->access = access;
434 req->inherit = (sa && (sa->nLength>=sizeof(*sa)) && sa->bInheritHandle);
435 req->sharing = sharing;
436 req->create = creation;
437 req->attrs = attributes;
438 req->drive_type = drive_type;
439 wine_server_add_data( req, filename, strlen(filename) );
440 SetLastError(0);
441 err = wine_server_call( req );
442 ret = reply->handle;
444 SERVER_END_REQ;
446 /* If write access failed, retry without GENERIC_WRITE */
448 if (!ret && !fail_read_only && (access & GENERIC_WRITE))
450 if ((err == STATUS_MEDIA_WRITE_PROTECTED) || (err == STATUS_ACCESS_DENIED))
452 TRACE("Write access failed for file '%s', trying without "
453 "write access\n", filename);
454 access &= ~GENERIC_WRITE;
455 continue;
459 if (err)
461 /* In the case file creation was rejected due to CREATE_NEW flag
462 * was specified and file with that name already exists, correct
463 * last error is ERROR_FILE_EXISTS and not ERROR_ALREADY_EXISTS.
464 * Note: RtlNtStatusToDosError is not the subject to blame here.
466 if (err == STATUS_OBJECT_NAME_COLLISION)
467 SetLastError( ERROR_FILE_EXISTS );
468 else
469 SetLastError( RtlNtStatusToDosError(err) );
472 if (!ret) WARN("Unable to create file '%s' (GLE %ld)\n", filename, GetLastError());
473 return ret;
478 /***********************************************************************
479 * FILE_CreateDevice
481 * Same as FILE_CreateFile but for a device
482 * Returns 0 on failure.
484 HANDLE FILE_CreateDevice( int client_id, DWORD access, LPSECURITY_ATTRIBUTES sa )
486 HANDLE ret;
487 SERVER_START_REQ( create_device )
489 req->access = access;
490 req->inherit = (sa && (sa->nLength>=sizeof(*sa)) && sa->bInheritHandle);
491 req->id = client_id;
492 SetLastError(0);
493 wine_server_call_err( req );
494 ret = reply->handle;
496 SERVER_END_REQ;
497 return ret;
500 static HANDLE FILE_OpenPipe(LPCWSTR name, DWORD access)
502 HANDLE ret;
503 DWORD len = 0;
505 if (name && (len = strlenW(name)) > MAX_PATH)
507 SetLastError( ERROR_FILENAME_EXCED_RANGE );
508 return 0;
510 SERVER_START_REQ( open_named_pipe )
512 req->access = access;
513 SetLastError(0);
514 wine_server_add_data( req, name, len * sizeof(WCHAR) );
515 wine_server_call_err( req );
516 ret = reply->handle;
518 SERVER_END_REQ;
519 TRACE("Returned %p\n",ret);
520 return ret;
523 /*************************************************************************
524 * CreateFileW [KERNEL32.@] Creates or opens a file or other object
526 * Creates or opens an object, and returns a handle that can be used to
527 * access that object.
529 * PARAMS
531 * filename [in] pointer to filename to be accessed
532 * access [in] access mode requested
533 * sharing [in] share mode
534 * sa [in] pointer to security attributes
535 * creation [in] how to create the file
536 * attributes [in] attributes for newly created file
537 * template [in] handle to file with extended attributes to copy
539 * RETURNS
540 * Success: Open handle to specified file
541 * Failure: INVALID_HANDLE_VALUE
543 * NOTES
544 * Should call SetLastError() on failure.
546 * BUGS
548 * Doesn't support character devices, template files, or a
549 * lot of the 'attributes' flags yet.
551 HANDLE WINAPI CreateFileW( LPCWSTR filename, DWORD access, DWORD sharing,
552 LPSECURITY_ATTRIBUTES sa, DWORD creation,
553 DWORD attributes, HANDLE template )
555 DOS_FULL_NAME full_name;
556 HANDLE ret;
557 static const WCHAR bkslashes_with_question_markW[] = {'\\','\\','?','\\',0};
558 static const WCHAR bkslashes_with_dotW[] = {'\\','\\','.','\\',0};
559 static const WCHAR bkslashesW[] = {'\\','\\',0};
560 static const WCHAR coninW[] = {'C','O','N','I','N','$',0};
561 static const WCHAR conoutW[] = {'C','O','N','O','U','T','$',0};
563 if (!filename)
565 SetLastError( ERROR_INVALID_PARAMETER );
566 return INVALID_HANDLE_VALUE;
568 TRACE("%s %s%s%s%s%s%s%s attributes 0x%lx\n", debugstr_w(filename),
569 ((access & GENERIC_READ)==GENERIC_READ)?"GENERIC_READ ":"",
570 ((access & GENERIC_WRITE)==GENERIC_WRITE)?"GENERIC_WRITE ":"",
571 (!access)?"QUERY_ACCESS ":"",
572 ((sharing & FILE_SHARE_READ)==FILE_SHARE_READ)?"FILE_SHARE_READ ":"",
573 ((sharing & FILE_SHARE_WRITE)==FILE_SHARE_WRITE)?"FILE_SHARE_WRITE ":"",
574 ((sharing & FILE_SHARE_DELETE)==FILE_SHARE_DELETE)?"FILE_SHARE_DELETE ":"",
575 (creation ==CREATE_NEW)?"CREATE_NEW":
576 (creation ==CREATE_ALWAYS)?"CREATE_ALWAYS ":
577 (creation ==OPEN_EXISTING)?"OPEN_EXISTING ":
578 (creation ==OPEN_ALWAYS)?"OPEN_ALWAYS ":
579 (creation ==TRUNCATE_EXISTING)?"TRUNCATE_EXISTING ":"", attributes);
581 /* If the name starts with '\\?\', ignore the first 4 chars. */
582 if (!strncmpW(filename, bkslashes_with_question_markW, 4))
584 static const WCHAR uncW[] = {'U','N','C','\\',0};
585 filename += 4;
586 if (!strncmpiW(filename, uncW, 4))
588 FIXME("UNC name (%s) not supported.\n", debugstr_w(filename) );
589 SetLastError( ERROR_PATH_NOT_FOUND );
590 return INVALID_HANDLE_VALUE;
594 if (!strncmpW(filename, bkslashes_with_dotW, 4))
596 static const WCHAR pipeW[] = {'P','I','P','E','\\',0};
597 if(!strncmpiW(filename + 4, pipeW, 5))
599 TRACE("Opening a pipe: %s\n", debugstr_w(filename));
600 ret = FILE_OpenPipe(filename,access);
601 goto done;
603 else if (isalphaW(filename[4]) && filename[5] == ':' && filename[6] == '\0')
605 ret = FILE_CreateDevice( (toupperW(filename[4]) - 'A') | 0x20000, access, sa );
606 goto done;
608 else if (!DOSFS_GetDevice( filename ))
610 ret = DEVICE_Open( filename+4, access, sa );
611 goto done;
613 else
614 filename+=4; /* fall into DOSFS_Device case below */
617 /* If the name still starts with '\\', it's a UNC name. */
618 if (!strncmpW(filename, bkslashesW, 2))
620 ret = SMB_CreateFileW(filename, access, sharing, sa, creation, attributes, template );
621 goto done;
624 /* If the name contains a DOS wild card (* or ?), do no create a file */
625 if(strchrW(filename, '*') || strchrW(filename, '?'))
626 return INVALID_HANDLE_VALUE;
628 /* Open a console for CONIN$ or CONOUT$ */
629 if (!strcmpiW(filename, coninW))
631 ret = FILE_OpenConsole( FALSE, access, sharing, sa );
632 goto done;
634 if (!strcmpiW(filename, conoutW))
636 ret = FILE_OpenConsole( TRUE, access, sharing, sa );
637 goto done;
640 if (DOSFS_GetDevice( filename ))
642 TRACE("opening device %s\n", debugstr_w(filename) );
644 if (!(ret = DOSFS_OpenDevice( filename, access, attributes, sa )))
646 /* Do not silence this please. It is a critical error. -MM */
647 ERR("Couldn't open device %s!\n", debugstr_w(filename));
648 SetLastError( ERROR_FILE_NOT_FOUND );
650 goto done;
653 /* check for filename, don't check for last entry if creating */
654 if (!DOSFS_GetFullName( filename,
655 (creation == OPEN_EXISTING) ||
656 (creation == TRUNCATE_EXISTING),
657 &full_name )) {
658 WARN("Unable to get full filename from %s (GLE %ld)\n",
659 debugstr_w(filename), GetLastError());
660 return INVALID_HANDLE_VALUE;
663 ret = FILE_CreateFile( full_name.long_name, access, sharing,
664 sa, creation, attributes, template,
665 DRIVE_GetFlags(full_name.drive) & DRIVE_FAIL_READ_ONLY,
666 GetDriveTypeW( full_name.short_name ) );
667 done:
668 if (!ret) ret = INVALID_HANDLE_VALUE;
669 TRACE("returning %p\n", ret);
670 return ret;
675 /*************************************************************************
676 * CreateFileA (KERNEL32.@)
678 HANDLE WINAPI CreateFileA( LPCSTR filename, DWORD access, DWORD sharing,
679 LPSECURITY_ATTRIBUTES sa, DWORD creation,
680 DWORD attributes, HANDLE template)
682 UNICODE_STRING filenameW;
683 HANDLE ret = INVALID_HANDLE_VALUE;
685 if (!filename)
687 SetLastError( ERROR_INVALID_PARAMETER );
688 return INVALID_HANDLE_VALUE;
691 if (RtlCreateUnicodeStringFromAsciiz(&filenameW, filename))
693 ret = CreateFileW(filenameW.Buffer, access, sharing, sa, creation,
694 attributes, template);
695 RtlFreeUnicodeString(&filenameW);
697 else
698 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
699 return ret;
703 /***********************************************************************
704 * FILE_FillInfo
706 * Fill a file information from a struct stat.
708 static void FILE_FillInfo( struct stat *st, BY_HANDLE_FILE_INFORMATION *info )
710 if (S_ISDIR(st->st_mode))
711 info->dwFileAttributes = FILE_ATTRIBUTE_DIRECTORY;
712 else
713 info->dwFileAttributes = FILE_ATTRIBUTE_ARCHIVE;
714 if (!(st->st_mode & S_IWUSR))
715 info->dwFileAttributes |= FILE_ATTRIBUTE_READONLY;
717 RtlSecondsSince1970ToTime( st->st_mtime, (LARGE_INTEGER *)&info->ftCreationTime );
718 RtlSecondsSince1970ToTime( st->st_mtime, (LARGE_INTEGER *)&info->ftLastWriteTime );
719 RtlSecondsSince1970ToTime( st->st_atime, (LARGE_INTEGER *)&info->ftLastAccessTime );
721 info->dwVolumeSerialNumber = 0; /* FIXME */
722 info->nFileSizeHigh = 0;
723 info->nFileSizeLow = 0;
724 if (!S_ISDIR(st->st_mode)) {
725 info->nFileSizeHigh = st->st_size >> 32;
726 info->nFileSizeLow = st->st_size & 0xffffffff;
728 info->nNumberOfLinks = st->st_nlink;
729 info->nFileIndexHigh = 0;
730 info->nFileIndexLow = st->st_ino;
734 /***********************************************************************
735 * FILE_Stat
737 * Stat a Unix path name. Return TRUE if OK.
739 BOOL FILE_Stat( LPCSTR unixName, BY_HANDLE_FILE_INFORMATION *info, BOOL *is_symlink_ptr )
741 struct stat st;
742 int is_symlink;
743 LPCSTR p;
745 if (lstat( unixName, &st ) == -1)
747 FILE_SetDosError();
748 return FALSE;
750 is_symlink = S_ISLNK(st.st_mode);
751 if (is_symlink)
753 /* do a "real" stat to find out
754 about the type of the symlink destination */
755 if (stat( unixName, &st ) == -1)
757 FILE_SetDosError();
758 return FALSE;
762 /* fill in the information we gathered so far */
763 FILE_FillInfo( &st, info );
765 /* and now see if this is a hidden file, based on the name */
766 p = strrchr( unixName, '/');
767 p = p ? p + 1 : unixName;
768 if (*p == '.' && *(p+1) && (*(p+1) != '.' || *(p+2)))
770 static const WCHAR wineW[] = {'w','i','n','e',0};
771 static const WCHAR ShowDotFilesW[] = {'S','h','o','w','D','o','t','F','i','l','e','s',0};
772 static int show_dot_files = -1;
773 if (show_dot_files == -1)
774 show_dot_files = PROFILE_GetWineIniBool(wineW, ShowDotFilesW, 0);
775 if (!show_dot_files)
776 info->dwFileAttributes |= FILE_ATTRIBUTE_HIDDEN;
778 if (is_symlink_ptr) *is_symlink_ptr = is_symlink;
779 return TRUE;
783 /***********************************************************************
784 * GetFileInformationByHandle (KERNEL32.@)
786 DWORD WINAPI GetFileInformationByHandle( HANDLE hFile,
787 BY_HANDLE_FILE_INFORMATION *info )
789 DWORD ret;
790 if (!info) return 0;
792 TRACE("%p\n", hFile);
794 SERVER_START_REQ( get_file_info )
796 req->handle = hFile;
797 if ((ret = !wine_server_call_err( req )))
799 /* FIXME: which file types are supported ?
800 * Serial ports (FILE_TYPE_CHAR) are not,
801 * and MSDN also says that pipes are not supported.
802 * FILE_TYPE_REMOTE seems to be supported according to
803 * MSDN q234741.txt */
804 if ((reply->type == FILE_TYPE_DISK) || (reply->type == FILE_TYPE_REMOTE))
806 RtlSecondsSince1970ToTime( reply->write_time, (LARGE_INTEGER *)&info->ftCreationTime );
807 RtlSecondsSince1970ToTime( reply->write_time, (LARGE_INTEGER *)&info->ftLastWriteTime );
808 RtlSecondsSince1970ToTime( reply->access_time, (LARGE_INTEGER *)&info->ftLastAccessTime );
809 info->dwFileAttributes = reply->attr;
810 info->dwVolumeSerialNumber = reply->serial;
811 info->nFileSizeHigh = reply->size_high;
812 info->nFileSizeLow = reply->size_low;
813 info->nNumberOfLinks = reply->links;
814 info->nFileIndexHigh = reply->index_high;
815 info->nFileIndexLow = reply->index_low;
817 else
819 SetLastError(ERROR_NOT_SUPPORTED);
820 ret = 0;
824 SERVER_END_REQ;
825 return ret;
829 /**************************************************************************
830 * GetFileAttributes (KERNEL.420)
832 DWORD WINAPI GetFileAttributes16( LPCSTR name )
834 return GetFileAttributesA( name );
838 /**************************************************************************
839 * GetFileAttributesW (KERNEL32.@)
841 DWORD WINAPI GetFileAttributesW( LPCWSTR name )
843 DOS_FULL_NAME full_name;
844 BY_HANDLE_FILE_INFORMATION info;
846 if (name == NULL)
848 SetLastError( ERROR_INVALID_PARAMETER );
849 return -1;
851 if (!DOSFS_GetFullName( name, TRUE, &full_name) )
852 return -1;
853 if (!FILE_Stat( full_name.long_name, &info, NULL )) return -1;
854 return info.dwFileAttributes;
858 /**************************************************************************
859 * GetFileAttributesA (KERNEL32.@)
861 DWORD WINAPI GetFileAttributesA( LPCSTR name )
863 UNICODE_STRING nameW;
864 DWORD ret = (DWORD)-1;
866 if (!name)
868 SetLastError( ERROR_INVALID_PARAMETER );
869 return (DWORD)-1;
872 if (RtlCreateUnicodeStringFromAsciiz(&nameW, name))
874 ret = GetFileAttributesW(nameW.Buffer);
875 RtlFreeUnicodeString(&nameW);
877 else
878 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
879 return ret;
883 /**************************************************************************
884 * SetFileAttributes (KERNEL.421)
886 BOOL16 WINAPI SetFileAttributes16( LPCSTR lpFileName, DWORD attributes )
888 return SetFileAttributesA( lpFileName, attributes );
892 /**************************************************************************
893 * SetFileAttributesW (KERNEL32.@)
895 BOOL WINAPI SetFileAttributesW(LPCWSTR lpFileName, DWORD attributes)
897 struct stat buf;
898 DOS_FULL_NAME full_name;
900 if (!lpFileName)
902 SetLastError( ERROR_INVALID_PARAMETER );
903 return FALSE;
906 TRACE("(%s,%lx)\n", debugstr_w(lpFileName), attributes);
908 if (!DOSFS_GetFullName( lpFileName, TRUE, &full_name ))
909 return FALSE;
911 if(stat(full_name.long_name,&buf)==-1)
913 FILE_SetDosError();
914 return FALSE;
916 if (attributes & FILE_ATTRIBUTE_READONLY)
918 if(S_ISDIR(buf.st_mode))
919 /* FIXME */
920 WARN("FILE_ATTRIBUTE_READONLY ignored for directory.\n");
921 else
922 buf.st_mode &= ~0222; /* octal!, clear write permission bits */
923 attributes &= ~FILE_ATTRIBUTE_READONLY;
925 else
927 /* add write permission */
928 buf.st_mode |= (0600 | ((buf.st_mode & 044) >> 1)) & (~FILE_umask);
930 if (attributes & FILE_ATTRIBUTE_DIRECTORY)
932 if (!S_ISDIR(buf.st_mode))
933 FIXME("SetFileAttributes expected the file %s to be a directory\n",
934 debugstr_w(lpFileName));
935 attributes &= ~FILE_ATTRIBUTE_DIRECTORY;
937 attributes &= ~(FILE_ATTRIBUTE_NORMAL|FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_HIDDEN|FILE_ATTRIBUTE_SYSTEM);
938 if (attributes)
939 FIXME("(%s):%lx attribute(s) not implemented.\n", debugstr_w(lpFileName), attributes);
940 if (-1==chmod(full_name.long_name,buf.st_mode))
942 if (GetDriveTypeW(lpFileName) == DRIVE_CDROM)
944 SetLastError( ERROR_ACCESS_DENIED );
945 return FALSE;
949 * FIXME: We don't return FALSE here because of differences between
950 * Linux and Windows privileges. Under Linux only the owner of
951 * the file is allowed to change file attributes. Under Windows,
952 * applications expect that if you can write to a file, you can also
953 * change its attributes (see GENERIC_WRITE). We could try to be
954 * clever here but that would break multi-user installations where
955 * users share read-only DLLs. This is because some installers like
956 * to change attributes of already installed DLLs.
958 FIXME("Couldn't set file attributes for existing file \"%s\".\n"
959 "Check permissions or set VFAT \"quiet\" mount flag\n", full_name.long_name);
961 return TRUE;
965 /**************************************************************************
966 * SetFileAttributesA (KERNEL32.@)
968 BOOL WINAPI SetFileAttributesA(LPCSTR lpFileName, DWORD attributes)
970 UNICODE_STRING filenameW;
971 BOOL ret = FALSE;
973 if (!lpFileName)
975 SetLastError( ERROR_INVALID_PARAMETER );
976 return FALSE;
979 if (RtlCreateUnicodeStringFromAsciiz(&filenameW, lpFileName))
981 ret = SetFileAttributesW(filenameW.Buffer, attributes);
982 RtlFreeUnicodeString(&filenameW);
984 else
985 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
986 return ret;
990 /***********************************************************************
991 * GetFileSize (KERNEL32.@)
993 DWORD WINAPI GetFileSize( HANDLE hFile, LPDWORD filesizehigh )
995 BY_HANDLE_FILE_INFORMATION info;
996 if (!GetFileInformationByHandle( hFile, &info )) return -1;
997 if (filesizehigh) *filesizehigh = info.nFileSizeHigh;
998 return info.nFileSizeLow;
1002 /***********************************************************************
1003 * GetFileSizeEx (KERNEL32.@)
1005 BOOL WINAPI GetFileSizeEx( HANDLE hFile, PLARGE_INTEGER lpFileSize )
1007 BY_HANDLE_FILE_INFORMATION info;
1009 if (!lpFileSize)
1011 SetLastError( ERROR_INVALID_PARAMETER );
1012 return FALSE;
1015 if (!GetFileInformationByHandle( hFile, &info ))
1017 return FALSE;
1020 lpFileSize->s.LowPart = info.nFileSizeLow;
1021 lpFileSize->s.HighPart = info.nFileSizeHigh;
1023 return TRUE;
1027 /***********************************************************************
1028 * GetFileTime (KERNEL32.@)
1030 BOOL WINAPI GetFileTime( HANDLE hFile, FILETIME *lpCreationTime,
1031 FILETIME *lpLastAccessTime,
1032 FILETIME *lpLastWriteTime )
1034 BY_HANDLE_FILE_INFORMATION info;
1035 if (!GetFileInformationByHandle( hFile, &info )) return FALSE;
1036 if (lpCreationTime) *lpCreationTime = info.ftCreationTime;
1037 if (lpLastAccessTime) *lpLastAccessTime = info.ftLastAccessTime;
1038 if (lpLastWriteTime) *lpLastWriteTime = info.ftLastWriteTime;
1039 return TRUE;
1042 /***********************************************************************
1043 * FILE_GetTempFileName : utility for GetTempFileName
1045 static UINT FILE_GetTempFileName( LPCWSTR path, LPCWSTR prefix, UINT unique,
1046 LPWSTR buffer )
1048 static UINT unique_temp;
1049 DOS_FULL_NAME full_name;
1050 int i;
1051 LPWSTR p;
1052 UINT num;
1053 char buf[20];
1055 if ( !path || !prefix || !buffer )
1057 SetLastError( ERROR_INVALID_PARAMETER );
1058 return 0;
1061 if (!unique_temp) unique_temp = time(NULL) & 0xffff;
1062 num = unique ? (unique & 0xffff) : (unique_temp++ & 0xffff);
1064 strcpyW( buffer, path );
1065 p = buffer + strlenW(buffer);
1067 /* add a \, if there isn't one and path is more than just the drive letter ... */
1068 if ( !((strlenW(buffer) == 2) && (buffer[1] == ':'))
1069 && ((p == buffer) || (p[-1] != '\\'))) *p++ = '\\';
1071 for (i = 3; (i > 0) && (*prefix); i--) *p++ = *prefix++;
1073 sprintf( buf, "%04x.tmp", num );
1074 MultiByteToWideChar(CP_ACP, 0, buf, -1, p, 20);
1076 /* Now try to create it */
1078 if (!unique)
1082 HANDLE handle = CreateFileW( buffer, GENERIC_WRITE, 0, NULL,
1083 CREATE_NEW, FILE_ATTRIBUTE_NORMAL, 0 );
1084 if (handle != INVALID_HANDLE_VALUE)
1085 { /* We created it */
1086 TRACE("created %s\n", debugstr_w(buffer) );
1087 CloseHandle( handle );
1088 break;
1090 if (GetLastError() != ERROR_FILE_EXISTS)
1091 break; /* No need to go on */
1092 num++;
1093 sprintf( buf, "%04x.tmp", num );
1094 MultiByteToWideChar(CP_ACP, 0, buf, -1, p, 20);
1095 } while (num != (unique & 0xffff));
1098 /* Get the full path name */
1100 if (DOSFS_GetFullName( buffer, FALSE, &full_name ))
1102 char *slash;
1103 /* Check if we have write access in the directory */
1104 if ((slash = strrchr( full_name.long_name, '/' ))) *slash = '\0';
1105 if (access( full_name.long_name, W_OK ) == -1)
1106 WARN("returns %s, which doesn't seem to be writeable.\n",
1107 debugstr_w(buffer) );
1109 TRACE("returning %s\n", debugstr_w(buffer) );
1110 return unique ? unique : num;
1114 /***********************************************************************
1115 * GetTempFileNameA (KERNEL32.@)
1117 UINT WINAPI GetTempFileNameA( LPCSTR path, LPCSTR prefix, UINT unique,
1118 LPSTR buffer)
1120 UNICODE_STRING pathW, prefixW;
1121 WCHAR bufferW[MAX_PATH];
1122 UINT ret;
1124 if ( !path || !prefix || !buffer )
1126 SetLastError( ERROR_INVALID_PARAMETER );
1127 return 0;
1130 RtlCreateUnicodeStringFromAsciiz(&pathW, path);
1131 RtlCreateUnicodeStringFromAsciiz(&prefixW, prefix);
1133 ret = GetTempFileNameW(pathW.Buffer, prefixW.Buffer, unique, bufferW);
1134 if (ret)
1135 WideCharToMultiByte(CP_ACP, 0, bufferW, -1, buffer, MAX_PATH, NULL, NULL);
1137 RtlFreeUnicodeString(&pathW);
1138 RtlFreeUnicodeString(&prefixW);
1139 return ret;
1142 /***********************************************************************
1143 * GetTempFileNameW (KERNEL32.@)
1145 UINT WINAPI GetTempFileNameW( LPCWSTR path, LPCWSTR prefix, UINT unique,
1146 LPWSTR buffer )
1148 return FILE_GetTempFileName( path, prefix, unique, buffer );
1152 /***********************************************************************
1153 * GetTempFileName (KERNEL.97)
1155 UINT16 WINAPI GetTempFileName16( BYTE drive, LPCSTR prefix, UINT16 unique,
1156 LPSTR buffer )
1158 char temppath[MAX_PATH];
1159 char *prefix16 = NULL;
1160 UINT16 ret;
1162 if (!(drive & ~TF_FORCEDRIVE)) /* drive 0 means current default drive */
1163 drive |= DRIVE_GetCurrentDrive() + 'A';
1165 if ((drive & TF_FORCEDRIVE) &&
1166 !DRIVE_IsValid( toupper(drive & ~TF_FORCEDRIVE) - 'A' ))
1168 drive &= ~TF_FORCEDRIVE;
1169 WARN("invalid drive %d specified\n", drive );
1172 if (drive & TF_FORCEDRIVE)
1173 sprintf(temppath,"%c:", drive & ~TF_FORCEDRIVE );
1174 else
1175 GetTempPathA( MAX_PATH, temppath );
1177 if (prefix)
1179 prefix16 = HeapAlloc(GetProcessHeap(), 0, strlen(prefix) + 2);
1180 *prefix16 = '~';
1181 strcpy(prefix16 + 1, prefix);
1184 ret = GetTempFileNameA( temppath, prefix16, unique, buffer );
1186 if (prefix16) HeapFree(GetProcessHeap(), 0, prefix16);
1187 return ret;
1190 /***********************************************************************
1191 * FILE_DoOpenFile
1193 * Implementation of OpenFile16() and OpenFile32().
1195 static HFILE FILE_DoOpenFile( LPCSTR name, OFSTRUCT *ofs, UINT mode,
1196 BOOL win32 )
1198 HFILE hFileRet;
1199 HANDLE handle;
1200 FILETIME filetime;
1201 WORD filedatetime[2];
1202 DOS_FULL_NAME full_name;
1203 DWORD access, sharing;
1204 WCHAR *p;
1205 WCHAR buffer[MAX_PATH];
1206 LPWSTR nameW;
1208 if (!ofs) return HFILE_ERROR;
1210 TRACE("%s %s %s %s%s%s%s%s%s%s%s%s\n",name,
1211 ((mode & 0x3 )==OF_READ)?"OF_READ":
1212 ((mode & 0x3 )==OF_WRITE)?"OF_WRITE":
1213 ((mode & 0x3 )==OF_READWRITE)?"OF_READWRITE":"unknown",
1214 ((mode & 0x70 )==OF_SHARE_COMPAT)?"OF_SHARE_COMPAT":
1215 ((mode & 0x70 )==OF_SHARE_DENY_NONE)?"OF_SHARE_DENY_NONE":
1216 ((mode & 0x70 )==OF_SHARE_DENY_READ)?"OF_SHARE_DENY_READ":
1217 ((mode & 0x70 )==OF_SHARE_DENY_WRITE)?"OF_SHARE_DENY_WRITE":
1218 ((mode & 0x70 )==OF_SHARE_EXCLUSIVE)?"OF_SHARE_EXCLUSIVE":"unknown",
1219 ((mode & OF_PARSE )==OF_PARSE)?"OF_PARSE ":"",
1220 ((mode & OF_DELETE )==OF_DELETE)?"OF_DELETE ":"",
1221 ((mode & OF_VERIFY )==OF_VERIFY)?"OF_VERIFY ":"",
1222 ((mode & OF_SEARCH )==OF_SEARCH)?"OF_SEARCH ":"",
1223 ((mode & OF_CANCEL )==OF_CANCEL)?"OF_CANCEL ":"",
1224 ((mode & OF_CREATE )==OF_CREATE)?"OF_CREATE ":"",
1225 ((mode & OF_PROMPT )==OF_PROMPT)?"OF_PROMPT ":"",
1226 ((mode & OF_EXIST )==OF_EXIST)?"OF_EXIST ":"",
1227 ((mode & OF_REOPEN )==OF_REOPEN)?"OF_REOPEN ":""
1231 ofs->cBytes = sizeof(OFSTRUCT);
1232 ofs->nErrCode = 0;
1233 if (mode & OF_REOPEN) name = ofs->szPathName;
1235 if (!name) {
1236 ERR("called with `name' set to NULL ! Please debug.\n");
1237 return HFILE_ERROR;
1240 TRACE("%s %04x\n", name, mode );
1242 /* the watcom 10.6 IDE relies on a valid path returned in ofs->szPathName
1243 Are there any cases where getting the path here is wrong?
1244 Uwe Bonnes 1997 Apr 2 */
1245 if (!GetFullPathNameA( name, sizeof(ofs->szPathName),
1246 ofs->szPathName, NULL )) goto error;
1247 FILE_ConvertOFMode( mode, &access, &sharing );
1249 /* OF_PARSE simply fills the structure */
1251 if (mode & OF_PARSE)
1253 ofs->fFixedDisk = (GetDriveType16( ofs->szPathName[0]-'A' )
1254 != DRIVE_REMOVABLE);
1255 TRACE("(%s): OF_PARSE, res = '%s'\n",
1256 name, ofs->szPathName );
1257 return 0;
1260 /* OF_CREATE is completely different from all other options, so
1261 handle it first */
1263 if (mode & OF_CREATE)
1265 if ((handle = CreateFileA( name, GENERIC_READ | GENERIC_WRITE,
1266 sharing, NULL, CREATE_ALWAYS,
1267 FILE_ATTRIBUTE_NORMAL, 0 ))== INVALID_HANDLE_VALUE)
1268 goto error;
1269 goto success;
1272 MultiByteToWideChar(CP_ACP, 0, name, -1, buffer, MAX_PATH);
1273 nameW = buffer;
1275 /* If OF_SEARCH is set, ignore the given path */
1277 if ((mode & OF_SEARCH) && !(mode & OF_REOPEN))
1279 /* First try the file name as is */
1280 if (DOSFS_GetFullName( nameW, TRUE, &full_name )) goto found;
1281 /* Now remove the path */
1282 if (nameW[0] && (nameW[1] == ':')) nameW += 2;
1283 if ((p = strrchrW( nameW, '\\' ))) nameW = p + 1;
1284 if ((p = strrchrW( nameW, '/' ))) nameW = p + 1;
1285 if (!nameW[0]) goto not_found;
1288 /* Now look for the file */
1290 if (!DIR_SearchPath( NULL, nameW, NULL, &full_name, win32 )) goto not_found;
1292 found:
1293 TRACE("found %s = %s\n",
1294 full_name.long_name, debugstr_w(full_name.short_name) );
1295 WideCharToMultiByte(CP_ACP, 0, full_name.short_name, -1,
1296 ofs->szPathName, sizeof(ofs->szPathName), NULL, NULL);
1298 if (mode & OF_SHARE_EXCLUSIVE)
1299 /* Some InstallShield version uses OF_SHARE_EXCLUSIVE
1300 on the file <tempdir>/_ins0432._mp to determine how
1301 far installation has proceeded.
1302 _ins0432._mp is an executable and while running the
1303 application expects the open with OF_SHARE_ to fail*/
1304 /* Probable FIXME:
1305 As our loader closes the files after loading the executable,
1306 we can't find the running executable with FILE_InUse.
1307 The loader should keep the file open, as Windows does that, too.
1310 char *last = strrchr(full_name.long_name,'/');
1311 if (!last)
1312 last = full_name.long_name - 1;
1313 if (GetModuleHandle16(last+1))
1315 TRACE("Denying shared open for %s\n",full_name.long_name);
1316 return HFILE_ERROR;
1320 if (mode & OF_DELETE)
1322 if (unlink( full_name.long_name ) == -1) goto not_found;
1323 TRACE("(%s): OF_DELETE return = OK\n", name);
1324 return 1;
1327 handle = FILE_CreateFile( full_name.long_name, access, sharing,
1328 NULL, OPEN_EXISTING, 0, 0,
1329 DRIVE_GetFlags(full_name.drive) & DRIVE_FAIL_READ_ONLY,
1330 GetDriveTypeW( full_name.short_name ) );
1331 if (!handle) goto not_found;
1333 GetFileTime( handle, NULL, NULL, &filetime );
1334 FileTimeToDosDateTime( &filetime, &filedatetime[0], &filedatetime[1] );
1335 if ((mode & OF_VERIFY) && (mode & OF_REOPEN))
1337 if (ofs->Reserved1 != filedatetime[0] || ofs->Reserved2 != filedatetime[1] )
1339 CloseHandle( handle );
1340 WARN("(%s): OF_VERIFY failed\n", name );
1341 /* FIXME: what error here? */
1342 SetLastError( ERROR_FILE_NOT_FOUND );
1343 goto error;
1346 ofs->Reserved1 = filedatetime[0];
1347 ofs->Reserved2 = filedatetime[1];
1349 success: /* We get here if the open was successful */
1350 TRACE("(%s): OK, return = %p\n", name, handle );
1351 if (win32)
1353 hFileRet = (HFILE)handle;
1354 if (mode & OF_EXIST) /* Return the handle, but close it first */
1355 CloseHandle( handle );
1357 else
1359 hFileRet = Win32HandleToDosFileHandle( handle );
1360 if (hFileRet == HFILE_ERROR16) goto error;
1361 if (mode & OF_EXIST) /* Return the handle, but close it first */
1362 _lclose16( hFileRet );
1364 return hFileRet;
1366 not_found: /* We get here if the file does not exist */
1367 WARN("'%s' not found or sharing violation\n", name );
1368 SetLastError( ERROR_FILE_NOT_FOUND );
1369 /* fall through */
1371 error: /* We get here if there was an error opening the file */
1372 ofs->nErrCode = GetLastError();
1373 WARN("(%s): return = HFILE_ERROR error= %d\n",
1374 name,ofs->nErrCode );
1375 return HFILE_ERROR;
1379 /***********************************************************************
1380 * OpenFile (KERNEL.74)
1381 * OpenFileEx (KERNEL.360)
1383 HFILE16 WINAPI OpenFile16( LPCSTR name, OFSTRUCT *ofs, UINT16 mode )
1385 return FILE_DoOpenFile( name, ofs, mode, FALSE );
1389 /***********************************************************************
1390 * OpenFile (KERNEL32.@)
1392 HFILE WINAPI OpenFile( LPCSTR name, OFSTRUCT *ofs, UINT mode )
1394 return FILE_DoOpenFile( name, ofs, mode, TRUE );
1398 /***********************************************************************
1399 * FILE_InitProcessDosHandles
1401 * Allocates the default DOS handles for a process. Called either by
1402 * Win32HandleToDosFileHandle below or by the DOSVM stuff.
1404 static void FILE_InitProcessDosHandles( void )
1406 HANDLE cp = GetCurrentProcess();
1407 DuplicateHandle(cp, GetStdHandle(STD_INPUT_HANDLE), cp, &dos_handles[0],
1408 0, TRUE, DUPLICATE_SAME_ACCESS);
1409 DuplicateHandle(cp, GetStdHandle(STD_OUTPUT_HANDLE), cp, &dos_handles[1],
1410 0, TRUE, DUPLICATE_SAME_ACCESS);
1411 DuplicateHandle(cp, GetStdHandle(STD_ERROR_HANDLE), cp, &dos_handles[2],
1412 0, TRUE, DUPLICATE_SAME_ACCESS);
1413 DuplicateHandle(cp, GetStdHandle(STD_ERROR_HANDLE), cp, &dos_handles[3],
1414 0, TRUE, DUPLICATE_SAME_ACCESS);
1415 DuplicateHandle(cp, GetStdHandle(STD_ERROR_HANDLE), cp, &dos_handles[4],
1416 0, TRUE, DUPLICATE_SAME_ACCESS);
1419 /***********************************************************************
1420 * Win32HandleToDosFileHandle (KERNEL32.21)
1422 * Allocate a DOS handle for a Win32 handle. The Win32 handle is no
1423 * longer valid after this function (even on failure).
1425 * Note: this is not exactly right, since on Win95 the Win32 handles
1426 * are on top of DOS handles and we do it the other way
1427 * around. Should be good enough though.
1429 HFILE WINAPI Win32HandleToDosFileHandle( HANDLE handle )
1431 int i;
1433 if (!handle || (handle == INVALID_HANDLE_VALUE))
1434 return HFILE_ERROR;
1436 for (i = 5; i < DOS_TABLE_SIZE; i++)
1437 if (!dos_handles[i])
1439 dos_handles[i] = handle;
1440 TRACE("Got %d for h32 %p\n", i, handle );
1441 return (HFILE)i;
1443 CloseHandle( handle );
1444 SetLastError( ERROR_TOO_MANY_OPEN_FILES );
1445 return HFILE_ERROR;
1449 /***********************************************************************
1450 * DosFileHandleToWin32Handle (KERNEL32.20)
1452 * Return the Win32 handle for a DOS handle.
1454 * Note: this is not exactly right, since on Win95 the Win32 handles
1455 * are on top of DOS handles and we do it the other way
1456 * around. Should be good enough though.
1458 HANDLE WINAPI DosFileHandleToWin32Handle( HFILE handle )
1460 HFILE16 hfile = (HFILE16)handle;
1461 if (hfile < 5 && !dos_handles[hfile]) FILE_InitProcessDosHandles();
1462 if ((hfile >= DOS_TABLE_SIZE) || !dos_handles[hfile])
1464 SetLastError( ERROR_INVALID_HANDLE );
1465 return INVALID_HANDLE_VALUE;
1467 return dos_handles[hfile];
1471 /***********************************************************************
1472 * DisposeLZ32Handle (KERNEL32.22)
1474 * Note: this is not entirely correct, we should only close the
1475 * 32-bit handle and not the 16-bit one, but we cannot do
1476 * this because of the way our DOS handles are implemented.
1477 * It shouldn't break anything though.
1479 void WINAPI DisposeLZ32Handle( HANDLE handle )
1481 int i;
1483 if (!handle || (handle == INVALID_HANDLE_VALUE)) return;
1485 for (i = 5; i < DOS_TABLE_SIZE; i++)
1486 if (dos_handles[i] == handle)
1488 dos_handles[i] = 0;
1489 CloseHandle( handle );
1490 break;
1495 /***********************************************************************
1496 * FILE_Dup2
1498 * dup2() function for DOS handles.
1500 HFILE16 FILE_Dup2( HFILE16 hFile1, HFILE16 hFile2 )
1502 HANDLE new_handle;
1504 if (hFile1 < 5 && !dos_handles[hFile1]) FILE_InitProcessDosHandles();
1506 if ((hFile1 >= DOS_TABLE_SIZE) || (hFile2 >= DOS_TABLE_SIZE) || !dos_handles[hFile1])
1508 SetLastError( ERROR_INVALID_HANDLE );
1509 return HFILE_ERROR16;
1511 if (!DuplicateHandle( GetCurrentProcess(), dos_handles[hFile1],
1512 GetCurrentProcess(), &new_handle,
1513 0, FALSE, DUPLICATE_SAME_ACCESS ))
1514 return HFILE_ERROR16;
1515 if (dos_handles[hFile2]) CloseHandle( dos_handles[hFile2] );
1516 dos_handles[hFile2] = new_handle;
1517 return hFile2;
1521 /***********************************************************************
1522 * _lclose (KERNEL.81)
1524 HFILE16 WINAPI _lclose16( HFILE16 hFile )
1526 if ((hFile >= DOS_TABLE_SIZE) || !dos_handles[hFile])
1528 SetLastError( ERROR_INVALID_HANDLE );
1529 return HFILE_ERROR16;
1531 TRACE("%d (handle32=%p)\n", hFile, dos_handles[hFile] );
1532 CloseHandle( dos_handles[hFile] );
1533 dos_handles[hFile] = 0;
1534 return 0;
1538 /***********************************************************************
1539 * _lclose (KERNEL32.@)
1541 HFILE WINAPI _lclose( HFILE hFile )
1543 TRACE("handle %d\n", hFile );
1544 return CloseHandle( (HANDLE)hFile ) ? 0 : HFILE_ERROR;
1547 /***********************************************************************
1548 * GetOverlappedResult (KERNEL32.@)
1550 * Check the result of an Asynchronous data transfer from a file.
1552 * RETURNS
1553 * TRUE on success
1554 * FALSE on failure
1556 * If successful (and relevant) lpTransferred will hold the number of
1557 * bytes transferred during the async operation.
1559 * BUGS
1561 * Currently only works for WaitCommEvent, ReadFile, WriteFile
1562 * with communications ports.
1565 BOOL WINAPI GetOverlappedResult(
1566 HANDLE hFile, /* [in] handle of file to check on */
1567 LPOVERLAPPED lpOverlapped, /* [in/out] pointer to overlapped */
1568 LPDWORD lpTransferred, /* [in/out] number of bytes transferred */
1569 BOOL bWait /* [in] wait for the transfer to complete ? */
1571 DWORD r;
1573 TRACE("(%p %p %p %x)\n", hFile, lpOverlapped, lpTransferred, bWait);
1575 if(lpOverlapped==NULL)
1577 ERR("lpOverlapped was null\n");
1578 return FALSE;
1580 if(!lpOverlapped->hEvent)
1582 ERR("lpOverlapped->hEvent was null\n");
1583 return FALSE;
1586 if ( bWait )
1588 do {
1589 TRACE("waiting on %p\n",lpOverlapped);
1590 r = WaitForSingleObjectEx(lpOverlapped->hEvent, INFINITE, TRUE);
1591 TRACE("wait on %p returned %ld\n",lpOverlapped,r);
1592 } while (r==STATUS_USER_APC);
1594 else if ( lpOverlapped->Internal == STATUS_PENDING )
1596 /* Wait in order to give APCs a chance to run. */
1597 /* This is cheating, so we must set the event again in case of success -
1598 it may be a non-manual reset event. */
1599 do {
1600 TRACE("waiting on %p\n",lpOverlapped);
1601 r = WaitForSingleObjectEx(lpOverlapped->hEvent, 0, TRUE);
1602 TRACE("wait on %p returned %ld\n",lpOverlapped,r);
1603 } while (r==STATUS_USER_APC);
1604 if ( r == WAIT_OBJECT_0 )
1605 NtSetEvent ( lpOverlapped->hEvent, NULL );
1608 if(lpTransferred)
1609 *lpTransferred = lpOverlapped->InternalHigh;
1611 switch ( lpOverlapped->Internal )
1613 case STATUS_SUCCESS:
1614 return TRUE;
1615 case STATUS_PENDING:
1616 SetLastError ( ERROR_IO_INCOMPLETE );
1617 if ( bWait ) ERR ("PENDING status after waiting!\n");
1618 return FALSE;
1619 default:
1620 SetLastError ( RtlNtStatusToDosError ( lpOverlapped->Internal ) );
1621 return FALSE;
1625 /***********************************************************************
1626 * CancelIo (KERNEL32.@)
1628 BOOL WINAPI CancelIo(HANDLE handle)
1630 async_private *ovp,*t;
1632 TRACE("handle = %p\n",handle);
1634 for (ovp = NtCurrentTeb()->pending_list; ovp; ovp = t)
1636 t = ovp->next;
1637 if ( ovp->handle == handle )
1638 cancel_async ( ovp );
1640 WaitForMultipleObjectsEx(0,NULL,FALSE,1,TRUE);
1641 return TRUE;
1644 /***********************************************************************
1645 * FILE_AsyncReadService (INTERNAL)
1647 * This function is called while the client is waiting on the
1648 * server, so we can't make any server calls here.
1650 static void FILE_AsyncReadService(async_private *ovp)
1652 async_fileio *fileio = (async_fileio*) ovp;
1653 LPOVERLAPPED lpOverlapped = fileio->lpOverlapped;
1654 int result, r;
1655 int already = lpOverlapped->InternalHigh;
1657 TRACE("%p %p\n", lpOverlapped, fileio->buffer );
1659 /* check to see if the data is ready (non-blocking) */
1661 if ( fileio->fd_type == FD_TYPE_SOCKET )
1662 result = read (ovp->fd, &fileio->buffer[already], fileio->count - already);
1663 else
1665 result = pread (ovp->fd, &fileio->buffer[already], fileio->count - already,
1666 OVERLAPPED_OFFSET (lpOverlapped) + already);
1667 if ((result < 0) && (errno == ESPIPE))
1668 result = read (ovp->fd, &fileio->buffer[already], fileio->count - already);
1671 if ( (result<0) && ((errno == EAGAIN) || (errno == EINTR)))
1673 TRACE("Deferred read %d\n",errno);
1674 r = STATUS_PENDING;
1675 goto async_end;
1678 /* check to see if the transfer is complete */
1679 if(result<0)
1681 r = FILE_GetNtStatus ();
1682 goto async_end;
1684 else if ( result == 0 )
1686 r = ( lpOverlapped->InternalHigh ? STATUS_SUCCESS : STATUS_END_OF_FILE );
1687 goto async_end;
1690 lpOverlapped->InternalHigh += result;
1691 TRACE("read %d more bytes %ld/%d so far\n",result,lpOverlapped->InternalHigh,fileio->count);
1693 if(lpOverlapped->InternalHigh >= fileio->count || fileio->fd_type == FD_TYPE_SOCKET )
1694 r = STATUS_SUCCESS;
1695 else
1696 r = STATUS_PENDING;
1698 async_end:
1699 lpOverlapped->Internal = r;
1702 /***********************************************************************
1703 * FILE_ReadFileEx (INTERNAL)
1705 static BOOL FILE_ReadFileEx(HANDLE hFile, LPVOID buffer, DWORD bytesToRead,
1706 LPOVERLAPPED overlapped,
1707 LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine,
1708 HANDLE hEvent)
1710 async_fileio *ovp;
1711 int fd;
1712 int flags;
1713 enum fd_type type;
1715 TRACE("file %p to buf %p num %ld %p func %p\n",
1716 hFile, buffer, bytesToRead, overlapped, lpCompletionRoutine);
1718 /* check that there is an overlapped struct */
1719 if (overlapped==NULL)
1721 SetLastError(ERROR_INVALID_PARAMETER);
1722 return FALSE;
1725 fd = FILE_GetUnixHandleType ( hFile, GENERIC_READ, &type, &flags);
1726 if ( fd < 0 )
1728 WARN ( "Couldn't get FD\n" );
1729 return FALSE;
1732 ovp = (async_fileio*) HeapAlloc(GetProcessHeap(), 0, sizeof (async_fileio));
1733 if(!ovp)
1735 TRACE("HeapAlloc Failed\n");
1736 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1737 goto error;
1740 ovp->async.ops = ( lpCompletionRoutine ? &fileio_async_ops : &fileio_nocomp_async_ops );
1741 ovp->async.handle = hFile;
1742 ovp->async.fd = fd;
1743 ovp->async.type = ASYNC_TYPE_READ;
1744 ovp->async.func = FILE_AsyncReadService;
1745 ovp->async.event = hEvent;
1746 ovp->lpOverlapped = overlapped;
1747 ovp->count = bytesToRead;
1748 ovp->completion_func = lpCompletionRoutine;
1749 ovp->buffer = buffer;
1750 ovp->fd_type = type;
1752 return !register_new_async (&ovp->async);
1754 error:
1755 close (fd);
1756 return FALSE;
1760 /***********************************************************************
1761 * ReadFileEx (KERNEL32.@)
1763 BOOL WINAPI ReadFileEx(HANDLE hFile, LPVOID buffer, DWORD bytesToRead,
1764 LPOVERLAPPED overlapped,
1765 LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine)
1767 overlapped->InternalHigh = 0;
1768 return FILE_ReadFileEx(hFile,buffer,bytesToRead,overlapped,lpCompletionRoutine, INVALID_HANDLE_VALUE);
1771 static BOOL FILE_TimeoutRead(HANDLE hFile, LPVOID buffer, DWORD bytesToRead, LPDWORD bytesRead)
1773 OVERLAPPED ov;
1774 BOOL r = FALSE;
1776 TRACE("%p %p %ld %p\n", hFile, buffer, bytesToRead, bytesRead );
1778 ZeroMemory(&ov, sizeof (OVERLAPPED));
1779 if(STATUS_SUCCESS==NtCreateEvent(&ov.hEvent, SYNCHRONIZE, NULL, 0, 0))
1781 if(FILE_ReadFileEx(hFile, buffer, bytesToRead, &ov, NULL, ov.hEvent))
1783 r = GetOverlappedResult(hFile, &ov, bytesRead, TRUE);
1786 CloseHandle(ov.hEvent);
1787 return r;
1790 /***********************************************************************
1791 * ReadFile (KERNEL32.@)
1793 BOOL WINAPI ReadFile( HANDLE hFile, LPVOID buffer, DWORD bytesToRead,
1794 LPDWORD bytesRead, LPOVERLAPPED overlapped )
1796 int unix_handle, result, flags;
1797 enum fd_type type;
1799 TRACE("%p %p %ld %p %p\n", hFile, buffer, bytesToRead,
1800 bytesRead, overlapped );
1802 if (bytesRead) *bytesRead = 0; /* Do this before anything else */
1803 if (!bytesToRead) return TRUE;
1805 unix_handle = FILE_GetUnixHandleType( hFile, GENERIC_READ, &type, &flags );
1807 if (flags & FD_FLAG_OVERLAPPED)
1809 if (unix_handle == -1) return FALSE;
1810 if ( (overlapped==NULL) || NtResetEvent( overlapped->hEvent, NULL ) )
1812 TRACE("Overlapped not specified or invalid event flag\n");
1813 close(unix_handle);
1814 SetLastError(ERROR_INVALID_PARAMETER);
1815 return FALSE;
1818 close(unix_handle);
1819 overlapped->InternalHigh = 0;
1821 if(!FILE_ReadFileEx(hFile, buffer, bytesToRead, overlapped, NULL, overlapped->hEvent))
1822 return FALSE;
1824 if ( !GetOverlappedResult (hFile, overlapped, bytesRead, FALSE) )
1826 if ( GetLastError() == ERROR_IO_INCOMPLETE )
1827 SetLastError ( ERROR_IO_PENDING );
1828 return FALSE;
1831 return TRUE;
1833 if (flags & FD_FLAG_TIMEOUT)
1835 close(unix_handle);
1836 return FILE_TimeoutRead(hFile, buffer, bytesToRead, bytesRead);
1838 switch(type)
1840 case FD_TYPE_SMB:
1841 return SMB_ReadFile(hFile, buffer, bytesToRead, bytesRead, NULL);
1843 case FD_TYPE_CONSOLE:
1844 return FILE_ReadConsole(hFile, buffer, bytesToRead, bytesRead, NULL);
1846 case FD_TYPE_DEFAULT:
1847 /* normal unix files */
1848 if (unix_handle == -1) return FALSE;
1849 if (overlapped)
1851 DWORD highOffset = overlapped->OffsetHigh;
1852 if ( (INVALID_SET_FILE_POINTER == SetFilePointer(hFile, overlapped->Offset,
1853 &highOffset, FILE_BEGIN)) &&
1854 (GetLastError() != NO_ERROR) )
1856 close(unix_handle);
1857 return FALSE;
1860 break;
1862 default:
1863 if (unix_handle == -1)
1864 return FALSE;
1867 if(overlapped)
1869 off_t offset = OVERLAPPED_OFFSET(overlapped);
1870 if(lseek(unix_handle, offset, SEEK_SET) == -1)
1872 close(unix_handle);
1873 SetLastError(ERROR_INVALID_PARAMETER);
1874 return FALSE;
1878 /* code for synchronous reads */
1879 while ((result = read( unix_handle, buffer, bytesToRead )) == -1)
1881 if ((errno == EAGAIN) || (errno == EINTR)) continue;
1882 if ((errno == EFAULT) && !IsBadWritePtr( buffer, bytesToRead )) continue;
1883 FILE_SetDosError();
1884 break;
1886 close( unix_handle );
1887 if (result == -1) return FALSE;
1888 if (bytesRead) *bytesRead = result;
1889 return TRUE;
1893 /***********************************************************************
1894 * FILE_AsyncWriteService (INTERNAL)
1896 * This function is called while the client is waiting on the
1897 * server, so we can't make any server calls here.
1899 static void FILE_AsyncWriteService(struct async_private *ovp)
1901 async_fileio *fileio = (async_fileio *) ovp;
1902 LPOVERLAPPED lpOverlapped = fileio->lpOverlapped;
1903 int result, r;
1904 int already = lpOverlapped->InternalHigh;
1906 TRACE("(%p %p)\n",lpOverlapped,fileio->buffer);
1908 /* write some data (non-blocking) */
1910 if ( fileio->fd_type == FD_TYPE_SOCKET )
1911 result = write(ovp->fd, &fileio->buffer[already], fileio->count - already);
1912 else
1914 result = pwrite(ovp->fd, &fileio->buffer[already], fileio->count - already,
1915 OVERLAPPED_OFFSET (lpOverlapped) + already);
1916 if ((result < 0) && (errno == ESPIPE))
1917 result = write(ovp->fd, &fileio->buffer[already], fileio->count - already);
1920 if ( (result<0) && ((errno == EAGAIN) || (errno == EINTR)))
1922 r = STATUS_PENDING;
1923 goto async_end;
1926 /* check to see if the transfer is complete */
1927 if(result<0)
1929 r = FILE_GetNtStatus ();
1930 goto async_end;
1933 lpOverlapped->InternalHigh += result;
1935 TRACE("wrote %d more bytes %ld/%d so far\n",result,lpOverlapped->InternalHigh,fileio->count);
1937 if(lpOverlapped->InternalHigh < fileio->count)
1938 r = STATUS_PENDING;
1939 else
1940 r = STATUS_SUCCESS;
1942 async_end:
1943 lpOverlapped->Internal = r;
1946 /***********************************************************************
1947 * FILE_WriteFileEx
1949 static BOOL FILE_WriteFileEx(HANDLE hFile, LPCVOID buffer, DWORD bytesToWrite,
1950 LPOVERLAPPED overlapped,
1951 LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine,
1952 HANDLE hEvent)
1954 async_fileio *ovp;
1955 int fd;
1956 int flags;
1957 enum fd_type type;
1959 TRACE("file %p to buf %p num %ld %p func %p handle %p\n",
1960 hFile, buffer, bytesToWrite, overlapped, lpCompletionRoutine, hEvent);
1962 if (overlapped == NULL)
1964 SetLastError(ERROR_INVALID_PARAMETER);
1965 return FALSE;
1968 fd = FILE_GetUnixHandleType ( hFile, GENERIC_WRITE, &type, &flags );
1969 if ( fd < 0 )
1971 TRACE( "Couldn't get FD\n" );
1972 return FALSE;
1975 ovp = (async_fileio*) HeapAlloc(GetProcessHeap(), 0, sizeof (async_fileio));
1976 if(!ovp)
1978 TRACE("HeapAlloc Failed\n");
1979 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1980 goto error;
1983 ovp->async.ops = ( lpCompletionRoutine ? &fileio_async_ops : &fileio_nocomp_async_ops );
1984 ovp->async.handle = hFile;
1985 ovp->async.fd = fd;
1986 ovp->async.type = ASYNC_TYPE_WRITE;
1987 ovp->async.func = FILE_AsyncWriteService;
1988 ovp->lpOverlapped = overlapped;
1989 ovp->async.event = hEvent;
1990 ovp->buffer = (LPVOID) buffer;
1991 ovp->count = bytesToWrite;
1992 ovp->completion_func = lpCompletionRoutine;
1993 ovp->fd_type = type;
1995 return !register_new_async (&ovp->async);
1997 error:
1998 close (fd);
1999 return FALSE;
2002 /***********************************************************************
2003 * WriteFileEx (KERNEL32.@)
2005 BOOL WINAPI WriteFileEx(HANDLE hFile, LPCVOID buffer, DWORD bytesToWrite,
2006 LPOVERLAPPED overlapped,
2007 LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine)
2009 overlapped->InternalHigh = 0;
2011 return FILE_WriteFileEx(hFile, buffer, bytesToWrite, overlapped, lpCompletionRoutine, INVALID_HANDLE_VALUE);
2014 /***********************************************************************
2015 * WriteFile (KERNEL32.@)
2017 BOOL WINAPI WriteFile( HANDLE hFile, LPCVOID buffer, DWORD bytesToWrite,
2018 LPDWORD bytesWritten, LPOVERLAPPED overlapped )
2020 int unix_handle, result, flags;
2021 enum fd_type type;
2023 TRACE("%p %p %ld %p %p\n", hFile, buffer, bytesToWrite,
2024 bytesWritten, overlapped );
2026 if (bytesWritten) *bytesWritten = 0; /* Do this before anything else */
2027 if (!bytesToWrite) return TRUE;
2029 unix_handle = FILE_GetUnixHandleType( hFile, GENERIC_WRITE, &type, &flags );
2031 if (flags & FD_FLAG_OVERLAPPED)
2033 if (unix_handle == -1) return FALSE;
2034 if ( (overlapped==NULL) || NtResetEvent( overlapped->hEvent, NULL ) )
2036 TRACE("Overlapped not specified or invalid event flag\n");
2037 close(unix_handle);
2038 SetLastError(ERROR_INVALID_PARAMETER);
2039 return FALSE;
2042 close(unix_handle);
2043 overlapped->InternalHigh = 0;
2045 if(!FILE_WriteFileEx(hFile, buffer, bytesToWrite, overlapped, NULL, overlapped->hEvent))
2046 return FALSE;
2048 if ( !GetOverlappedResult (hFile, overlapped, bytesWritten, FALSE) )
2050 if ( GetLastError() == ERROR_IO_INCOMPLETE )
2051 SetLastError ( ERROR_IO_PENDING );
2052 return FALSE;
2055 return TRUE;
2058 switch(type)
2060 case FD_TYPE_CONSOLE:
2061 TRACE("%p %s %ld %p %p\n", hFile, debugstr_an(buffer, bytesToWrite), bytesToWrite,
2062 bytesWritten, overlapped );
2063 return FILE_WriteConsole(hFile, buffer, bytesToWrite, bytesWritten, NULL);
2065 case FD_TYPE_DEFAULT:
2066 if (unix_handle == -1) return FALSE;
2068 if(overlapped)
2070 DWORD highOffset = overlapped->OffsetHigh;
2071 if ( (INVALID_SET_FILE_POINTER == SetFilePointer(hFile, overlapped->Offset,
2072 &highOffset, FILE_BEGIN)) &&
2073 (GetLastError() != NO_ERROR) )
2075 close(unix_handle);
2076 return FALSE;
2079 break;
2081 default:
2082 if (unix_handle == -1)
2083 return FALSE;
2084 if (overlapped)
2086 close(unix_handle);
2087 SetLastError(ERROR_INVALID_PARAMETER);
2088 return FALSE;
2090 break;
2093 if(overlapped)
2095 off_t offset = OVERLAPPED_OFFSET(overlapped);
2096 if(lseek(unix_handle, offset, SEEK_SET) == -1)
2098 close(unix_handle);
2099 SetLastError(ERROR_INVALID_PARAMETER);
2100 return FALSE;
2104 /* synchronous file write */
2105 while ((result = write( unix_handle, buffer, bytesToWrite )) == -1)
2107 if ((errno == EAGAIN) || (errno == EINTR)) continue;
2108 if ((errno == EFAULT) && !IsBadReadPtr( buffer, bytesToWrite )) continue;
2109 if (errno == ENOSPC)
2110 SetLastError( ERROR_DISK_FULL );
2111 else
2112 FILE_SetDosError();
2113 break;
2115 close( unix_handle );
2116 if (result == -1) return FALSE;
2117 if (bytesWritten) *bytesWritten = result;
2118 return TRUE;
2122 /***********************************************************************
2123 * _hread (KERNEL.349)
2125 LONG WINAPI WIN16_hread( HFILE16 hFile, SEGPTR buffer, LONG count )
2127 LONG maxlen;
2129 TRACE("%d %08lx %ld\n",
2130 hFile, (DWORD)buffer, count );
2132 /* Some programs pass a count larger than the allocated buffer */
2133 maxlen = GetSelectorLimit16( SELECTOROF(buffer) ) - OFFSETOF(buffer) + 1;
2134 if (count > maxlen) count = maxlen;
2135 return _lread((HFILE)DosFileHandleToWin32Handle(hFile), MapSL(buffer), count );
2139 /***********************************************************************
2140 * _lread (KERNEL.82)
2142 UINT16 WINAPI WIN16_lread( HFILE16 hFile, SEGPTR buffer, UINT16 count )
2144 return (UINT16)WIN16_hread( hFile, buffer, (LONG)count );
2148 /***********************************************************************
2149 * _lread (KERNEL32.@)
2151 UINT WINAPI _lread( HFILE handle, LPVOID buffer, UINT count )
2153 DWORD result;
2154 if (!ReadFile( (HANDLE)handle, buffer, count, &result, NULL )) return -1;
2155 return result;
2159 /***********************************************************************
2160 * _lread16 (KERNEL.82)
2162 UINT16 WINAPI _lread16( HFILE16 hFile, LPVOID buffer, UINT16 count )
2164 return (UINT16)_lread((HFILE)DosFileHandleToWin32Handle(hFile), buffer, (LONG)count );
2168 /***********************************************************************
2169 * _lcreat (KERNEL.83)
2171 HFILE16 WINAPI _lcreat16( LPCSTR path, INT16 attr )
2173 return Win32HandleToDosFileHandle( (HANDLE)_lcreat( path, attr ) );
2177 /***********************************************************************
2178 * _lcreat (KERNEL32.@)
2180 HFILE WINAPI _lcreat( LPCSTR path, INT attr )
2182 /* Mask off all flags not explicitly allowed by the doc */
2183 attr &= FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM;
2184 TRACE("%s %02x\n", path, attr );
2185 return (HFILE)CreateFileA( path, GENERIC_READ | GENERIC_WRITE,
2186 FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
2187 CREATE_ALWAYS, attr, 0 );
2191 /***********************************************************************
2192 * SetFilePointer (KERNEL32.@)
2194 DWORD WINAPI SetFilePointer( HANDLE hFile, LONG distance, LONG *highword,
2195 DWORD method )
2197 DWORD ret = INVALID_SET_FILE_POINTER;
2199 TRACE("handle %p offset %ld high %ld origin %ld\n",
2200 hFile, distance, highword?*highword:0, method );
2202 SERVER_START_REQ( set_file_pointer )
2204 req->handle = hFile;
2205 req->low = distance;
2206 req->high = highword ? *highword : (distance >= 0) ? 0 : -1;
2207 /* FIXME: assumes 1:1 mapping between Windows and Unix seek constants */
2208 req->whence = method;
2209 SetLastError( 0 );
2210 if (!wine_server_call_err( req ))
2212 ret = reply->new_low;
2213 if (highword) *highword = reply->new_high;
2216 SERVER_END_REQ;
2217 return ret;
2221 /***********************************************************************
2222 * _llseek (KERNEL.84)
2224 * FIXME:
2225 * Seeking before the start of the file should be allowed for _llseek16,
2226 * but cause subsequent I/O operations to fail (cf. interrupt list)
2229 LONG WINAPI _llseek16( HFILE16 hFile, LONG lOffset, INT16 nOrigin )
2231 return SetFilePointer( DosFileHandleToWin32Handle(hFile), lOffset, NULL, nOrigin );
2235 /***********************************************************************
2236 * _llseek (KERNEL32.@)
2238 LONG WINAPI _llseek( HFILE hFile, LONG lOffset, INT nOrigin )
2240 return SetFilePointer( (HANDLE)hFile, lOffset, NULL, nOrigin );
2244 /***********************************************************************
2245 * _lopen (KERNEL.85)
2247 HFILE16 WINAPI _lopen16( LPCSTR path, INT16 mode )
2249 return Win32HandleToDosFileHandle( (HANDLE)_lopen( path, mode ) );
2253 /***********************************************************************
2254 * _lopen (KERNEL32.@)
2256 HFILE WINAPI _lopen( LPCSTR path, INT mode )
2258 DWORD access, sharing;
2260 TRACE("('%s',%04x)\n", path, mode );
2261 FILE_ConvertOFMode( mode, &access, &sharing );
2262 return (HFILE)CreateFileA( path, access, sharing, NULL, OPEN_EXISTING, 0, 0 );
2266 /***********************************************************************
2267 * _lwrite (KERNEL.86)
2269 UINT16 WINAPI _lwrite16( HFILE16 hFile, LPCSTR buffer, UINT16 count )
2271 return (UINT16)_hwrite( (HFILE)DosFileHandleToWin32Handle(hFile), buffer, (LONG)count );
2274 /***********************************************************************
2275 * _lwrite (KERNEL32.@)
2277 UINT WINAPI _lwrite( HFILE hFile, LPCSTR buffer, UINT count )
2279 return (UINT)_hwrite( hFile, buffer, (LONG)count );
2283 /***********************************************************************
2284 * _hread16 (KERNEL.349)
2286 LONG WINAPI _hread16( HFILE16 hFile, LPVOID buffer, LONG count)
2288 return _lread( (HFILE)DosFileHandleToWin32Handle(hFile), buffer, count );
2292 /***********************************************************************
2293 * _hread (KERNEL32.@)
2295 LONG WINAPI _hread( HFILE hFile, LPVOID buffer, LONG count)
2297 return _lread( hFile, buffer, count );
2301 /***********************************************************************
2302 * _hwrite (KERNEL.350)
2304 LONG WINAPI _hwrite16( HFILE16 hFile, LPCSTR buffer, LONG count )
2306 return _hwrite( (HFILE)DosFileHandleToWin32Handle(hFile), buffer, count );
2310 /***********************************************************************
2311 * _hwrite (KERNEL32.@)
2313 * experimentation yields that _lwrite:
2314 * o truncates the file at the current position with
2315 * a 0 len write
2316 * o returns 0 on a 0 length write
2317 * o works with console handles
2320 LONG WINAPI _hwrite( HFILE handle, LPCSTR buffer, LONG count )
2322 DWORD result;
2324 TRACE("%d %p %ld\n", handle, buffer, count );
2326 if (!count)
2328 /* Expand or truncate at current position */
2329 if (!SetEndOfFile( (HANDLE)handle )) return HFILE_ERROR;
2330 return 0;
2332 if (!WriteFile( (HANDLE)handle, buffer, count, &result, NULL ))
2333 return HFILE_ERROR;
2334 return result;
2338 /***********************************************************************
2339 * SetHandleCount (KERNEL.199)
2341 UINT16 WINAPI SetHandleCount16( UINT16 count )
2343 return SetHandleCount( count );
2347 /*************************************************************************
2348 * SetHandleCount (KERNEL32.@)
2350 UINT WINAPI SetHandleCount( UINT count )
2352 return min( 256, count );
2356 /***********************************************************************
2357 * FlushFileBuffers (KERNEL32.@)
2359 BOOL WINAPI FlushFileBuffers( HANDLE hFile )
2361 BOOL ret;
2362 SERVER_START_REQ( flush_file )
2364 req->handle = hFile;
2365 ret = !wine_server_call_err( req );
2367 SERVER_END_REQ;
2368 return ret;
2372 /**************************************************************************
2373 * SetEndOfFile (KERNEL32.@)
2375 BOOL WINAPI SetEndOfFile( HANDLE hFile )
2377 BOOL ret;
2378 SERVER_START_REQ( truncate_file )
2380 req->handle = hFile;
2381 ret = !wine_server_call_err( req );
2383 SERVER_END_REQ;
2384 return ret;
2388 /***********************************************************************
2389 * DeleteFile (KERNEL.146)
2391 BOOL16 WINAPI DeleteFile16( LPCSTR path )
2393 return DeleteFileA( path );
2397 /***********************************************************************
2398 * DeleteFileW (KERNEL32.@)
2400 BOOL WINAPI DeleteFileW( LPCWSTR path )
2402 DOS_FULL_NAME full_name;
2403 HANDLE hFile;
2405 TRACE("%s\n", debugstr_w(path) );
2406 if (!path || !*path)
2408 SetLastError(ERROR_PATH_NOT_FOUND);
2409 return FALSE;
2411 if (DOSFS_GetDevice( path ))
2413 WARN("cannot remove DOS device %s!\n", debugstr_w(path));
2414 SetLastError( ERROR_FILE_NOT_FOUND );
2415 return FALSE;
2418 if (!DOSFS_GetFullName( path, TRUE, &full_name )) return FALSE;
2420 /* check if we are allowed to delete the source */
2421 hFile = FILE_CreateFile( full_name.long_name, GENERIC_READ|GENERIC_WRITE, 0,
2422 NULL, OPEN_EXISTING, 0, 0, TRUE,
2423 GetDriveTypeW( full_name.short_name ) );
2424 if (!hFile) return FALSE;
2426 if (unlink( full_name.long_name ) == -1)
2428 FILE_SetDosError();
2429 CloseHandle(hFile);
2430 return FALSE;
2432 CloseHandle(hFile);
2433 return TRUE;
2437 /***********************************************************************
2438 * DeleteFileA (KERNEL32.@)
2440 BOOL WINAPI DeleteFileA( LPCSTR path )
2442 UNICODE_STRING pathW;
2443 BOOL ret = FALSE;
2445 if (!path)
2447 SetLastError(ERROR_INVALID_PARAMETER);
2448 return FALSE;
2451 if (RtlCreateUnicodeStringFromAsciiz(&pathW, path))
2453 ret = DeleteFileW(pathW.Buffer);
2454 RtlFreeUnicodeString(&pathW);
2456 else
2457 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
2458 return ret;
2462 /***********************************************************************
2463 * GetFileType (KERNEL32.@)
2465 DWORD WINAPI GetFileType( HANDLE hFile )
2467 DWORD ret = FILE_TYPE_UNKNOWN;
2468 SERVER_START_REQ( get_file_info )
2470 req->handle = hFile;
2471 if (!wine_server_call_err( req )) ret = reply->type;
2473 SERVER_END_REQ;
2474 return ret;
2478 /* check if a file name is for an executable file (.exe or .com) */
2479 inline static BOOL is_executable( const char *name )
2481 int len = strlen(name);
2483 if (len < 4) return FALSE;
2484 return (!strcasecmp( name + len - 4, ".exe" ) ||
2485 !strcasecmp( name + len - 4, ".com" ));
2489 /***********************************************************************
2490 * FILE_AddBootRenameEntry
2492 * Adds an entry to the registry that is loaded when windows boots and
2493 * checks if there are some files to be removed or renamed/moved.
2494 * <fn1> has to be valid and <fn2> may be NULL. If both pointers are
2495 * non-NULL then the file is moved, otherwise it is deleted. The
2496 * entry of the registrykey is always appended with two zero
2497 * terminated strings. If <fn2> is NULL then the second entry is
2498 * simply a single 0-byte. Otherwise the second filename goes
2499 * there. The entries are prepended with \??\ before the path and the
2500 * second filename gets also a '!' as the first character if
2501 * MOVEFILE_REPLACE_EXISTING is set. After the final string another
2502 * 0-byte follows to indicate the end of the strings.
2503 * i.e.:
2504 * \??\D:\test\file1[0]
2505 * !\??\D:\test\file1_renamed[0]
2506 * \??\D:\Test|delete[0]
2507 * [0] <- file is to be deleted, second string empty
2508 * \??\D:\test\file2[0]
2509 * !\??\D:\test\file2_renamed[0]
2510 * [0] <- indicates end of strings
2512 * or:
2513 * \??\D:\test\file1[0]
2514 * !\??\D:\test\file1_renamed[0]
2515 * \??\D:\Test|delete[0]
2516 * [0] <- file is to be deleted, second string empty
2517 * [0] <- indicates end of strings
2520 static BOOL FILE_AddBootRenameEntry( LPCWSTR fn1, LPCWSTR fn2, DWORD flags )
2522 static const WCHAR PreString[] = {'\\','?','?','\\',0};
2523 static const WCHAR ValueName[] = {'P','e','n','d','i','n','g',
2524 'F','i','l','e','R','e','n','a','m','e',
2525 'O','p','e','r','a','t','i','o','n','s',0};
2526 static const WCHAR SessionW[] = {'M','a','c','h','i','n','e','\\',
2527 'S','y','s','t','e','m','\\',
2528 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
2529 'C','o','n','t','r','o','l','\\',
2530 'S','e','s','s','i','o','n',' ','M','a','n','a','g','e','r',0};
2531 static const int info_size = FIELD_OFFSET( KEY_VALUE_PARTIAL_INFORMATION, Data );
2533 OBJECT_ATTRIBUTES attr;
2534 UNICODE_STRING nameW;
2535 KEY_VALUE_PARTIAL_INFORMATION *info;
2536 BOOL rc = FALSE;
2537 HKEY Reboot = 0;
2538 DWORD len0, len1, len2;
2539 DWORD DataSize = 0;
2540 BYTE *Buffer = NULL;
2541 WCHAR *p;
2543 attr.Length = sizeof(attr);
2544 attr.RootDirectory = 0;
2545 attr.ObjectName = &nameW;
2546 attr.Attributes = 0;
2547 attr.SecurityDescriptor = NULL;
2548 attr.SecurityQualityOfService = NULL;
2549 RtlInitUnicodeString( &nameW, SessionW );
2551 if (NtCreateKey( &Reboot, KEY_ALL_ACCESS, &attr, 0, NULL, 0, NULL ) != STATUS_SUCCESS)
2553 WARN("Error creating key for reboot managment [%s]\n",
2554 "SYSTEM\\CurrentControlSet\\Control\\Session Manager");
2555 return FALSE;
2558 len0 = strlenW(PreString);
2559 len1 = strlenW(fn1) + len0 + 1;
2560 if (fn2)
2562 len2 = strlenW(fn2) + len0 + 1;
2563 if (flags & MOVEFILE_REPLACE_EXISTING) len2++; /* Plus 1 because of the leading '!' */
2565 else len2 = 1; /* minimum is the 0 characters for the empty second string */
2567 /* convert characters to bytes */
2568 len0 *= sizeof(WCHAR);
2569 len1 *= sizeof(WCHAR);
2570 len2 *= sizeof(WCHAR);
2572 RtlInitUnicodeString( &nameW, ValueName );
2574 /* First we check if the key exists and if so how many bytes it already contains. */
2575 if (NtQueryValueKey( Reboot, &nameW, KeyValuePartialInformation,
2576 NULL, 0, &DataSize ) == STATUS_BUFFER_OVERFLOW)
2578 if (!(Buffer = HeapAlloc( GetProcessHeap(), 0, DataSize + len1 + len2 + sizeof(WCHAR) )))
2579 goto Quit;
2580 if (NtQueryValueKey( Reboot, &nameW, KeyValuePartialInformation,
2581 Buffer, DataSize, &DataSize )) goto Quit;
2582 info = (KEY_VALUE_PARTIAL_INFORMATION *)Buffer;
2583 if (info->Type != REG_MULTI_SZ) goto Quit;
2584 if (DataSize > sizeof(info)) DataSize -= sizeof(WCHAR); /* remove terminating null (will be added back later) */
2586 else
2588 DataSize = info_size;
2589 if (!(Buffer = HeapAlloc( GetProcessHeap(), 0, DataSize + len1 + len2 + sizeof(WCHAR) )))
2590 goto Quit;
2593 p = (WCHAR *)(Buffer + DataSize);
2594 strcpyW( p, PreString );
2595 strcatW( p, fn1 );
2596 DataSize += len1;
2597 if (fn2)
2599 p = (WCHAR *)(Buffer + DataSize);
2600 if (flags & MOVEFILE_REPLACE_EXISTING)
2601 *p++ = '!';
2602 strcpyW( p, PreString );
2603 strcatW( p, fn2 );
2604 DataSize += len2;
2606 else
2608 p = (WCHAR *)(Buffer + DataSize);
2609 *p = 0;
2610 DataSize += sizeof(WCHAR);
2613 /* add final null */
2614 p = (WCHAR *)(Buffer + DataSize);
2615 *p = 0;
2616 DataSize += sizeof(WCHAR);
2618 rc = !NtSetValueKey(Reboot, &nameW, 0, REG_MULTI_SZ, Buffer + info_size, DataSize - info_size);
2620 Quit:
2621 if (Reboot) NtClose(Reboot);
2622 if (Buffer) HeapFree( GetProcessHeap(), 0, Buffer );
2623 return(rc);
2627 /**************************************************************************
2628 * MoveFileExW (KERNEL32.@)
2630 BOOL WINAPI MoveFileExW( LPCWSTR fn1, LPCWSTR fn2, DWORD flag )
2632 DOS_FULL_NAME full_name1, full_name2;
2633 HANDLE hFile;
2634 DWORD attr = INVALID_FILE_ATTRIBUTES;
2636 TRACE("(%s,%s,%04lx)\n", debugstr_w(fn1), debugstr_w(fn2), flag);
2638 /* FIXME: <Gerhard W. Gruber>sparhawk@gmx.at
2639 In case of W9x and lesser this function should return 120 (ERROR_CALL_NOT_IMPLEMENTED)
2640 to be really compatible. Most programs wont have any problems though. In case
2641 you encounter one, this is what you should return here. I don't know what's up
2642 with NT 3.5. Is this function available there or not?
2643 Does anybody really care about 3.5? :)
2646 /* Filename1 has to be always set to a valid path. Filename2 may be NULL
2647 if the source file has to be deleted.
2649 if (!fn1) {
2650 SetLastError(ERROR_INVALID_PARAMETER);
2651 return FALSE;
2654 /* This function has to be run through in order to process the name properly.
2655 If the BOOTDELAY flag is set, the file doesn't need to exist though. At least
2656 that is the behaviour on NT 4.0. The operation accepts the filenames as
2657 they are given but it can't reply with a reasonable returncode. Success
2658 means in that case success for entering the values into the registry.
2660 if(!DOSFS_GetFullName( fn1, TRUE, &full_name1 ))
2662 if(!(flag & MOVEFILE_DELAY_UNTIL_REBOOT))
2663 return FALSE;
2666 if (fn2) /* !fn2 means delete fn1 */
2668 if (DOSFS_GetFullName( fn2, TRUE, &full_name2 ))
2670 if(!(flag & MOVEFILE_DELAY_UNTIL_REBOOT))
2672 /* target exists, check if we may overwrite */
2673 if (!(flag & MOVEFILE_REPLACE_EXISTING))
2675 SetLastError( ERROR_FILE_EXISTS );
2676 return FALSE;
2680 else
2682 if (!DOSFS_GetFullName( fn2, FALSE, &full_name2 ))
2684 if(!(flag & MOVEFILE_DELAY_UNTIL_REBOOT))
2685 return FALSE;
2689 /* Source name and target path are valid */
2691 if (flag & MOVEFILE_DELAY_UNTIL_REBOOT)
2693 /* FIXME: (bon@elektron.ikp.physik.th-darmstadt.de 970706)
2694 Perhaps we should queue these command and execute it
2695 when exiting... What about using on_exit(2)
2697 FIXME("Please move existing file %s to file %s when Wine has finished\n",
2698 debugstr_w(fn1), debugstr_w(fn2));
2699 return FILE_AddBootRenameEntry( fn1, fn2, flag );
2702 attr = GetFileAttributesW( fn1 );
2703 if ( attr == INVALID_FILE_ATTRIBUTES ) return FALSE;
2705 /* check if we are allowed to rename the source */
2706 hFile = FILE_CreateFile( full_name1.long_name, 0, 0,
2707 NULL, OPEN_EXISTING, 0, 0, TRUE,
2708 GetDriveTypeW( full_name1.short_name ) );
2709 if (!hFile)
2711 if (GetLastError() != ERROR_ACCESS_DENIED) return FALSE;
2712 if ( !(attr & FILE_ATTRIBUTE_DIRECTORY) ) return FALSE;
2713 /* if it's a directory we can continue */
2715 else CloseHandle(hFile);
2717 /* check, if we are allowed to delete the destination,
2718 ** (but the file not being there is fine) */
2719 hFile = FILE_CreateFile( full_name2.long_name, GENERIC_READ|GENERIC_WRITE, 0,
2720 NULL, OPEN_EXISTING, 0, 0, TRUE,
2721 GetDriveTypeW( full_name2.short_name ) );
2722 if(!hFile && GetLastError() != ERROR_FILE_NOT_FOUND) return FALSE;
2723 CloseHandle(hFile);
2725 if (full_name1.drive != full_name2.drive)
2727 if (!(flag & MOVEFILE_COPY_ALLOWED))
2729 SetLastError( ERROR_NOT_SAME_DEVICE );
2730 return FALSE;
2732 else if ( attr & FILE_ATTRIBUTE_DIRECTORY )
2734 /* Strange, but that's what Windows returns */
2735 SetLastError ( ERROR_ACCESS_DENIED );
2736 return FALSE;
2739 if (rename( full_name1.long_name, full_name2.long_name ) == -1)
2740 /* Try copy/delete unless it's a directory. */
2741 /* FIXME: This does not handle the (unlikely) case that the two locations
2742 are on the same Wine drive, but on different Unix file systems. */
2744 if ( attr & FILE_ATTRIBUTE_DIRECTORY )
2746 FILE_SetDosError();
2747 return FALSE;
2749 else
2751 if ( ! CopyFileW( fn1, fn2, !(flag & MOVEFILE_REPLACE_EXISTING) ))
2752 return FALSE;
2753 if ( ! DeleteFileW ( fn1 ) )
2754 return FALSE;
2757 if (is_executable( full_name1.long_name ) != is_executable( full_name2.long_name ))
2759 struct stat fstat;
2760 if (stat( full_name2.long_name, &fstat ) != -1)
2762 if (is_executable( full_name2.long_name ))
2763 /* set executable bit where read bit is set */
2764 fstat.st_mode |= (fstat.st_mode & 0444) >> 2;
2765 else
2766 fstat.st_mode &= ~0111;
2767 chmod( full_name2.long_name, fstat.st_mode );
2770 return TRUE;
2772 else /* fn2 == NULL means delete source */
2774 if (flag & MOVEFILE_DELAY_UNTIL_REBOOT)
2776 if (flag & MOVEFILE_COPY_ALLOWED) {
2777 WARN("Illegal flag\n");
2778 SetLastError( ERROR_GEN_FAILURE );
2779 return FALSE;
2781 /* FIXME: (bon@elektron.ikp.physik.th-darmstadt.de 970706)
2782 Perhaps we should queue these command and execute it
2783 when exiting... What about using on_exit(2)
2785 FIXME("Please delete file %s when Wine has finished\n", debugstr_w(fn1));
2786 return FILE_AddBootRenameEntry( fn1, NULL, flag );
2789 if (unlink( full_name1.long_name ) == -1)
2791 FILE_SetDosError();
2792 return FALSE;
2794 return TRUE; /* successfully deleted */
2798 /**************************************************************************
2799 * MoveFileExA (KERNEL32.@)
2801 BOOL WINAPI MoveFileExA( LPCSTR fn1, LPCSTR fn2, DWORD flag )
2803 UNICODE_STRING fn1W, fn2W;
2804 BOOL ret;
2806 if (!fn1)
2808 SetLastError(ERROR_INVALID_PARAMETER);
2809 return FALSE;
2812 RtlCreateUnicodeStringFromAsciiz(&fn1W, fn1);
2813 if (fn2) RtlCreateUnicodeStringFromAsciiz(&fn2W, fn2);
2814 else fn2W.Buffer = NULL;
2816 ret = MoveFileExW( fn1W.Buffer, fn2W.Buffer, flag );
2818 RtlFreeUnicodeString(&fn1W);
2819 RtlFreeUnicodeString(&fn2W);
2820 return ret;
2824 /**************************************************************************
2825 * MoveFileW (KERNEL32.@)
2827 * Move file or directory
2829 BOOL WINAPI MoveFileW( LPCWSTR fn1, LPCWSTR fn2 )
2831 DOS_FULL_NAME full_name1, full_name2;
2832 struct stat fstat;
2834 if (!fn1 || !fn2)
2836 SetLastError(ERROR_INVALID_PARAMETER);
2837 return FALSE;
2840 TRACE("(%s,%s)\n", debugstr_w(fn1), debugstr_w(fn2) );
2842 if (!DOSFS_GetFullName( fn1, TRUE, &full_name1 )) return FALSE;
2843 if (DOSFS_GetFullName( fn2, TRUE, &full_name2 )) {
2844 /* The new name must not already exist */
2845 SetLastError(ERROR_ALREADY_EXISTS);
2846 return FALSE;
2848 if (!DOSFS_GetFullName( fn2, FALSE, &full_name2 )) return FALSE;
2850 if (full_name1.drive == full_name2.drive) /* move */
2851 return MoveFileExW( fn1, fn2, MOVEFILE_COPY_ALLOWED );
2853 /* copy */
2854 if (stat( full_name1.long_name, &fstat ))
2856 WARN("Invalid source file %s\n",
2857 full_name1.long_name);
2858 FILE_SetDosError();
2859 return FALSE;
2861 if (S_ISDIR(fstat.st_mode)) {
2862 /* No Move for directories across file systems */
2863 /* FIXME: Use right error code */
2864 SetLastError( ERROR_GEN_FAILURE );
2865 return FALSE;
2867 return CopyFileW(fn1, fn2, TRUE); /*fail, if exist */
2871 /**************************************************************************
2872 * MoveFileA (KERNEL32.@)
2874 BOOL WINAPI MoveFileA( LPCSTR fn1, LPCSTR fn2 )
2876 UNICODE_STRING fn1W, fn2W;
2877 BOOL ret;
2879 if (!fn1 || !fn2)
2881 SetLastError(ERROR_INVALID_PARAMETER);
2882 return FALSE;
2885 RtlCreateUnicodeStringFromAsciiz(&fn1W, fn1);
2886 RtlCreateUnicodeStringFromAsciiz(&fn2W, fn2);
2888 ret = MoveFileW( fn1W.Buffer, fn2W.Buffer );
2890 RtlFreeUnicodeString(&fn1W);
2891 RtlFreeUnicodeString(&fn2W);
2892 return ret;
2896 /**************************************************************************
2897 * CopyFileW (KERNEL32.@)
2899 BOOL WINAPI CopyFileW( LPCWSTR source, LPCWSTR dest, BOOL fail_if_exists )
2901 HANDLE h1, h2;
2902 BY_HANDLE_FILE_INFORMATION info;
2903 DWORD count;
2904 BOOL ret = FALSE;
2905 char buffer[2048];
2907 if (!source || !dest)
2909 SetLastError(ERROR_INVALID_PARAMETER);
2910 return FALSE;
2913 TRACE("%s -> %s\n", debugstr_w(source), debugstr_w(dest));
2915 if ((h1 = CreateFileW(source, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE,
2916 NULL, OPEN_EXISTING, 0, 0)) == INVALID_HANDLE_VALUE)
2918 WARN("Unable to open source %s\n", debugstr_w(source));
2919 return FALSE;
2922 if (!GetFileInformationByHandle( h1, &info ))
2924 WARN("GetFileInformationByHandle returned error for %s\n", debugstr_w(source));
2925 CloseHandle( h1 );
2926 return FALSE;
2929 if ((h2 = CreateFileW( dest, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
2930 fail_if_exists ? CREATE_NEW : CREATE_ALWAYS,
2931 info.dwFileAttributes, h1 )) == INVALID_HANDLE_VALUE)
2933 WARN("Unable to open dest %s\n", debugstr_w(dest));
2934 CloseHandle( h1 );
2935 return FALSE;
2938 while (ReadFile( h1, buffer, sizeof(buffer), &count, NULL ) && count)
2940 char *p = buffer;
2941 while (count != 0)
2943 DWORD res;
2944 if (!WriteFile( h2, p, count, &res, NULL ) || !res) goto done;
2945 p += res;
2946 count -= res;
2949 ret = TRUE;
2950 done:
2951 CloseHandle( h1 );
2952 CloseHandle( h2 );
2953 return ret;
2957 /**************************************************************************
2958 * CopyFileA (KERNEL32.@)
2960 BOOL WINAPI CopyFileA( LPCSTR source, LPCSTR dest, BOOL fail_if_exists)
2962 UNICODE_STRING sourceW, destW;
2963 BOOL ret;
2965 if (!source || !dest)
2967 SetLastError(ERROR_INVALID_PARAMETER);
2968 return FALSE;
2971 RtlCreateUnicodeStringFromAsciiz(&sourceW, source);
2972 RtlCreateUnicodeStringFromAsciiz(&destW, dest);
2974 ret = CopyFileW(sourceW.Buffer, destW.Buffer, fail_if_exists);
2976 RtlFreeUnicodeString(&sourceW);
2977 RtlFreeUnicodeString(&destW);
2978 return ret;
2982 /**************************************************************************
2983 * CopyFileExW (KERNEL32.@)
2985 * This implementation ignores most of the extra parameters passed-in into
2986 * the "ex" version of the method and calls the CopyFile method.
2987 * It will have to be fixed eventually.
2989 BOOL WINAPI CopyFileExW(LPCWSTR sourceFilename, LPCWSTR destFilename,
2990 LPPROGRESS_ROUTINE progressRoutine, LPVOID appData,
2991 LPBOOL cancelFlagPointer, DWORD copyFlags)
2994 * Interpret the only flag that CopyFile can interpret.
2996 return CopyFileW(sourceFilename, destFilename, (copyFlags & COPY_FILE_FAIL_IF_EXISTS) != 0);
2999 /**************************************************************************
3000 * CopyFileExA (KERNEL32.@)
3002 BOOL WINAPI CopyFileExA(LPCSTR sourceFilename, LPCSTR destFilename,
3003 LPPROGRESS_ROUTINE progressRoutine, LPVOID appData,
3004 LPBOOL cancelFlagPointer, DWORD copyFlags)
3006 UNICODE_STRING sourceW, destW;
3007 BOOL ret;
3009 if (!sourceFilename || !destFilename)
3011 SetLastError(ERROR_INVALID_PARAMETER);
3012 return FALSE;
3015 RtlCreateUnicodeStringFromAsciiz(&sourceW, sourceFilename);
3016 RtlCreateUnicodeStringFromAsciiz(&destW, destFilename);
3018 ret = CopyFileExW(sourceW.Buffer, destW.Buffer, progressRoutine, appData,
3019 cancelFlagPointer, copyFlags);
3021 RtlFreeUnicodeString(&sourceW);
3022 RtlFreeUnicodeString(&destW);
3023 return ret;
3027 /***********************************************************************
3028 * SetFileTime (KERNEL32.@)
3030 BOOL WINAPI SetFileTime( HANDLE hFile,
3031 const FILETIME *lpCreationTime,
3032 const FILETIME *lpLastAccessTime,
3033 const FILETIME *lpLastWriteTime )
3035 BOOL ret;
3036 SERVER_START_REQ( set_file_time )
3038 req->handle = hFile;
3039 if (lpLastAccessTime)
3040 RtlTimeToSecondsSince1970( (PLARGE_INTEGER) lpLastAccessTime, (DWORD *)&req->access_time );
3041 else
3042 req->access_time = 0; /* FIXME */
3043 if (lpLastWriteTime)
3044 RtlTimeToSecondsSince1970( (PLARGE_INTEGER) lpLastWriteTime, (DWORD *)&req->write_time );
3045 else
3046 req->write_time = 0; /* FIXME */
3047 ret = !wine_server_call_err( req );
3049 SERVER_END_REQ;
3050 return ret;
3054 /**************************************************************************
3055 * LockFile (KERNEL32.@)
3057 BOOL WINAPI LockFile( HANDLE hFile, DWORD dwFileOffsetLow, DWORD dwFileOffsetHigh,
3058 DWORD nNumberOfBytesToLockLow, DWORD nNumberOfBytesToLockHigh )
3060 BOOL ret;
3062 FIXME("not implemented in server\n");
3064 SERVER_START_REQ( lock_file )
3066 req->handle = hFile;
3067 req->offset_low = dwFileOffsetLow;
3068 req->offset_high = dwFileOffsetHigh;
3069 req->count_low = nNumberOfBytesToLockLow;
3070 req->count_high = nNumberOfBytesToLockHigh;
3071 ret = !wine_server_call_err( req );
3073 SERVER_END_REQ;
3074 return ret;
3077 /**************************************************************************
3078 * LockFileEx [KERNEL32.@]
3080 * Locks a byte range within an open file for shared or exclusive access.
3082 * RETURNS
3083 * success: TRUE
3084 * failure: FALSE
3086 * NOTES
3087 * Per Microsoft docs, the third parameter (reserved) must be set to 0.
3089 BOOL WINAPI LockFileEx( HANDLE hFile, DWORD flags, DWORD reserved,
3090 DWORD nNumberOfBytesToLockLow, DWORD nNumberOfBytesToLockHigh,
3091 LPOVERLAPPED pOverlapped )
3093 FIXME("hFile=%p,flags=%ld,reserved=%ld,lowbytes=%ld,highbytes=%ld,overlapped=%p: stub.\n",
3094 hFile, flags, reserved, nNumberOfBytesToLockLow, nNumberOfBytesToLockHigh,
3095 pOverlapped);
3096 if (reserved == 0)
3097 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
3098 else
3100 ERR("reserved == %ld: Supposed to be 0??\n", reserved);
3101 SetLastError(ERROR_INVALID_PARAMETER);
3104 return FALSE;
3108 /**************************************************************************
3109 * UnlockFile (KERNEL32.@)
3111 BOOL WINAPI UnlockFile( HANDLE hFile, DWORD dwFileOffsetLow, DWORD dwFileOffsetHigh,
3112 DWORD nNumberOfBytesToUnlockLow, DWORD nNumberOfBytesToUnlockHigh )
3114 BOOL ret;
3116 FIXME("not implemented in server\n");
3118 SERVER_START_REQ( unlock_file )
3120 req->handle = hFile;
3121 req->offset_low = dwFileOffsetLow;
3122 req->offset_high = dwFileOffsetHigh;
3123 req->count_low = nNumberOfBytesToUnlockLow;
3124 req->count_high = nNumberOfBytesToUnlockHigh;
3125 ret = !wine_server_call_err( req );
3127 SERVER_END_REQ;
3128 return ret;
3132 /**************************************************************************
3133 * UnlockFileEx (KERNEL32.@)
3135 BOOL WINAPI UnlockFileEx(
3136 HANDLE hFile,
3137 DWORD dwReserved,
3138 DWORD nNumberOfBytesToUnlockLow,
3139 DWORD nNumberOfBytesToUnlockHigh,
3140 LPOVERLAPPED lpOverlapped
3143 FIXME("hFile=%p,reserved=%ld,lowbytes=%ld,highbytes=%ld,overlapped=%p: stub.\n",
3144 hFile, dwReserved, nNumberOfBytesToUnlockLow, nNumberOfBytesToUnlockHigh,
3145 lpOverlapped);
3146 if (dwReserved == 0)
3147 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
3148 else
3150 ERR("reserved == %ld: Supposed to be 0??\n", dwReserved);
3151 SetLastError(ERROR_INVALID_PARAMETER);
3154 return FALSE;
3158 #if 0
3160 struct DOS_FILE_LOCK {
3161 struct DOS_FILE_LOCK * next;
3162 DWORD base;
3163 DWORD len;
3164 DWORD processId;
3165 FILE_OBJECT * dos_file;
3166 /* char * unix_name;*/
3169 typedef struct DOS_FILE_LOCK DOS_FILE_LOCK;
3171 static DOS_FILE_LOCK *locks = NULL;
3172 static void DOS_RemoveFileLocks(FILE_OBJECT *file);
3175 /* Locks need to be mirrored because unix file locking is based
3176 * on the pid. Inside of wine there can be multiple WINE processes
3177 * that share the same unix pid.
3178 * Read's and writes should check these locks also - not sure
3179 * how critical that is at this point (FIXME).
3182 static BOOL DOS_AddLock(FILE_OBJECT *file, struct flock *f)
3184 DOS_FILE_LOCK *curr;
3185 DWORD processId;
3187 processId = GetCurrentProcessId();
3189 /* check if lock overlaps a current lock for the same file */
3190 #if 0
3191 for (curr = locks; curr; curr = curr->next) {
3192 if (strcmp(curr->unix_name, file->unix_name) == 0) {
3193 if ((f->l_start == curr->base) && (f->l_len == curr->len))
3194 return TRUE;/* region is identic */
3195 if ((f->l_start < (curr->base + curr->len)) &&
3196 ((f->l_start + f->l_len) > curr->base)) {
3197 /* region overlaps */
3198 return FALSE;
3202 #endif
3204 curr = HeapAlloc( GetProcessHeap(), 0, sizeof(DOS_FILE_LOCK) );
3205 curr->processId = GetCurrentProcessId();
3206 curr->base = f->l_start;
3207 curr->len = f->l_len;
3208 /* curr->unix_name = HEAP_strdupA( GetProcessHeap(), 0, file->unix_name);*/
3209 curr->next = locks;
3210 curr->dos_file = file;
3211 locks = curr;
3212 return TRUE;
3215 static void DOS_RemoveFileLocks(FILE_OBJECT *file)
3217 DWORD processId;
3218 DOS_FILE_LOCK **curr;
3219 DOS_FILE_LOCK *rem;
3221 processId = GetCurrentProcessId();
3222 curr = &locks;
3223 while (*curr) {
3224 if ((*curr)->dos_file == file) {
3225 rem = *curr;
3226 *curr = (*curr)->next;
3227 /* HeapFree( GetProcessHeap(), 0, rem->unix_name );*/
3228 HeapFree( GetProcessHeap(), 0, rem );
3230 else
3231 curr = &(*curr)->next;
3235 static BOOL DOS_RemoveLock(FILE_OBJECT *file, struct flock *f)
3237 DWORD processId;
3238 DOS_FILE_LOCK **curr;
3239 DOS_FILE_LOCK *rem;
3241 processId = GetCurrentProcessId();
3242 for (curr = &locks; *curr; curr = &(*curr)->next) {
3243 if ((*curr)->processId == processId &&
3244 (*curr)->dos_file == file &&
3245 (*curr)->base == f->l_start &&
3246 (*curr)->len == f->l_len) {
3247 /* this is the same lock */
3248 rem = *curr;
3249 *curr = (*curr)->next;
3250 /* HeapFree( GetProcessHeap(), 0, rem->unix_name );*/
3251 HeapFree( GetProcessHeap(), 0, rem );
3252 return TRUE;
3255 /* no matching lock found */
3256 return FALSE;
3260 /**************************************************************************
3261 * LockFile (KERNEL32.@)
3263 BOOL WINAPI LockFile(
3264 HANDLE hFile,DWORD dwFileOffsetLow,DWORD dwFileOffsetHigh,
3265 DWORD nNumberOfBytesToLockLow,DWORD nNumberOfBytesToLockHigh )
3267 struct flock f;
3268 FILE_OBJECT *file;
3270 TRACE("handle %d offsetlow=%ld offsethigh=%ld nbyteslow=%ld nbyteshigh=%ld\n",
3271 hFile, dwFileOffsetLow, dwFileOffsetHigh,
3272 nNumberOfBytesToLockLow, nNumberOfBytesToLockHigh);
3274 if (dwFileOffsetHigh || nNumberOfBytesToLockHigh) {
3275 FIXME("Unimplemented bytes > 32bits\n");
3276 return FALSE;
3279 f.l_start = dwFileOffsetLow;
3280 f.l_len = nNumberOfBytesToLockLow;
3281 f.l_whence = SEEK_SET;
3282 f.l_pid = 0;
3283 f.l_type = F_WRLCK;
3285 if (!(file = FILE_GetFile(hFile,0,NULL))) return FALSE;
3287 /* shadow locks internally */
3288 if (!DOS_AddLock(file, &f)) {
3289 SetLastError( ERROR_LOCK_VIOLATION );
3290 return FALSE;
3293 /* FIXME: Unix locking commented out for now, doesn't work with Excel */
3294 #ifdef USE_UNIX_LOCKS
3295 if (fcntl(file->unix_handle, F_SETLK, &f) == -1) {
3296 if (errno == EACCES || errno == EAGAIN) {
3297 SetLastError( ERROR_LOCK_VIOLATION );
3299 else {
3300 FILE_SetDosError();
3302 /* remove our internal copy of the lock */
3303 DOS_RemoveLock(file, &f);
3304 return FALSE;
3306 #endif
3307 return TRUE;
3311 /**************************************************************************
3312 * UnlockFile (KERNEL32.@)
3314 BOOL WINAPI UnlockFile(
3315 HANDLE hFile,DWORD dwFileOffsetLow,DWORD dwFileOffsetHigh,
3316 DWORD nNumberOfBytesToUnlockLow,DWORD nNumberOfBytesToUnlockHigh )
3318 FILE_OBJECT *file;
3319 struct flock f;
3321 TRACE("handle %d offsetlow=%ld offsethigh=%ld nbyteslow=%ld nbyteshigh=%ld\n",
3322 hFile, dwFileOffsetLow, dwFileOffsetHigh,
3323 nNumberOfBytesToUnlockLow, nNumberOfBytesToUnlockHigh);
3325 if (dwFileOffsetHigh || nNumberOfBytesToUnlockHigh) {
3326 WARN("Unimplemented bytes > 32bits\n");
3327 return FALSE;
3330 f.l_start = dwFileOffsetLow;
3331 f.l_len = nNumberOfBytesToUnlockLow;
3332 f.l_whence = SEEK_SET;
3333 f.l_pid = 0;
3334 f.l_type = F_UNLCK;
3336 if (!(file = FILE_GetFile(hFile,0,NULL))) return FALSE;
3338 DOS_RemoveLock(file, &f); /* ok if fails - may be another wine */
3340 /* FIXME: Unix locking commented out for now, doesn't work with Excel */
3341 #ifdef USE_UNIX_LOCKS
3342 if (fcntl(file->unix_handle, F_SETLK, &f) == -1) {
3343 FILE_SetDosError();
3344 return FALSE;
3346 #endif
3347 return TRUE;
3349 #endif
3351 /**************************************************************************
3352 * GetFileAttributesExW (KERNEL32.@)
3354 BOOL WINAPI GetFileAttributesExW(
3355 LPCWSTR lpFileName, GET_FILEEX_INFO_LEVELS fInfoLevelId,
3356 LPVOID lpFileInformation)
3358 DOS_FULL_NAME full_name;
3359 BY_HANDLE_FILE_INFORMATION info;
3361 if (!lpFileName || !lpFileInformation)
3363 SetLastError(ERROR_INVALID_PARAMETER);
3364 return FALSE;
3367 if (fInfoLevelId == GetFileExInfoStandard) {
3368 LPWIN32_FILE_ATTRIBUTE_DATA lpFad =
3369 (LPWIN32_FILE_ATTRIBUTE_DATA) lpFileInformation;
3370 if (!DOSFS_GetFullName( lpFileName, TRUE, &full_name )) return FALSE;
3371 if (!FILE_Stat( full_name.long_name, &info, NULL )) return FALSE;
3373 lpFad->dwFileAttributes = info.dwFileAttributes;
3374 lpFad->ftCreationTime = info.ftCreationTime;
3375 lpFad->ftLastAccessTime = info.ftLastAccessTime;
3376 lpFad->ftLastWriteTime = info.ftLastWriteTime;
3377 lpFad->nFileSizeHigh = info.nFileSizeHigh;
3378 lpFad->nFileSizeLow = info.nFileSizeLow;
3380 else {
3381 FIXME("invalid info level %d!\n", fInfoLevelId);
3382 return FALSE;
3385 return TRUE;
3389 /**************************************************************************
3390 * GetFileAttributesExA (KERNEL32.@)
3392 BOOL WINAPI GetFileAttributesExA(
3393 LPCSTR filename, GET_FILEEX_INFO_LEVELS fInfoLevelId,
3394 LPVOID lpFileInformation)
3396 UNICODE_STRING filenameW;
3397 BOOL ret = FALSE;
3399 if (!filename || !lpFileInformation)
3401 SetLastError(ERROR_INVALID_PARAMETER);
3402 return FALSE;
3405 if (RtlCreateUnicodeStringFromAsciiz(&filenameW, filename))
3407 ret = GetFileAttributesExW(filenameW.Buffer, fInfoLevelId, lpFileInformation);
3408 RtlFreeUnicodeString(&filenameW);
3410 else
3411 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
3412 return ret;
3415 /**************************************************************************
3416 * ReplaceFileW (KERNEL32.@)
3417 * ReplaceFile (KERNEL32.@)
3419 BOOL WINAPI ReplaceFileW(LPCWSTR lpReplacedFileName,LPCWSTR lpReplacementFileName,
3420 LPCWSTR lpBackupFileName, DWORD dwReplaceFlags,
3421 LPVOID lpExclude, LPVOID lpReserved)
3423 FIXME("(%s,%s,%s,%08lx,%p,%p) stub\n",debugstr_w(lpReplacedFileName),debugstr_w(lpReplacementFileName),
3424 debugstr_w(lpBackupFileName),dwReplaceFlags,lpExclude,lpReserved);
3425 SetLastError(ERROR_UNABLE_TO_MOVE_REPLACEMENT);
3426 return FALSE;
3429 /**************************************************************************
3430 * ReplaceFileA (KERNEL32.@)
3432 BOOL WINAPI ReplaceFileA(LPCSTR lpReplacedFileName,LPCSTR lpReplacementFileName,
3433 LPCSTR lpBackupFileName, DWORD dwReplaceFlags,
3434 LPVOID lpExclude, LPVOID lpReserved)
3436 FIXME("(%s,%s,%s,%08lx,%p,%p) stub\n",lpReplacedFileName,lpReplacementFileName,
3437 lpBackupFileName,dwReplaceFlags,lpExclude,lpReserved);
3438 SetLastError(ERROR_UNABLE_TO_MOVE_REPLACEMENT);
3439 return FALSE;