Compile the shlwapi dll with -DSTRICT.
[wine/gsoc_dplay.git] / files / file.c
blob7f875f126ac49225065c200c548643940c4653e8
1 /*
2 * File handling functions
4 * Copyright 1993 John Burton
5 * Copyright 1996 Alexandre Julliard
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 * TODO:
22 * Fix the CopyFileEx methods to implement the "extended" functionality.
23 * Right now, they simply call the CopyFile method.
26 #include "config.h"
27 #include "wine/port.h"
29 #include <assert.h>
30 #include <ctype.h>
31 #include <errno.h>
32 #include <fcntl.h>
33 #include <stdlib.h>
34 #include <stdio.h>
35 #include <string.h>
36 #ifdef HAVE_SYS_ERRNO_H
37 #include <sys/errno.h>
38 #endif
39 #include <sys/types.h>
40 #include <sys/stat.h>
41 #ifdef HAVE_SYS_MMAN_H
42 #include <sys/mman.h>
43 #endif
44 #ifdef HAVE_SYS_TIME_H
45 # include <sys/time.h>
46 #endif
47 #ifdef HAVE_SYS_POLL_H
48 # include <sys/poll.h>
49 #endif
50 #include <time.h>
51 #ifdef HAVE_UNISTD_H
52 # include <unistd.h>
53 #endif
54 #ifdef HAVE_UTIME_H
55 # include <utime.h>
56 #endif
58 #include "winerror.h"
59 #include "windef.h"
60 #include "winbase.h"
61 #include "winternl.h"
62 #include "wine/winbase16.h"
63 #include "wine/server.h"
65 #include "drive.h"
66 #include "file.h"
67 #include "async.h"
68 #include "heap.h"
69 #include "msdos.h"
70 #include "wincon.h"
72 #include "smb.h"
73 #include "wine/unicode.h"
74 #include "wine/debug.h"
76 WINE_DEFAULT_DEBUG_CHANNEL(file);
78 #if defined(MAP_ANONYMOUS) && !defined(MAP_ANON)
79 #define MAP_ANON MAP_ANONYMOUS
80 #endif
82 /* Size of per-process table of DOS handles */
83 #define DOS_TABLE_SIZE 256
85 /* Macro to derive file offset from OVERLAPPED struct */
86 #define OVERLAPPED_OFFSET(overlapped) ((off_t) (overlapped)->Offset + ((off_t) (overlapped)->OffsetHigh << 32))
88 static HANDLE dos_handles[DOS_TABLE_SIZE];
90 mode_t FILE_umask;
92 extern HANDLE WINAPI FILE_SmbOpen(LPCSTR name);
94 /***********************************************************************
95 * Asynchronous file I/O *
97 static DWORD fileio_get_async_status (const async_private *ovp);
98 static DWORD fileio_get_async_count (const async_private *ovp);
99 static void fileio_set_async_status (async_private *ovp, const DWORD status);
100 static void CALLBACK fileio_call_completion_func (ULONG_PTR data);
101 static void fileio_async_cleanup (async_private *ovp);
103 static async_ops fileio_async_ops =
105 fileio_get_async_status, /* get_status */
106 fileio_set_async_status, /* set_status */
107 fileio_get_async_count, /* get_count */
108 fileio_call_completion_func, /* call_completion */
109 fileio_async_cleanup /* cleanup */
112 static async_ops fileio_nocomp_async_ops =
114 fileio_get_async_status, /* get_status */
115 fileio_set_async_status, /* set_status */
116 fileio_get_async_count, /* get_count */
117 NULL, /* call_completion */
118 fileio_async_cleanup /* cleanup */
121 typedef struct async_fileio
123 struct async_private async;
124 LPOVERLAPPED lpOverlapped;
125 LPOVERLAPPED_COMPLETION_ROUTINE completion_func;
126 char *buffer;
127 unsigned int count;
128 enum fd_type fd_type;
129 } async_fileio;
131 static DWORD fileio_get_async_status (const struct async_private *ovp)
133 return ((async_fileio*) ovp)->lpOverlapped->Internal;
136 static void fileio_set_async_status (async_private *ovp, const DWORD status)
138 ((async_fileio*) ovp)->lpOverlapped->Internal = status;
141 static DWORD fileio_get_async_count (const struct async_private *ovp)
143 async_fileio *fileio = (async_fileio*) ovp;
145 if (fileio->count < fileio->lpOverlapped->InternalHigh)
146 return 0;
147 return fileio->count - fileio->lpOverlapped->InternalHigh;
150 static void CALLBACK fileio_call_completion_func (ULONG_PTR data)
152 async_fileio *ovp = (async_fileio*) data;
153 TRACE ("data: %p\n", ovp);
155 ovp->completion_func( ovp->lpOverlapped->Internal,
156 ovp->lpOverlapped->InternalHigh,
157 ovp->lpOverlapped );
159 fileio_async_cleanup ( &ovp->async );
162 static void fileio_async_cleanup ( struct async_private *ovp )
164 HeapFree ( GetProcessHeap(), 0, ovp );
167 /***********************************************************************
168 * FILE_ConvertOFMode
170 * Convert OF_* mode into flags for CreateFile.
172 static void FILE_ConvertOFMode( INT mode, DWORD *access, DWORD *sharing )
174 switch(mode & 0x03)
176 case OF_READ: *access = GENERIC_READ; break;
177 case OF_WRITE: *access = GENERIC_WRITE; break;
178 case OF_READWRITE: *access = GENERIC_READ | GENERIC_WRITE; break;
179 default: *access = 0; break;
181 switch(mode & 0x70)
183 case OF_SHARE_EXCLUSIVE: *sharing = 0; break;
184 case OF_SHARE_DENY_WRITE: *sharing = FILE_SHARE_READ; break;
185 case OF_SHARE_DENY_READ: *sharing = FILE_SHARE_WRITE; break;
186 case OF_SHARE_DENY_NONE:
187 case OF_SHARE_COMPAT:
188 default: *sharing = FILE_SHARE_READ | FILE_SHARE_WRITE; break;
193 /***********************************************************************
194 * FILE_strcasecmp
196 * locale-independent case conversion for file I/O
198 int FILE_strcasecmp( const char *str1, const char *str2 )
200 int ret = 0;
201 for ( ; ; str1++, str2++)
202 if ((ret = FILE_toupper(*str1) - FILE_toupper(*str2)) || !*str1) break;
203 return ret;
207 /***********************************************************************
208 * FILE_strncasecmp
210 * locale-independent case conversion for file I/O
212 int FILE_strncasecmp( const char *str1, const char *str2, int len )
214 int ret = 0;
215 for ( ; len > 0; len--, str1++, str2++)
216 if ((ret = FILE_toupper(*str1) - FILE_toupper(*str2)) || !*str1) break;
217 return ret;
221 /***********************************************************************
222 * FILE_GetNtStatus(void)
224 * Retrieve the Nt Status code from errno.
225 * Try to be consistent with FILE_SetDosError().
227 DWORD FILE_GetNtStatus(void)
229 int err = errno;
230 DWORD nt;
231 TRACE ( "errno = %d\n", errno );
232 switch ( err )
234 case EAGAIN: nt = STATUS_SHARING_VIOLATION; break;
235 case EBADF: nt = STATUS_INVALID_HANDLE; break;
236 case ENOSPC: nt = STATUS_DISK_FULL; break;
237 case EPERM:
238 case EROFS:
239 case EACCES: nt = STATUS_ACCESS_DENIED; break;
240 case ENOENT: nt = STATUS_SHARING_VIOLATION; break;
241 case EISDIR: nt = STATUS_FILE_IS_A_DIRECTORY; break;
242 case EMFILE:
243 case ENFILE: nt = STATUS_NO_MORE_FILES; break;
244 case EINVAL:
245 case ENOTEMPTY: nt = STATUS_DIRECTORY_NOT_EMPTY; break;
246 case EPIPE: nt = STATUS_PIPE_BROKEN; break;
247 case ENOEXEC: /* ?? */
248 case ESPIPE: /* ?? */
249 case EEXIST: /* ?? */
250 default:
251 FIXME ( "Converting errno %d to STATUS_UNSUCCESSFUL\n", err );
252 nt = STATUS_UNSUCCESSFUL;
254 return nt;
257 /***********************************************************************
258 * FILE_SetDosError
260 * Set the DOS error code from errno.
262 void FILE_SetDosError(void)
264 int save_errno = errno; /* errno gets overwritten by printf */
266 TRACE("errno = %d %s\n", errno, strerror(errno));
267 switch (save_errno)
269 case EAGAIN:
270 SetLastError( ERROR_SHARING_VIOLATION );
271 break;
272 case EBADF:
273 SetLastError( ERROR_INVALID_HANDLE );
274 break;
275 case ENOSPC:
276 SetLastError( ERROR_HANDLE_DISK_FULL );
277 break;
278 case EACCES:
279 case EPERM:
280 case EROFS:
281 SetLastError( ERROR_ACCESS_DENIED );
282 break;
283 case EBUSY:
284 SetLastError( ERROR_LOCK_VIOLATION );
285 break;
286 case ENOENT:
287 SetLastError( ERROR_FILE_NOT_FOUND );
288 break;
289 case EISDIR:
290 SetLastError( ERROR_CANNOT_MAKE );
291 break;
292 case ENFILE:
293 case EMFILE:
294 SetLastError( ERROR_NO_MORE_FILES );
295 break;
296 case EEXIST:
297 SetLastError( ERROR_FILE_EXISTS );
298 break;
299 case EINVAL:
300 case ESPIPE:
301 SetLastError( ERROR_SEEK );
302 break;
303 case ENOTEMPTY:
304 SetLastError( ERROR_DIR_NOT_EMPTY );
305 break;
306 case ENOEXEC:
307 SetLastError( ERROR_BAD_FORMAT );
308 break;
309 default:
310 WARN("unknown file error: %s\n", strerror(save_errno) );
311 SetLastError( ERROR_GEN_FAILURE );
312 break;
314 errno = save_errno;
318 /***********************************************************************
319 * FILE_GetUnixHandleType
321 * Retrieve the Unix handle corresponding to a file handle.
322 * Returns -1 on failure.
324 static int FILE_GetUnixHandleType( HANDLE handle, DWORD access, enum fd_type *type, int *flags_ptr )
326 int ret, flags, fd = -1;
328 ret = wine_server_handle_to_fd( handle, access, &fd, type, &flags );
329 if (flags_ptr) *flags_ptr = flags;
330 if (ret) SetLastError( RtlNtStatusToDosError(ret) );
331 else if (((access & GENERIC_READ) && (flags & FD_FLAG_RECV_SHUTDOWN)) ||
332 ((access & GENERIC_WRITE) && (flags & FD_FLAG_SEND_SHUTDOWN)))
334 close (fd);
335 SetLastError ( ERROR_PIPE_NOT_CONNECTED );
336 return -1;
338 return fd;
341 /***********************************************************************
342 * FILE_GetUnixHandle
344 * Retrieve the Unix handle corresponding to a file handle.
345 * Returns -1 on failure.
347 int FILE_GetUnixHandle( HANDLE handle, DWORD access )
349 return FILE_GetUnixHandleType( handle, access, NULL, NULL );
352 /*************************************************************************
353 * FILE_OpenConsole
355 * Open a handle to the current process console.
356 * Returns 0 on failure.
358 static HANDLE FILE_OpenConsole( BOOL output, DWORD access, DWORD sharing, LPSECURITY_ATTRIBUTES sa )
360 HANDLE ret;
362 SERVER_START_REQ( open_console )
364 req->from = output;
365 req->access = access;
366 req->share = sharing;
367 req->inherit = (sa && (sa->nLength>=sizeof(*sa)) && sa->bInheritHandle);
368 SetLastError(0);
369 wine_server_call_err( req );
370 ret = reply->handle;
372 SERVER_END_REQ;
373 return ret;
376 /* FIXME: those routines defined as pointers are needed, because this file is
377 * currently compiled into NTDLL whereas it belongs to kernel32.
378 * this shall go away once all the DLL separation process is done
380 typedef BOOL (WINAPI* pRW)(HANDLE, const void*, DWORD, DWORD*, void*);
382 static BOOL FILE_ReadConsole(HANDLE hCon, void* buf, DWORD nb, DWORD* nr, void* p)
384 static HANDLE hKernel /* = 0 */;
385 static pRW pReadConsole /* = 0 */;
387 if ((!hKernel && !(hKernel = LoadLibraryA("kernel32"))) ||
388 (!pReadConsole &&
389 !(pReadConsole = GetProcAddress(hKernel, "ReadConsoleA"))))
391 *nr = 0;
392 return 0;
394 return (pReadConsole)(hCon, buf, nb, nr, p);
397 static BOOL FILE_WriteConsole(HANDLE hCon, const void* buf, DWORD nb, DWORD* nr, void* p)
399 static HANDLE hKernel /* = 0 */;
400 static pRW pWriteConsole /* = 0 */;
402 if ((!hKernel && !(hKernel = LoadLibraryA("kernel32"))) ||
403 (!pWriteConsole &&
404 !(pWriteConsole = GetProcAddress(hKernel, "WriteConsoleA"))))
406 *nr = 0;
407 return 0;
409 return (pWriteConsole)(hCon, buf, nb, nr, p);
411 /* end of FIXME */
413 /***********************************************************************
414 * FILE_CreateFile
416 * Implementation of CreateFile. Takes a Unix path name.
417 * Returns 0 on failure.
419 HANDLE FILE_CreateFile( LPCSTR filename, DWORD access, DWORD sharing,
420 LPSECURITY_ATTRIBUTES sa, DWORD creation,
421 DWORD attributes, HANDLE template, BOOL fail_read_only,
422 UINT drive_type )
424 unsigned int err;
425 HANDLE ret;
427 for (;;)
429 SERVER_START_REQ( create_file )
431 req->access = access;
432 req->inherit = (sa && (sa->nLength>=sizeof(*sa)) && sa->bInheritHandle);
433 req->sharing = sharing;
434 req->create = creation;
435 req->attrs = attributes;
436 req->drive_type = drive_type;
437 wine_server_add_data( req, filename, strlen(filename) );
438 SetLastError(0);
439 err = wine_server_call( req );
440 ret = reply->handle;
442 SERVER_END_REQ;
444 /* If write access failed, retry without GENERIC_WRITE */
446 if (!ret && !fail_read_only && (access & GENERIC_WRITE))
448 if ((err == STATUS_MEDIA_WRITE_PROTECTED) || (err == STATUS_ACCESS_DENIED))
450 TRACE("Write access failed for file '%s', trying without "
451 "write access\n", filename);
452 access &= ~GENERIC_WRITE;
453 continue;
457 if (err)
459 /* In the case file creation was rejected due to CREATE_NEW flag
460 * was specified and file with that name already exists, correct
461 * last error is ERROR_FILE_EXISTS and not ERROR_ALREADY_EXISTS.
462 * Note: RtlNtStatusToDosError is not the subject to blame here.
464 if (err == STATUS_OBJECT_NAME_COLLISION)
465 SetLastError( ERROR_FILE_EXISTS );
466 else
467 SetLastError( RtlNtStatusToDosError(err) );
470 if (!ret) WARN("Unable to create file '%s' (GLE %ld)\n", filename, GetLastError());
471 return ret;
476 /***********************************************************************
477 * FILE_CreateDevice
479 * Same as FILE_CreateFile but for a device
480 * Returns 0 on failure.
482 HANDLE FILE_CreateDevice( int client_id, DWORD access, LPSECURITY_ATTRIBUTES sa )
484 HANDLE ret;
485 SERVER_START_REQ( create_device )
487 req->access = access;
488 req->inherit = (sa && (sa->nLength>=sizeof(*sa)) && sa->bInheritHandle);
489 req->id = client_id;
490 SetLastError(0);
491 wine_server_call_err( req );
492 ret = reply->handle;
494 SERVER_END_REQ;
495 return ret;
498 static HANDLE FILE_OpenPipe(LPCWSTR name, DWORD access)
500 HANDLE ret;
501 DWORD len = 0;
503 if (name && (len = strlenW(name)) > MAX_PATH)
505 SetLastError( ERROR_FILENAME_EXCED_RANGE );
506 return 0;
508 SERVER_START_REQ( open_named_pipe )
510 req->access = access;
511 SetLastError(0);
512 wine_server_add_data( req, name, len * sizeof(WCHAR) );
513 wine_server_call_err( req );
514 ret = reply->handle;
516 SERVER_END_REQ;
517 TRACE("Returned %d\n",ret);
518 return ret;
521 /*************************************************************************
522 * CreateFileW [KERNEL32.@] Creates or opens a file or other object
524 * Creates or opens an object, and returns a handle that can be used to
525 * access that object.
527 * PARAMS
529 * filename [in] pointer to filename to be accessed
530 * access [in] access mode requested
531 * sharing [in] share mode
532 * sa [in] pointer to security attributes
533 * creation [in] how to create the file
534 * attributes [in] attributes for newly created file
535 * template [in] handle to file with extended attributes to copy
537 * RETURNS
538 * Success: Open handle to specified file
539 * Failure: INVALID_HANDLE_VALUE
541 * NOTES
542 * Should call SetLastError() on failure.
544 * BUGS
546 * Doesn't support character devices, template files, or a
547 * lot of the 'attributes' flags yet.
549 HANDLE WINAPI CreateFileW( LPCWSTR filename, DWORD access, DWORD sharing,
550 LPSECURITY_ATTRIBUTES sa, DWORD creation,
551 DWORD attributes, HANDLE template )
553 DOS_FULL_NAME full_name;
554 HANDLE ret;
555 static const WCHAR bkslashes_with_question_markW[] = {'\\','\\','?','\\',0};
556 static const WCHAR bkslashes_with_dotW[] = {'\\','\\','.','\\',0};
557 static const WCHAR bkslashesW[] = {'\\','\\',0};
558 static const WCHAR coninW[] = {'C','O','N','I','N','$',0};
559 static const WCHAR conoutW[] = {'C','O','N','O','U','T','$',0};
561 if (!filename)
563 SetLastError( ERROR_INVALID_PARAMETER );
564 return INVALID_HANDLE_VALUE;
566 TRACE("%s %s%s%s%s%s%s%s attributes 0x%lx\n", debugstr_w(filename),
567 ((access & GENERIC_READ)==GENERIC_READ)?"GENERIC_READ ":"",
568 ((access & GENERIC_WRITE)==GENERIC_WRITE)?"GENERIC_WRITE ":"",
569 (!access)?"QUERY_ACCESS ":"",
570 ((sharing & FILE_SHARE_READ)==FILE_SHARE_READ)?"FILE_SHARE_READ ":"",
571 ((sharing & FILE_SHARE_WRITE)==FILE_SHARE_WRITE)?"FILE_SHARE_WRITE ":"",
572 ((sharing & FILE_SHARE_DELETE)==FILE_SHARE_DELETE)?"FILE_SHARE_DELETE ":"",
573 (creation ==CREATE_NEW)?"CREATE_NEW":
574 (creation ==CREATE_ALWAYS)?"CREATE_ALWAYS ":
575 (creation ==OPEN_EXISTING)?"OPEN_EXISTING ":
576 (creation ==OPEN_ALWAYS)?"OPEN_ALWAYS ":
577 (creation ==TRUNCATE_EXISTING)?"TRUNCATE_EXISTING ":"", attributes);
579 /* If the name starts with '\\?\', ignore the first 4 chars. */
580 if (!strncmpW(filename, bkslashes_with_question_markW, 4))
582 static const WCHAR uncW[] = {'U','N','C','\\',0};
583 filename += 4;
584 if (!strncmpiW(filename, uncW, 4))
586 FIXME("UNC name (%s) not supported.\n", debugstr_w(filename) );
587 SetLastError( ERROR_PATH_NOT_FOUND );
588 return INVALID_HANDLE_VALUE;
592 if (!strncmpW(filename, bkslashes_with_dotW, 4))
594 static const WCHAR pipeW[] = {'P','I','P','E','\\',0};
595 if(!strncmpiW(filename + 4, pipeW, 5))
597 TRACE("Opening a pipe: %s\n", debugstr_w(filename));
598 ret = FILE_OpenPipe(filename,access);
599 goto done;
601 else if (isalphaW(filename[4]) && filename[5] == ':' && filename[6] == '\0')
603 ret = FILE_CreateDevice( (toupperW(filename[4]) - 'A') | 0x20000, access, sa );
604 goto done;
606 else if (!DOSFS_GetDevice( filename ))
608 ret = DEVICE_Open( filename+4, access, sa );
609 goto done;
611 else
612 filename+=4; /* fall into DOSFS_Device case below */
615 /* If the name still starts with '\\', it's a UNC name. */
616 if (!strncmpW(filename, bkslashesW, 2))
618 ret = SMB_CreateFileW(filename, access, sharing, sa, creation, attributes, template );
619 goto done;
622 /* If the name contains a DOS wild card (* or ?), do no create a file */
623 if(strchrW(filename, '*') || strchrW(filename, '?'))
624 return INVALID_HANDLE_VALUE;
626 /* Open a console for CONIN$ or CONOUT$ */
627 if (!strcmpiW(filename, coninW))
629 ret = FILE_OpenConsole( FALSE, access, sharing, sa );
630 goto done;
632 if (!strcmpiW(filename, conoutW))
634 ret = FILE_OpenConsole( TRUE, access, sharing, sa );
635 goto done;
638 if (DOSFS_GetDevice( filename ))
640 TRACE("opening device %s\n", debugstr_w(filename) );
642 if (!(ret = DOSFS_OpenDevice( filename, access, attributes, sa )))
644 /* Do not silence this please. It is a critical error. -MM */
645 ERR("Couldn't open device %s!\n", debugstr_w(filename));
646 SetLastError( ERROR_FILE_NOT_FOUND );
648 goto done;
651 /* check for filename, don't check for last entry if creating */
652 if (!DOSFS_GetFullName( filename,
653 (creation == OPEN_EXISTING) ||
654 (creation == TRUNCATE_EXISTING),
655 &full_name )) {
656 WARN("Unable to get full filename from %s (GLE %ld)\n",
657 debugstr_w(filename), GetLastError());
658 return INVALID_HANDLE_VALUE;
661 ret = FILE_CreateFile( full_name.long_name, access, sharing,
662 sa, creation, attributes, template,
663 DRIVE_GetFlags(full_name.drive) & DRIVE_FAIL_READ_ONLY,
664 GetDriveTypeW( full_name.short_name ) );
665 done:
666 if (!ret) ret = INVALID_HANDLE_VALUE;
667 TRACE("returning %08x\n", ret);
668 return ret;
673 /*************************************************************************
674 * CreateFileA (KERNEL32.@)
676 HANDLE WINAPI CreateFileA( LPCSTR filename, DWORD access, DWORD sharing,
677 LPSECURITY_ATTRIBUTES sa, DWORD creation,
678 DWORD attributes, HANDLE template)
680 UNICODE_STRING filenameW;
681 HANDLE ret = INVALID_HANDLE_VALUE;
683 if (!filename)
685 SetLastError( ERROR_INVALID_PARAMETER );
686 return INVALID_HANDLE_VALUE;
689 if (RtlCreateUnicodeStringFromAsciiz(&filenameW, filename))
691 ret = CreateFileW(filenameW.Buffer, access, sharing, sa, creation,
692 attributes, template);
693 RtlFreeUnicodeString(&filenameW);
695 else
696 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
697 return ret;
701 /***********************************************************************
702 * FILE_FillInfo
704 * Fill a file information from a struct stat.
706 static void FILE_FillInfo( struct stat *st, BY_HANDLE_FILE_INFORMATION *info )
708 if (S_ISDIR(st->st_mode))
709 info->dwFileAttributes = FILE_ATTRIBUTE_DIRECTORY;
710 else
711 info->dwFileAttributes = FILE_ATTRIBUTE_ARCHIVE;
712 if (!(st->st_mode & S_IWUSR))
713 info->dwFileAttributes |= FILE_ATTRIBUTE_READONLY;
715 RtlSecondsSince1970ToTime( st->st_mtime, (LARGE_INTEGER *)&info->ftCreationTime );
716 RtlSecondsSince1970ToTime( st->st_mtime, (LARGE_INTEGER *)&info->ftLastWriteTime );
717 RtlSecondsSince1970ToTime( st->st_atime, (LARGE_INTEGER *)&info->ftLastAccessTime );
719 info->dwVolumeSerialNumber = 0; /* FIXME */
720 info->nFileSizeHigh = 0;
721 info->nFileSizeLow = 0;
722 if (!S_ISDIR(st->st_mode)) {
723 info->nFileSizeHigh = st->st_size >> 32;
724 info->nFileSizeLow = st->st_size & 0xffffffff;
726 info->nNumberOfLinks = st->st_nlink;
727 info->nFileIndexHigh = 0;
728 info->nFileIndexLow = st->st_ino;
732 /***********************************************************************
733 * FILE_Stat
735 * Stat a Unix path name. Return TRUE if OK.
737 BOOL FILE_Stat( LPCSTR unixName, BY_HANDLE_FILE_INFORMATION *info )
739 struct stat st;
740 int is_symlink;
741 LPCSTR p;
743 if (lstat( unixName, &st ) == -1)
745 FILE_SetDosError();
746 return FALSE;
748 is_symlink = S_ISLNK(st.st_mode);
749 if (is_symlink)
751 /* do a "real" stat to find out
752 about the type of the symlink destination */
753 if (stat( unixName, &st ) == -1)
755 FILE_SetDosError();
756 return FALSE;
760 /* fill in the information we gathered so far */
761 FILE_FillInfo( &st, info );
762 if (is_symlink) info->dwFileAttributes |= FILE_ATTRIBUTE_SYMLINK;
764 /* and now see if this is a hidden file, based on the name */
765 p = strrchr( unixName, '/');
766 p = p ? p + 1 : unixName;
767 if (*p == '.' && *(p+1) && (*(p+1) != '.' || *(p+2)))
769 static const WCHAR wineW[] = {'w','i','n','e',0};
770 static const WCHAR ShowDotFilesW[] = {'S','h','o','w','D','o','t','F','i','l','e','s',0};
771 static int show_dot_files = -1;
772 if (show_dot_files == -1)
773 show_dot_files = PROFILE_GetWineIniBool(wineW, ShowDotFilesW, 0);
774 if (!show_dot_files)
775 info->dwFileAttributes |= FILE_ATTRIBUTE_HIDDEN;
778 return TRUE;
782 /***********************************************************************
783 * GetFileInformationByHandle (KERNEL32.@)
785 DWORD WINAPI GetFileInformationByHandle( HANDLE hFile,
786 BY_HANDLE_FILE_INFORMATION *info )
788 DWORD ret;
789 if (!info) return 0;
791 TRACE("%08x\n", hFile);
793 SERVER_START_REQ( get_file_info )
795 req->handle = hFile;
796 if ((ret = !wine_server_call_err( req )))
798 /* FIXME: which file types are supported ?
799 * Serial ports (FILE_TYPE_CHAR) are not,
800 * and MSDN also says that pipes are not supported.
801 * FILE_TYPE_REMOTE seems to be supported according to
802 * MSDN q234741.txt */
803 if ((reply->type == FILE_TYPE_DISK) || (reply->type == FILE_TYPE_REMOTE))
805 RtlSecondsSince1970ToTime( reply->write_time, (LARGE_INTEGER *)&info->ftCreationTime );
806 RtlSecondsSince1970ToTime( reply->write_time, (LARGE_INTEGER *)&info->ftLastWriteTime );
807 RtlSecondsSince1970ToTime( reply->access_time, (LARGE_INTEGER *)&info->ftLastAccessTime );
808 info->dwFileAttributes = reply->attr;
809 info->dwVolumeSerialNumber = reply->serial;
810 info->nFileSizeHigh = reply->size_high;
811 info->nFileSizeLow = reply->size_low;
812 info->nNumberOfLinks = reply->links;
813 info->nFileIndexHigh = reply->index_high;
814 info->nFileIndexLow = reply->index_low;
816 else
818 SetLastError(ERROR_NOT_SUPPORTED);
819 ret = 0;
823 SERVER_END_REQ;
824 return ret;
828 /**************************************************************************
829 * GetFileAttributes (KERNEL.420)
831 DWORD WINAPI GetFileAttributes16( LPCSTR name )
833 return GetFileAttributesA( name );
837 /**************************************************************************
838 * GetFileAttributesW (KERNEL32.@)
840 DWORD WINAPI GetFileAttributesW( LPCWSTR name )
842 DOS_FULL_NAME full_name;
843 BY_HANDLE_FILE_INFORMATION info;
845 if (name == NULL)
847 SetLastError( ERROR_INVALID_PARAMETER );
848 return -1;
850 if (!DOSFS_GetFullName( name, TRUE, &full_name) )
851 return -1;
852 if (!FILE_Stat( full_name.long_name, &info )) return -1;
853 return info.dwFileAttributes;
857 /**************************************************************************
858 * GetFileAttributesA (KERNEL32.@)
860 DWORD WINAPI GetFileAttributesA( LPCSTR name )
862 UNICODE_STRING nameW;
863 DWORD ret = (DWORD)-1;
865 if (!name)
867 SetLastError( ERROR_INVALID_PARAMETER );
868 return (DWORD)-1;
871 if (RtlCreateUnicodeStringFromAsciiz(&nameW, name))
873 ret = GetFileAttributesW(nameW.Buffer);
874 RtlFreeUnicodeString(&nameW);
876 else
877 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
878 return ret;
882 /**************************************************************************
883 * SetFileAttributes (KERNEL.421)
885 BOOL16 WINAPI SetFileAttributes16( LPCSTR lpFileName, DWORD attributes )
887 return SetFileAttributesA( lpFileName, attributes );
891 /**************************************************************************
892 * SetFileAttributesW (KERNEL32.@)
894 BOOL WINAPI SetFileAttributesW(LPCWSTR lpFileName, DWORD attributes)
896 struct stat buf;
897 DOS_FULL_NAME full_name;
899 if (!lpFileName)
901 SetLastError( ERROR_INVALID_PARAMETER );
902 return FALSE;
905 TRACE("(%s,%lx)\n", debugstr_w(lpFileName), attributes);
907 if (!DOSFS_GetFullName( lpFileName, TRUE, &full_name ))
908 return FALSE;
910 if(stat(full_name.long_name,&buf)==-1)
912 FILE_SetDosError();
913 return FALSE;
915 if (attributes & FILE_ATTRIBUTE_READONLY)
917 if(S_ISDIR(buf.st_mode))
918 /* FIXME */
919 WARN("FILE_ATTRIBUTE_READONLY ignored for directory.\n");
920 else
921 buf.st_mode &= ~0222; /* octal!, clear write permission bits */
922 attributes &= ~FILE_ATTRIBUTE_READONLY;
924 else
926 /* add write permission */
927 buf.st_mode |= (0600 | ((buf.st_mode & 044) >> 1)) & (~FILE_umask);
929 if (attributes & FILE_ATTRIBUTE_DIRECTORY)
931 if (!S_ISDIR(buf.st_mode))
932 FIXME("SetFileAttributes expected the file %s to be a directory\n",
933 debugstr_w(lpFileName));
934 attributes &= ~FILE_ATTRIBUTE_DIRECTORY;
936 attributes &= ~(FILE_ATTRIBUTE_NORMAL|FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_HIDDEN|FILE_ATTRIBUTE_SYSTEM);
937 if (attributes)
938 FIXME("(%s):%lx attribute(s) not implemented.\n", debugstr_w(lpFileName), attributes);
939 if (-1==chmod(full_name.long_name,buf.st_mode))
941 if (GetDriveTypeW(lpFileName) == DRIVE_CDROM)
943 SetLastError( ERROR_ACCESS_DENIED );
944 return FALSE;
948 * FIXME: We don't return FALSE here because of differences between
949 * Linux and Windows privileges. Under Linux only the owner of
950 * the file is allowed to change file attributes. Under Windows,
951 * applications expect that if you can write to a file, you can also
952 * change its attributes (see GENERIC_WRITE). We could try to be
953 * clever here but that would break multi-user installations where
954 * users share read-only DLLs. This is because some installers like
955 * to change attributes of already installed DLLs.
957 FIXME("Couldn't set file attributes for existing file \"%s\".\n"
958 "Check permissions or set VFAT \"quiet\" mount flag\n", full_name.long_name);
960 return TRUE;
964 /**************************************************************************
965 * SetFileAttributesA (KERNEL32.@)
967 BOOL WINAPI SetFileAttributesA(LPCSTR lpFileName, DWORD attributes)
969 UNICODE_STRING filenameW;
970 BOOL ret = FALSE;
972 if (!lpFileName)
974 SetLastError( ERROR_INVALID_PARAMETER );
975 return FALSE;
978 if (RtlCreateUnicodeStringFromAsciiz(&filenameW, lpFileName))
980 ret = SetFileAttributesW(filenameW.Buffer, attributes);
981 RtlFreeUnicodeString(&filenameW);
983 else
984 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
985 return ret;
989 /***********************************************************************
990 * GetFileSize (KERNEL32.@)
992 DWORD WINAPI GetFileSize( HANDLE hFile, LPDWORD filesizehigh )
994 BY_HANDLE_FILE_INFORMATION info;
995 if (!GetFileInformationByHandle( hFile, &info )) return -1;
996 if (filesizehigh) *filesizehigh = info.nFileSizeHigh;
997 return info.nFileSizeLow;
1001 /***********************************************************************
1002 * GetFileTime (KERNEL32.@)
1004 BOOL WINAPI GetFileTime( HANDLE hFile, FILETIME *lpCreationTime,
1005 FILETIME *lpLastAccessTime,
1006 FILETIME *lpLastWriteTime )
1008 BY_HANDLE_FILE_INFORMATION info;
1009 if (!GetFileInformationByHandle( hFile, &info )) return FALSE;
1010 if (lpCreationTime) *lpCreationTime = info.ftCreationTime;
1011 if (lpLastAccessTime) *lpLastAccessTime = info.ftLastAccessTime;
1012 if (lpLastWriteTime) *lpLastWriteTime = info.ftLastWriteTime;
1013 return TRUE;
1016 /***********************************************************************
1017 * CompareFileTime (KERNEL32.@)
1019 INT WINAPI CompareFileTime( LPFILETIME x, LPFILETIME y )
1021 if (!x || !y) return -1;
1023 if (x->dwHighDateTime > y->dwHighDateTime)
1024 return 1;
1025 if (x->dwHighDateTime < y->dwHighDateTime)
1026 return -1;
1027 if (x->dwLowDateTime > y->dwLowDateTime)
1028 return 1;
1029 if (x->dwLowDateTime < y->dwLowDateTime)
1030 return -1;
1031 return 0;
1034 /***********************************************************************
1035 * FILE_GetTempFileName : utility for GetTempFileName
1037 static UINT FILE_GetTempFileName( LPCWSTR path, LPCWSTR prefix, UINT unique,
1038 LPWSTR buffer )
1040 static UINT unique_temp;
1041 DOS_FULL_NAME full_name;
1042 int i;
1043 LPWSTR p;
1044 UINT num;
1045 char buf[20];
1047 if ( !path || !prefix || !buffer )
1049 SetLastError( ERROR_INVALID_PARAMETER );
1050 return 0;
1053 if (!unique_temp) unique_temp = time(NULL) & 0xffff;
1054 num = unique ? (unique & 0xffff) : (unique_temp++ & 0xffff);
1056 strcpyW( buffer, path );
1057 p = buffer + strlenW(buffer);
1059 /* add a \, if there isn't one and path is more than just the drive letter ... */
1060 if ( !((strlenW(buffer) == 2) && (buffer[1] == ':'))
1061 && ((p == buffer) || (p[-1] != '\\'))) *p++ = '\\';
1063 for (i = 3; (i > 0) && (*prefix); i--) *p++ = *prefix++;
1065 sprintf( buf, "%04x.tmp", num );
1066 MultiByteToWideChar(CP_ACP, 0, buf, -1, p, 20);
1068 /* Now try to create it */
1070 if (!unique)
1074 HANDLE handle = CreateFileW( buffer, GENERIC_WRITE, 0, NULL,
1075 CREATE_NEW, FILE_ATTRIBUTE_NORMAL, 0 );
1076 if (handle != INVALID_HANDLE_VALUE)
1077 { /* We created it */
1078 TRACE("created %s\n", debugstr_w(buffer) );
1079 CloseHandle( handle );
1080 break;
1082 if (GetLastError() != ERROR_FILE_EXISTS)
1083 break; /* No need to go on */
1084 num++;
1085 sprintf( buf, "%04x.tmp", num );
1086 MultiByteToWideChar(CP_ACP, 0, buf, -1, p, 20);
1087 } while (num != (unique & 0xffff));
1090 /* Get the full path name */
1092 if (DOSFS_GetFullName( buffer, FALSE, &full_name ))
1094 char *slash;
1095 /* Check if we have write access in the directory */
1096 if ((slash = strrchr( full_name.long_name, '/' ))) *slash = '\0';
1097 if (access( full_name.long_name, W_OK ) == -1)
1098 WARN("returns %s, which doesn't seem to be writeable.\n",
1099 debugstr_w(buffer) );
1101 TRACE("returning %s\n", debugstr_w(buffer) );
1102 return unique ? unique : num;
1106 /***********************************************************************
1107 * GetTempFileNameA (KERNEL32.@)
1109 UINT WINAPI GetTempFileNameA( LPCSTR path, LPCSTR prefix, UINT unique,
1110 LPSTR buffer)
1112 UNICODE_STRING pathW, prefixW;
1113 WCHAR bufferW[MAX_PATH];
1114 UINT ret;
1116 if ( !path || !prefix || !buffer )
1118 SetLastError( ERROR_INVALID_PARAMETER );
1119 return 0;
1122 RtlCreateUnicodeStringFromAsciiz(&pathW, path);
1123 RtlCreateUnicodeStringFromAsciiz(&prefixW, prefix);
1125 ret = GetTempFileNameW(pathW.Buffer, prefixW.Buffer, unique, bufferW);
1126 if (ret)
1127 WideCharToMultiByte(CP_ACP, 0, bufferW, -1, buffer, MAX_PATH, NULL, NULL);
1129 RtlFreeUnicodeString(&pathW);
1130 RtlFreeUnicodeString(&prefixW);
1131 return ret;
1134 /***********************************************************************
1135 * GetTempFileNameW (KERNEL32.@)
1137 UINT WINAPI GetTempFileNameW( LPCWSTR path, LPCWSTR prefix, UINT unique,
1138 LPWSTR buffer )
1140 return FILE_GetTempFileName( path, prefix, unique, buffer );
1144 /***********************************************************************
1145 * GetTempFileName (KERNEL.97)
1147 UINT16 WINAPI GetTempFileName16( BYTE drive, LPCSTR prefix, UINT16 unique,
1148 LPSTR buffer )
1150 char temppath[MAX_PATH];
1151 char *prefix16 = NULL;
1152 UINT16 ret;
1154 if (!(drive & ~TF_FORCEDRIVE)) /* drive 0 means current default drive */
1155 drive |= DRIVE_GetCurrentDrive() + 'A';
1157 if ((drive & TF_FORCEDRIVE) &&
1158 !DRIVE_IsValid( toupper(drive & ~TF_FORCEDRIVE) - 'A' ))
1160 drive &= ~TF_FORCEDRIVE;
1161 WARN("invalid drive %d specified\n", drive );
1164 if (drive & TF_FORCEDRIVE)
1165 sprintf(temppath,"%c:", drive & ~TF_FORCEDRIVE );
1166 else
1167 GetTempPathA( MAX_PATH, temppath );
1169 if (prefix)
1171 prefix16 = HeapAlloc(GetProcessHeap(), 0, strlen(prefix) + 2);
1172 *prefix16 = '~';
1173 strcpy(prefix16 + 1, prefix);
1176 ret = GetTempFileNameA( temppath, prefix16, unique, buffer );
1178 if (prefix16) HeapFree(GetProcessHeap(), 0, prefix16);
1179 return ret;
1182 /***********************************************************************
1183 * FILE_DoOpenFile
1185 * Implementation of OpenFile16() and OpenFile32().
1187 static HFILE FILE_DoOpenFile( LPCSTR name, OFSTRUCT *ofs, UINT mode,
1188 BOOL win32 )
1190 HFILE hFileRet;
1191 HANDLE handle;
1192 FILETIME filetime;
1193 WORD filedatetime[2];
1194 DOS_FULL_NAME full_name;
1195 DWORD access, sharing;
1196 WCHAR *p;
1197 WCHAR buffer[MAX_PATH];
1198 LPWSTR nameW;
1200 if (!ofs) return HFILE_ERROR;
1202 TRACE("%s %s %s %s%s%s%s%s%s%s%s%s\n",name,
1203 ((mode & 0x3 )==OF_READ)?"OF_READ":
1204 ((mode & 0x3 )==OF_WRITE)?"OF_WRITE":
1205 ((mode & 0x3 )==OF_READWRITE)?"OF_READWRITE":"unknown",
1206 ((mode & 0x70 )==OF_SHARE_COMPAT)?"OF_SHARE_COMPAT":
1207 ((mode & 0x70 )==OF_SHARE_DENY_NONE)?"OF_SHARE_DENY_NONE":
1208 ((mode & 0x70 )==OF_SHARE_DENY_READ)?"OF_SHARE_DENY_READ":
1209 ((mode & 0x70 )==OF_SHARE_DENY_WRITE)?"OF_SHARE_DENY_WRITE":
1210 ((mode & 0x70 )==OF_SHARE_EXCLUSIVE)?"OF_SHARE_EXCLUSIVE":"unknown",
1211 ((mode & OF_PARSE )==OF_PARSE)?"OF_PARSE ":"",
1212 ((mode & OF_DELETE )==OF_DELETE)?"OF_DELETE ":"",
1213 ((mode & OF_VERIFY )==OF_VERIFY)?"OF_VERIFY ":"",
1214 ((mode & OF_SEARCH )==OF_SEARCH)?"OF_SEARCH ":"",
1215 ((mode & OF_CANCEL )==OF_CANCEL)?"OF_CANCEL ":"",
1216 ((mode & OF_CREATE )==OF_CREATE)?"OF_CREATE ":"",
1217 ((mode & OF_PROMPT )==OF_PROMPT)?"OF_PROMPT ":"",
1218 ((mode & OF_EXIST )==OF_EXIST)?"OF_EXIST ":"",
1219 ((mode & OF_REOPEN )==OF_REOPEN)?"OF_REOPEN ":""
1223 ofs->cBytes = sizeof(OFSTRUCT);
1224 ofs->nErrCode = 0;
1225 if (mode & OF_REOPEN) name = ofs->szPathName;
1227 if (!name) {
1228 ERR("called with `name' set to NULL ! Please debug.\n");
1229 return HFILE_ERROR;
1232 TRACE("%s %04x\n", name, mode );
1234 /* the watcom 10.6 IDE relies on a valid path returned in ofs->szPathName
1235 Are there any cases where getting the path here is wrong?
1236 Uwe Bonnes 1997 Apr 2 */
1237 if (!GetFullPathNameA( name, sizeof(ofs->szPathName),
1238 ofs->szPathName, NULL )) goto error;
1239 FILE_ConvertOFMode( mode, &access, &sharing );
1241 /* OF_PARSE simply fills the structure */
1243 if (mode & OF_PARSE)
1245 ofs->fFixedDisk = (GetDriveType16( ofs->szPathName[0]-'A' )
1246 != DRIVE_REMOVABLE);
1247 TRACE("(%s): OF_PARSE, res = '%s'\n",
1248 name, ofs->szPathName );
1249 return 0;
1252 /* OF_CREATE is completely different from all other options, so
1253 handle it first */
1255 if (mode & OF_CREATE)
1257 if ((handle = CreateFileA( name, GENERIC_READ | GENERIC_WRITE,
1258 sharing, NULL, CREATE_ALWAYS,
1259 FILE_ATTRIBUTE_NORMAL, 0 ))== INVALID_HANDLE_VALUE)
1260 goto error;
1261 goto success;
1264 MultiByteToWideChar(CP_ACP, 0, name, -1, buffer, MAX_PATH);
1265 nameW = buffer;
1267 /* If OF_SEARCH is set, ignore the given path */
1269 if ((mode & OF_SEARCH) && !(mode & OF_REOPEN))
1271 /* First try the file name as is */
1272 if (DOSFS_GetFullName( nameW, TRUE, &full_name )) goto found;
1273 /* Now remove the path */
1274 if (nameW[0] && (nameW[1] == ':')) nameW += 2;
1275 if ((p = strrchrW( nameW, '\\' ))) nameW = p + 1;
1276 if ((p = strrchrW( nameW, '/' ))) nameW = p + 1;
1277 if (!nameW[0]) goto not_found;
1280 /* Now look for the file */
1282 if (!DIR_SearchPath( NULL, nameW, NULL, &full_name, win32 )) goto not_found;
1284 found:
1285 TRACE("found %s = %s\n",
1286 full_name.long_name, debugstr_w(full_name.short_name) );
1287 WideCharToMultiByte(CP_ACP, 0, full_name.short_name, -1,
1288 ofs->szPathName, sizeof(ofs->szPathName), NULL, NULL);
1290 if (mode & OF_SHARE_EXCLUSIVE)
1291 /* Some InstallShield version uses OF_SHARE_EXCLUSIVE
1292 on the file <tempdir>/_ins0432._mp to determine how
1293 far installation has proceeded.
1294 _ins0432._mp is an executable and while running the
1295 application expects the open with OF_SHARE_ to fail*/
1296 /* Probable FIXME:
1297 As our loader closes the files after loading the executable,
1298 we can't find the running executable with FILE_InUse.
1299 The loader should keep the file open, as Windows does that, too.
1302 char *last = strrchr(full_name.long_name,'/');
1303 if (!last)
1304 last = full_name.long_name - 1;
1305 if (GetModuleHandle16(last+1))
1307 TRACE("Denying shared open for %s\n",full_name.long_name);
1308 return HFILE_ERROR;
1312 if (mode & OF_DELETE)
1314 if (unlink( full_name.long_name ) == -1) goto not_found;
1315 TRACE("(%s): OF_DELETE return = OK\n", name);
1316 return 1;
1319 handle = FILE_CreateFile( full_name.long_name, access, sharing,
1320 NULL, OPEN_EXISTING, 0, 0,
1321 DRIVE_GetFlags(full_name.drive) & DRIVE_FAIL_READ_ONLY,
1322 GetDriveTypeW( full_name.short_name ) );
1323 if (!handle) goto not_found;
1325 GetFileTime( handle, NULL, NULL, &filetime );
1326 FileTimeToDosDateTime( &filetime, &filedatetime[0], &filedatetime[1] );
1327 if ((mode & OF_VERIFY) && (mode & OF_REOPEN))
1329 if (ofs->Reserved1 != filedatetime[0] || ofs->Reserved2 != filedatetime[1] )
1331 CloseHandle( handle );
1332 WARN("(%s): OF_VERIFY failed\n", name );
1333 /* FIXME: what error here? */
1334 SetLastError( ERROR_FILE_NOT_FOUND );
1335 goto error;
1338 ofs->Reserved1 = filedatetime[0];
1339 ofs->Reserved2 = filedatetime[1];
1341 success: /* We get here if the open was successful */
1342 TRACE("(%s): OK, return = %x\n", name, handle );
1343 if (win32)
1345 hFileRet = (HFILE)handle;
1346 if (mode & OF_EXIST) /* Return the handle, but close it first */
1347 CloseHandle( handle );
1349 else
1351 hFileRet = Win32HandleToDosFileHandle( handle );
1352 if (hFileRet == HFILE_ERROR16) goto error;
1353 if (mode & OF_EXIST) /* Return the handle, but close it first */
1354 _lclose16( hFileRet );
1356 return hFileRet;
1358 not_found: /* We get here if the file does not exist */
1359 WARN("'%s' not found or sharing violation\n", name );
1360 SetLastError( ERROR_FILE_NOT_FOUND );
1361 /* fall through */
1363 error: /* We get here if there was an error opening the file */
1364 ofs->nErrCode = GetLastError();
1365 WARN("(%s): return = HFILE_ERROR error= %d\n",
1366 name,ofs->nErrCode );
1367 return HFILE_ERROR;
1371 /***********************************************************************
1372 * OpenFile (KERNEL.74)
1373 * OpenFileEx (KERNEL.360)
1375 HFILE16 WINAPI OpenFile16( LPCSTR name, OFSTRUCT *ofs, UINT16 mode )
1377 return FILE_DoOpenFile( name, ofs, mode, FALSE );
1381 /***********************************************************************
1382 * OpenFile (KERNEL32.@)
1384 HFILE WINAPI OpenFile( LPCSTR name, OFSTRUCT *ofs, UINT mode )
1386 return FILE_DoOpenFile( name, ofs, mode, TRUE );
1390 /***********************************************************************
1391 * FILE_InitProcessDosHandles
1393 * Allocates the default DOS handles for a process. Called either by
1394 * Win32HandleToDosFileHandle below or by the DOSVM stuff.
1396 static void FILE_InitProcessDosHandles( void )
1398 HANDLE cp = GetCurrentProcess();
1399 DuplicateHandle(cp, GetStdHandle(STD_INPUT_HANDLE), cp, &dos_handles[0],
1400 0, TRUE, DUPLICATE_SAME_ACCESS);
1401 DuplicateHandle(cp, GetStdHandle(STD_OUTPUT_HANDLE), cp, &dos_handles[1],
1402 0, TRUE, DUPLICATE_SAME_ACCESS);
1403 DuplicateHandle(cp, GetStdHandle(STD_ERROR_HANDLE), cp, &dos_handles[2],
1404 0, TRUE, DUPLICATE_SAME_ACCESS);
1405 DuplicateHandle(cp, GetStdHandle(STD_ERROR_HANDLE), cp, &dos_handles[3],
1406 0, TRUE, DUPLICATE_SAME_ACCESS);
1407 DuplicateHandle(cp, GetStdHandle(STD_ERROR_HANDLE), cp, &dos_handles[4],
1408 0, TRUE, DUPLICATE_SAME_ACCESS);
1411 /***********************************************************************
1412 * Win32HandleToDosFileHandle (KERNEL32.21)
1414 * Allocate a DOS handle for a Win32 handle. The Win32 handle is no
1415 * longer valid after this function (even on failure).
1417 * Note: this is not exactly right, since on Win95 the Win32 handles
1418 * are on top of DOS handles and we do it the other way
1419 * around. Should be good enough though.
1421 HFILE WINAPI Win32HandleToDosFileHandle( HANDLE handle )
1423 int i;
1425 if (!handle || (handle == INVALID_HANDLE_VALUE))
1426 return HFILE_ERROR;
1428 for (i = 5; i < DOS_TABLE_SIZE; i++)
1429 if (!dos_handles[i])
1431 dos_handles[i] = handle;
1432 TRACE("Got %d for h32 %d\n", i, handle );
1433 return (HFILE)i;
1435 CloseHandle( handle );
1436 SetLastError( ERROR_TOO_MANY_OPEN_FILES );
1437 return HFILE_ERROR;
1441 /***********************************************************************
1442 * DosFileHandleToWin32Handle (KERNEL32.20)
1444 * Return the Win32 handle for a DOS handle.
1446 * Note: this is not exactly right, since on Win95 the Win32 handles
1447 * are on top of DOS handles and we do it the other way
1448 * around. Should be good enough though.
1450 HANDLE WINAPI DosFileHandleToWin32Handle( HFILE handle )
1452 HFILE16 hfile = (HFILE16)handle;
1453 if (hfile < 5 && !dos_handles[hfile]) FILE_InitProcessDosHandles();
1454 if ((hfile >= DOS_TABLE_SIZE) || !dos_handles[hfile])
1456 SetLastError( ERROR_INVALID_HANDLE );
1457 return INVALID_HANDLE_VALUE;
1459 return dos_handles[hfile];
1463 /***********************************************************************
1464 * DisposeLZ32Handle (KERNEL32.22)
1466 * Note: this is not entirely correct, we should only close the
1467 * 32-bit handle and not the 16-bit one, but we cannot do
1468 * this because of the way our DOS handles are implemented.
1469 * It shouldn't break anything though.
1471 void WINAPI DisposeLZ32Handle( HANDLE handle )
1473 int i;
1475 if (!handle || (handle == INVALID_HANDLE_VALUE)) return;
1477 for (i = 5; i < DOS_TABLE_SIZE; i++)
1478 if (dos_handles[i] == handle)
1480 dos_handles[i] = 0;
1481 CloseHandle( handle );
1482 break;
1487 /***********************************************************************
1488 * FILE_Dup2
1490 * dup2() function for DOS handles.
1492 HFILE16 FILE_Dup2( HFILE16 hFile1, HFILE16 hFile2 )
1494 HANDLE new_handle;
1496 if (hFile1 < 5 && !dos_handles[hFile1]) FILE_InitProcessDosHandles();
1498 if ((hFile1 >= DOS_TABLE_SIZE) || (hFile2 >= DOS_TABLE_SIZE) || !dos_handles[hFile1])
1500 SetLastError( ERROR_INVALID_HANDLE );
1501 return HFILE_ERROR16;
1503 if (!DuplicateHandle( GetCurrentProcess(), dos_handles[hFile1],
1504 GetCurrentProcess(), &new_handle,
1505 0, FALSE, DUPLICATE_SAME_ACCESS ))
1506 return HFILE_ERROR16;
1507 if (dos_handles[hFile2]) CloseHandle( dos_handles[hFile2] );
1508 dos_handles[hFile2] = new_handle;
1509 return hFile2;
1513 /***********************************************************************
1514 * _lclose (KERNEL.81)
1516 HFILE16 WINAPI _lclose16( HFILE16 hFile )
1518 if ((hFile >= DOS_TABLE_SIZE) || !dos_handles[hFile])
1520 SetLastError( ERROR_INVALID_HANDLE );
1521 return HFILE_ERROR16;
1523 TRACE("%d (handle32=%d)\n", hFile, dos_handles[hFile] );
1524 CloseHandle( dos_handles[hFile] );
1525 dos_handles[hFile] = 0;
1526 return 0;
1530 /***********************************************************************
1531 * _lclose (KERNEL32.@)
1533 HFILE WINAPI _lclose( HFILE hFile )
1535 TRACE("handle %d\n", hFile );
1536 return CloseHandle( (HANDLE)hFile ) ? 0 : HFILE_ERROR;
1539 /***********************************************************************
1540 * GetOverlappedResult (KERNEL32.@)
1542 * Check the result of an Asynchronous data transfer from a file.
1544 * RETURNS
1545 * TRUE on success
1546 * FALSE on failure
1548 * If successful (and relevant) lpTransferred will hold the number of
1549 * bytes transferred during the async operation.
1551 * BUGS
1553 * Currently only works for WaitCommEvent, ReadFile, WriteFile
1554 * with communications ports.
1557 BOOL WINAPI GetOverlappedResult(
1558 HANDLE hFile, /* [in] handle of file to check on */
1559 LPOVERLAPPED lpOverlapped, /* [in/out] pointer to overlapped */
1560 LPDWORD lpTransferred, /* [in/out] number of bytes transferred */
1561 BOOL bWait /* [in] wait for the transfer to complete ? */
1563 DWORD r;
1565 TRACE("(%d %p %p %x)\n", hFile, lpOverlapped, lpTransferred, bWait);
1567 if(lpOverlapped==NULL)
1569 ERR("lpOverlapped was null\n");
1570 return FALSE;
1572 if(!lpOverlapped->hEvent)
1574 ERR("lpOverlapped->hEvent was null\n");
1575 return FALSE;
1578 if ( bWait )
1580 do {
1581 TRACE("waiting on %p\n",lpOverlapped);
1582 r = WaitForSingleObjectEx(lpOverlapped->hEvent, INFINITE, TRUE);
1583 TRACE("wait on %p returned %ld\n",lpOverlapped,r);
1584 } while (r==STATUS_USER_APC);
1586 else if ( lpOverlapped->Internal == STATUS_PENDING )
1588 /* Wait in order to give APCs a chance to run. */
1589 /* This is cheating, so we must set the event again in case of success -
1590 it may be a non-manual reset event. */
1591 do {
1592 TRACE("waiting on %p\n",lpOverlapped);
1593 r = WaitForSingleObjectEx(lpOverlapped->hEvent, 0, TRUE);
1594 TRACE("wait on %p returned %ld\n",lpOverlapped,r);
1595 } while (r==STATUS_USER_APC);
1596 if ( r == WAIT_OBJECT_0 )
1597 NtSetEvent ( lpOverlapped->hEvent, NULL );
1600 if(lpTransferred)
1601 *lpTransferred = lpOverlapped->InternalHigh;
1603 switch ( lpOverlapped->Internal )
1605 case STATUS_SUCCESS:
1606 return TRUE;
1607 case STATUS_PENDING:
1608 SetLastError ( ERROR_IO_INCOMPLETE );
1609 if ( bWait ) ERR ("PENDING status after waiting!\n");
1610 return FALSE;
1611 default:
1612 SetLastError ( RtlNtStatusToDosError ( lpOverlapped->Internal ) );
1613 return FALSE;
1617 /***********************************************************************
1618 * CancelIo (KERNEL32.@)
1620 BOOL WINAPI CancelIo(HANDLE handle)
1622 async_private *ovp,*t;
1624 TRACE("handle = %x\n",handle);
1626 for (ovp = NtCurrentTeb()->pending_list; ovp; ovp = t)
1628 t = ovp->next;
1629 if ( ovp->handle == handle )
1630 cancel_async ( ovp );
1632 WaitForMultipleObjectsEx(0,NULL,FALSE,1,TRUE);
1633 return TRUE;
1636 /***********************************************************************
1637 * FILE_AsyncReadService (INTERNAL)
1639 * This function is called while the client is waiting on the
1640 * server, so we can't make any server calls here.
1642 static void FILE_AsyncReadService(async_private *ovp)
1644 async_fileio *fileio = (async_fileio*) ovp;
1645 LPOVERLAPPED lpOverlapped = fileio->lpOverlapped;
1646 int result, r;
1647 int already = lpOverlapped->InternalHigh;
1649 TRACE("%p %p\n", lpOverlapped, fileio->buffer );
1651 /* check to see if the data is ready (non-blocking) */
1653 if ( fileio->fd_type == FD_TYPE_SOCKET )
1654 result = read (ovp->fd, &fileio->buffer[already], fileio->count - already);
1655 else
1657 result = pread (ovp->fd, &fileio->buffer[already], fileio->count - already,
1658 OVERLAPPED_OFFSET (lpOverlapped) + already);
1659 if ((result < 0) && (errno == ESPIPE))
1660 result = read (ovp->fd, &fileio->buffer[already], fileio->count - already);
1663 if ( (result<0) && ((errno == EAGAIN) || (errno == EINTR)))
1665 TRACE("Deferred read %d\n",errno);
1666 r = STATUS_PENDING;
1667 goto async_end;
1670 /* check to see if the transfer is complete */
1671 if(result<0)
1673 r = FILE_GetNtStatus ();
1674 goto async_end;
1677 lpOverlapped->InternalHigh += result;
1678 TRACE("read %d more bytes %ld/%d so far\n",result,lpOverlapped->InternalHigh,fileio->count);
1680 if(lpOverlapped->InternalHigh >= fileio->count || fileio->fd_type == FD_TYPE_SOCKET )
1681 r = STATUS_SUCCESS;
1682 else
1683 r = STATUS_PENDING;
1685 async_end:
1686 lpOverlapped->Internal = r;
1689 /***********************************************************************
1690 * FILE_ReadFileEx (INTERNAL)
1692 static BOOL FILE_ReadFileEx(HANDLE hFile, LPVOID buffer, DWORD bytesToRead,
1693 LPOVERLAPPED overlapped,
1694 LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine,
1695 HANDLE hEvent)
1697 async_fileio *ovp;
1698 int fd;
1699 int flags;
1700 enum fd_type type;
1702 TRACE("file %d to buf %p num %ld %p func %p\n",
1703 hFile, buffer, bytesToRead, overlapped, lpCompletionRoutine);
1705 /* check that there is an overlapped struct */
1706 if (overlapped==NULL)
1708 SetLastError(ERROR_INVALID_PARAMETER);
1709 return FALSE;
1712 fd = FILE_GetUnixHandleType ( hFile, GENERIC_READ, &type, &flags);
1713 if ( fd < 0 )
1715 WARN ( "Couldn't get FD\n" );
1716 return FALSE;
1719 ovp = (async_fileio*) HeapAlloc(GetProcessHeap(), 0, sizeof (async_fileio));
1720 if(!ovp)
1722 TRACE("HeapAlloc Failed\n");
1723 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1724 goto error;
1727 ovp->async.ops = ( lpCompletionRoutine ? &fileio_async_ops : &fileio_nocomp_async_ops );
1728 ovp->async.handle = hFile;
1729 ovp->async.fd = fd;
1730 ovp->async.type = ASYNC_TYPE_READ;
1731 ovp->async.func = FILE_AsyncReadService;
1732 ovp->async.event = hEvent;
1733 ovp->lpOverlapped = overlapped;
1734 ovp->count = bytesToRead;
1735 ovp->completion_func = lpCompletionRoutine;
1736 ovp->buffer = buffer;
1737 ovp->fd_type = type;
1739 return !register_new_async (&ovp->async);
1741 error:
1742 close (fd);
1743 return FALSE;
1747 /***********************************************************************
1748 * ReadFileEx (KERNEL32.@)
1750 BOOL WINAPI ReadFileEx(HANDLE hFile, LPVOID buffer, DWORD bytesToRead,
1751 LPOVERLAPPED overlapped,
1752 LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine)
1754 overlapped->InternalHigh = 0;
1755 return FILE_ReadFileEx(hFile,buffer,bytesToRead,overlapped,lpCompletionRoutine, INVALID_HANDLE_VALUE);
1758 static BOOL FILE_TimeoutRead(HANDLE hFile, LPVOID buffer, DWORD bytesToRead, LPDWORD bytesRead)
1760 OVERLAPPED ov;
1761 BOOL r = FALSE;
1763 TRACE("%d %p %ld %p\n", hFile, buffer, bytesToRead, bytesRead );
1765 ZeroMemory(&ov, sizeof (OVERLAPPED));
1766 if(STATUS_SUCCESS==NtCreateEvent(&ov.hEvent, SYNCHRONIZE, NULL, 0, 0))
1768 if(FILE_ReadFileEx(hFile, buffer, bytesToRead, &ov, NULL, ov.hEvent))
1770 r = GetOverlappedResult(hFile, &ov, bytesRead, TRUE);
1773 CloseHandle(ov.hEvent);
1774 return r;
1777 /***********************************************************************
1778 * ReadFile (KERNEL32.@)
1780 BOOL WINAPI ReadFile( HANDLE hFile, LPVOID buffer, DWORD bytesToRead,
1781 LPDWORD bytesRead, LPOVERLAPPED overlapped )
1783 int unix_handle, result, flags;
1784 enum fd_type type;
1786 TRACE("%d %p %ld %p %p\n", hFile, buffer, bytesToRead,
1787 bytesRead, overlapped );
1789 if (bytesRead) *bytesRead = 0; /* Do this before anything else */
1790 if (!bytesToRead) return TRUE;
1792 unix_handle = FILE_GetUnixHandleType( hFile, GENERIC_READ, &type, &flags );
1794 if (flags & FD_FLAG_OVERLAPPED)
1796 if (unix_handle == -1) return FALSE;
1797 if ( (overlapped==NULL) || NtResetEvent( overlapped->hEvent, NULL ) )
1799 TRACE("Overlapped not specified or invalid event flag\n");
1800 close(unix_handle);
1801 SetLastError(ERROR_INVALID_PARAMETER);
1802 return FALSE;
1805 close(unix_handle);
1806 overlapped->InternalHigh = 0;
1808 if(!FILE_ReadFileEx(hFile, buffer, bytesToRead, overlapped, NULL, overlapped->hEvent))
1809 return FALSE;
1811 if ( !GetOverlappedResult (hFile, overlapped, bytesRead, FALSE) )
1813 if ( GetLastError() == ERROR_IO_INCOMPLETE )
1814 SetLastError ( ERROR_IO_PENDING );
1815 return FALSE;
1818 return TRUE;
1820 if (flags & FD_FLAG_TIMEOUT)
1822 close(unix_handle);
1823 return FILE_TimeoutRead(hFile, buffer, bytesToRead, bytesRead);
1825 switch(type)
1827 case FD_TYPE_SMB:
1828 return SMB_ReadFile(hFile, buffer, bytesToRead, bytesRead, NULL);
1830 case FD_TYPE_CONSOLE:
1831 return FILE_ReadConsole(hFile, buffer, bytesToRead, bytesRead, NULL);
1833 case FD_TYPE_DEFAULT:
1834 /* normal unix files */
1835 if (unix_handle == -1) return FALSE;
1836 if (overlapped)
1838 DWORD highOffset = overlapped->OffsetHigh;
1839 if ( (INVALID_SET_FILE_POINTER == SetFilePointer(hFile, overlapped->Offset,
1840 &highOffset, FILE_BEGIN)) &&
1841 (GetLastError() != NO_ERROR) )
1843 close(unix_handle);
1844 return FALSE;
1847 break;
1849 default:
1850 if (unix_handle == -1)
1851 return FALSE;
1854 if(overlapped)
1856 off_t offset = OVERLAPPED_OFFSET(overlapped);
1857 if(lseek(unix_handle, offset, SEEK_SET) == -1)
1859 close(unix_handle);
1860 SetLastError(ERROR_INVALID_PARAMETER);
1861 return FALSE;
1865 /* code for synchronous reads */
1866 while ((result = read( unix_handle, buffer, bytesToRead )) == -1)
1868 if ((errno == EAGAIN) || (errno == EINTR)) continue;
1869 if ((errno == EFAULT) && !IsBadWritePtr( buffer, bytesToRead )) continue;
1870 FILE_SetDosError();
1871 break;
1873 close( unix_handle );
1874 if (result == -1) return FALSE;
1875 if (bytesRead) *bytesRead = result;
1876 return TRUE;
1880 /***********************************************************************
1881 * FILE_AsyncWriteService (INTERNAL)
1883 * This function is called while the client is waiting on the
1884 * server, so we can't make any server calls here.
1886 static void FILE_AsyncWriteService(struct async_private *ovp)
1888 async_fileio *fileio = (async_fileio *) ovp;
1889 LPOVERLAPPED lpOverlapped = fileio->lpOverlapped;
1890 int result, r;
1891 int already = lpOverlapped->InternalHigh;
1893 TRACE("(%p %p)\n",lpOverlapped,fileio->buffer);
1895 /* write some data (non-blocking) */
1897 if ( fileio->fd_type == FD_TYPE_SOCKET )
1898 result = write(ovp->fd, &fileio->buffer[already], fileio->count - already);
1899 else
1901 result = pwrite(ovp->fd, &fileio->buffer[already], fileio->count - already,
1902 OVERLAPPED_OFFSET (lpOverlapped) + already);
1903 if ((result < 0) && (errno == ESPIPE))
1904 result = write(ovp->fd, &fileio->buffer[already], fileio->count - already);
1907 if ( (result<0) && ((errno == EAGAIN) || (errno == EINTR)))
1909 r = STATUS_PENDING;
1910 goto async_end;
1913 /* check to see if the transfer is complete */
1914 if(result<0)
1916 r = FILE_GetNtStatus ();
1917 goto async_end;
1920 lpOverlapped->InternalHigh += result;
1922 TRACE("wrote %d more bytes %ld/%d so far\n",result,lpOverlapped->InternalHigh,fileio->count);
1924 if(lpOverlapped->InternalHigh < fileio->count)
1925 r = STATUS_PENDING;
1926 else
1927 r = STATUS_SUCCESS;
1929 async_end:
1930 lpOverlapped->Internal = r;
1933 /***********************************************************************
1934 * FILE_WriteFileEx
1936 static BOOL FILE_WriteFileEx(HANDLE hFile, LPCVOID buffer, DWORD bytesToWrite,
1937 LPOVERLAPPED overlapped,
1938 LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine,
1939 HANDLE hEvent)
1941 async_fileio *ovp;
1942 int fd;
1943 int flags;
1944 enum fd_type type;
1946 TRACE("file %d to buf %p num %ld %p func %p handle %d\n",
1947 hFile, buffer, bytesToWrite, overlapped, lpCompletionRoutine, hEvent);
1949 if (overlapped == NULL)
1951 SetLastError(ERROR_INVALID_PARAMETER);
1952 return FALSE;
1955 fd = FILE_GetUnixHandleType ( hFile, GENERIC_WRITE, &type, &flags );
1956 if ( fd < 0 )
1958 TRACE( "Couldn't get FD\n" );
1959 return FALSE;
1962 ovp = (async_fileio*) HeapAlloc(GetProcessHeap(), 0, sizeof (async_fileio));
1963 if(!ovp)
1965 TRACE("HeapAlloc Failed\n");
1966 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1967 goto error;
1970 ovp->async.ops = ( lpCompletionRoutine ? &fileio_async_ops : &fileio_nocomp_async_ops );
1971 ovp->async.handle = hFile;
1972 ovp->async.fd = fd;
1973 ovp->async.type = ASYNC_TYPE_WRITE;
1974 ovp->async.func = FILE_AsyncWriteService;
1975 ovp->lpOverlapped = overlapped;
1976 ovp->async.event = hEvent;
1977 ovp->buffer = (LPVOID) buffer;
1978 ovp->count = bytesToWrite;
1979 ovp->completion_func = lpCompletionRoutine;
1980 ovp->fd_type = type;
1982 return !register_new_async (&ovp->async);
1984 error:
1985 close (fd);
1986 return FALSE;
1989 /***********************************************************************
1990 * WriteFileEx (KERNEL32.@)
1992 BOOL WINAPI WriteFileEx(HANDLE hFile, LPCVOID buffer, DWORD bytesToWrite,
1993 LPOVERLAPPED overlapped,
1994 LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine)
1996 overlapped->InternalHigh = 0;
1998 return FILE_WriteFileEx(hFile, buffer, bytesToWrite, overlapped, lpCompletionRoutine, INVALID_HANDLE_VALUE);
2001 /***********************************************************************
2002 * WriteFile (KERNEL32.@)
2004 BOOL WINAPI WriteFile( HANDLE hFile, LPCVOID buffer, DWORD bytesToWrite,
2005 LPDWORD bytesWritten, LPOVERLAPPED overlapped )
2007 int unix_handle, result, flags;
2008 enum fd_type type;
2010 TRACE("%d %p %ld %p %p\n", hFile, buffer, bytesToWrite,
2011 bytesWritten, overlapped );
2013 if (bytesWritten) *bytesWritten = 0; /* Do this before anything else */
2014 if (!bytesToWrite) return TRUE;
2016 unix_handle = FILE_GetUnixHandleType( hFile, GENERIC_WRITE, &type, &flags );
2018 if (flags & FD_FLAG_OVERLAPPED)
2020 if (unix_handle == -1) return FALSE;
2021 if ( (overlapped==NULL) || NtResetEvent( overlapped->hEvent, NULL ) )
2023 TRACE("Overlapped not specified or invalid event flag\n");
2024 close(unix_handle);
2025 SetLastError(ERROR_INVALID_PARAMETER);
2026 return FALSE;
2029 close(unix_handle);
2030 overlapped->InternalHigh = 0;
2032 if(!FILE_WriteFileEx(hFile, buffer, bytesToWrite, overlapped, NULL, overlapped->hEvent))
2033 return FALSE;
2035 if ( !GetOverlappedResult (hFile, overlapped, bytesWritten, FALSE) )
2037 if ( GetLastError() == ERROR_IO_INCOMPLETE )
2038 SetLastError ( ERROR_IO_PENDING );
2039 return FALSE;
2042 return TRUE;
2045 switch(type)
2047 case FD_TYPE_CONSOLE:
2048 TRACE("%d %s %ld %p %p\n", hFile, debugstr_an(buffer, bytesToWrite), bytesToWrite,
2049 bytesWritten, overlapped );
2050 return FILE_WriteConsole(hFile, buffer, bytesToWrite, bytesWritten, NULL);
2052 case FD_TYPE_DEFAULT:
2053 if (unix_handle == -1) return FALSE;
2055 if(overlapped)
2057 DWORD highOffset = overlapped->OffsetHigh;
2058 if ( (INVALID_SET_FILE_POINTER == SetFilePointer(hFile, overlapped->Offset,
2059 &highOffset, FILE_BEGIN)) &&
2060 (GetLastError() != NO_ERROR) )
2062 close(unix_handle);
2063 return FALSE;
2066 break;
2068 default:
2069 if (unix_handle == -1)
2070 return FALSE;
2071 if (overlapped)
2073 close(unix_handle);
2074 SetLastError(ERROR_INVALID_PARAMETER);
2075 return FALSE;
2077 break;
2080 if(overlapped)
2082 off_t offset = OVERLAPPED_OFFSET(overlapped);
2083 if(lseek(unix_handle, offset, SEEK_SET) == -1)
2085 close(unix_handle);
2086 SetLastError(ERROR_INVALID_PARAMETER);
2087 return FALSE;
2091 /* synchronous file write */
2092 while ((result = write( unix_handle, buffer, bytesToWrite )) == -1)
2094 if ((errno == EAGAIN) || (errno == EINTR)) continue;
2095 if ((errno == EFAULT) && !IsBadReadPtr( buffer, bytesToWrite )) continue;
2096 if (errno == ENOSPC)
2097 SetLastError( ERROR_DISK_FULL );
2098 else
2099 FILE_SetDosError();
2100 break;
2102 close( unix_handle );
2103 if (result == -1) return FALSE;
2104 if (bytesWritten) *bytesWritten = result;
2105 return TRUE;
2109 /***********************************************************************
2110 * _hread (KERNEL.349)
2112 LONG WINAPI WIN16_hread( HFILE16 hFile, SEGPTR buffer, LONG count )
2114 LONG maxlen;
2116 TRACE("%d %08lx %ld\n",
2117 hFile, (DWORD)buffer, count );
2119 /* Some programs pass a count larger than the allocated buffer */
2120 maxlen = GetSelectorLimit16( SELECTOROF(buffer) ) - OFFSETOF(buffer) + 1;
2121 if (count > maxlen) count = maxlen;
2122 return _lread((HFILE)DosFileHandleToWin32Handle(hFile), MapSL(buffer), count );
2126 /***********************************************************************
2127 * _lread (KERNEL.82)
2129 UINT16 WINAPI WIN16_lread( HFILE16 hFile, SEGPTR buffer, UINT16 count )
2131 return (UINT16)WIN16_hread( hFile, buffer, (LONG)count );
2135 /***********************************************************************
2136 * _lread (KERNEL32.@)
2138 UINT WINAPI _lread( HFILE handle, LPVOID buffer, UINT count )
2140 DWORD result;
2141 if (!ReadFile( (HANDLE)handle, buffer, count, &result, NULL )) return -1;
2142 return result;
2146 /***********************************************************************
2147 * _lread16 (KERNEL.82)
2149 UINT16 WINAPI _lread16( HFILE16 hFile, LPVOID buffer, UINT16 count )
2151 return (UINT16)_lread((HFILE)DosFileHandleToWin32Handle(hFile), buffer, (LONG)count );
2155 /***********************************************************************
2156 * _lcreat (KERNEL.83)
2158 HFILE16 WINAPI _lcreat16( LPCSTR path, INT16 attr )
2160 return Win32HandleToDosFileHandle( (HANDLE)_lcreat( path, attr ) );
2164 /***********************************************************************
2165 * _lcreat (KERNEL32.@)
2167 HFILE WINAPI _lcreat( LPCSTR path, INT attr )
2169 /* Mask off all flags not explicitly allowed by the doc */
2170 attr &= FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM;
2171 TRACE("%s %02x\n", path, attr );
2172 return (HFILE)CreateFileA( path, GENERIC_READ | GENERIC_WRITE,
2173 FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
2174 CREATE_ALWAYS, attr, 0 );
2178 /***********************************************************************
2179 * SetFilePointer (KERNEL32.@)
2181 DWORD WINAPI SetFilePointer( HANDLE hFile, LONG distance, LONG *highword,
2182 DWORD method )
2184 DWORD ret = INVALID_SET_FILE_POINTER;
2186 TRACE("handle %d offset %ld high %ld origin %ld\n",
2187 hFile, distance, highword?*highword:0, method );
2189 SERVER_START_REQ( set_file_pointer )
2191 req->handle = hFile;
2192 req->low = distance;
2193 req->high = highword ? *highword : (distance >= 0) ? 0 : -1;
2194 /* FIXME: assumes 1:1 mapping between Windows and Unix seek constants */
2195 req->whence = method;
2196 SetLastError( 0 );
2197 if (!wine_server_call_err( req ))
2199 ret = reply->new_low;
2200 if (highword) *highword = reply->new_high;
2203 SERVER_END_REQ;
2204 return ret;
2208 /***********************************************************************
2209 * _llseek (KERNEL.84)
2211 * FIXME:
2212 * Seeking before the start of the file should be allowed for _llseek16,
2213 * but cause subsequent I/O operations to fail (cf. interrupt list)
2216 LONG WINAPI _llseek16( HFILE16 hFile, LONG lOffset, INT16 nOrigin )
2218 return SetFilePointer( DosFileHandleToWin32Handle(hFile), lOffset, NULL, nOrigin );
2222 /***********************************************************************
2223 * _llseek (KERNEL32.@)
2225 LONG WINAPI _llseek( HFILE hFile, LONG lOffset, INT nOrigin )
2227 return SetFilePointer( (HANDLE)hFile, lOffset, NULL, nOrigin );
2231 /***********************************************************************
2232 * _lopen (KERNEL.85)
2234 HFILE16 WINAPI _lopen16( LPCSTR path, INT16 mode )
2236 return Win32HandleToDosFileHandle( (HANDLE)_lopen( path, mode ) );
2240 /***********************************************************************
2241 * _lopen (KERNEL32.@)
2243 HFILE WINAPI _lopen( LPCSTR path, INT mode )
2245 DWORD access, sharing;
2247 TRACE("('%s',%04x)\n", path, mode );
2248 FILE_ConvertOFMode( mode, &access, &sharing );
2249 return (HFILE)CreateFileA( path, access, sharing, NULL, OPEN_EXISTING, 0, 0 );
2253 /***********************************************************************
2254 * _lwrite (KERNEL.86)
2256 UINT16 WINAPI _lwrite16( HFILE16 hFile, LPCSTR buffer, UINT16 count )
2258 return (UINT16)_hwrite( (HFILE)DosFileHandleToWin32Handle(hFile), buffer, (LONG)count );
2261 /***********************************************************************
2262 * _lwrite (KERNEL32.@)
2264 UINT WINAPI _lwrite( HFILE hFile, LPCSTR buffer, UINT count )
2266 return (UINT)_hwrite( hFile, buffer, (LONG)count );
2270 /***********************************************************************
2271 * _hread16 (KERNEL.349)
2273 LONG WINAPI _hread16( HFILE16 hFile, LPVOID buffer, LONG count)
2275 return _lread( (HFILE)DosFileHandleToWin32Handle(hFile), buffer, count );
2279 /***********************************************************************
2280 * _hread (KERNEL32.@)
2282 LONG WINAPI _hread( HFILE hFile, LPVOID buffer, LONG count)
2284 return _lread( hFile, buffer, count );
2288 /***********************************************************************
2289 * _hwrite (KERNEL.350)
2291 LONG WINAPI _hwrite16( HFILE16 hFile, LPCSTR buffer, LONG count )
2293 return _hwrite( (HFILE)DosFileHandleToWin32Handle(hFile), buffer, count );
2297 /***********************************************************************
2298 * _hwrite (KERNEL32.@)
2300 * experimentation yields that _lwrite:
2301 * o truncates the file at the current position with
2302 * a 0 len write
2303 * o returns 0 on a 0 length write
2304 * o works with console handles
2307 LONG WINAPI _hwrite( HFILE handle, LPCSTR buffer, LONG count )
2309 DWORD result;
2311 TRACE("%d %p %ld\n", handle, buffer, count );
2313 if (!count)
2315 /* Expand or truncate at current position */
2316 if (!SetEndOfFile( (HANDLE)handle )) return HFILE_ERROR;
2317 return 0;
2319 if (!WriteFile( (HANDLE)handle, buffer, count, &result, NULL ))
2320 return HFILE_ERROR;
2321 return result;
2325 /***********************************************************************
2326 * SetHandleCount (KERNEL.199)
2328 UINT16 WINAPI SetHandleCount16( UINT16 count )
2330 return SetHandleCount( count );
2334 /*************************************************************************
2335 * SetHandleCount (KERNEL32.@)
2337 UINT WINAPI SetHandleCount( UINT count )
2339 return min( 256, count );
2343 /***********************************************************************
2344 * FlushFileBuffers (KERNEL32.@)
2346 BOOL WINAPI FlushFileBuffers( HANDLE hFile )
2348 BOOL ret;
2349 SERVER_START_REQ( flush_file )
2351 req->handle = hFile;
2352 ret = !wine_server_call_err( req );
2354 SERVER_END_REQ;
2355 return ret;
2359 /**************************************************************************
2360 * SetEndOfFile (KERNEL32.@)
2362 BOOL WINAPI SetEndOfFile( HANDLE hFile )
2364 BOOL ret;
2365 SERVER_START_REQ( truncate_file )
2367 req->handle = hFile;
2368 ret = !wine_server_call_err( req );
2370 SERVER_END_REQ;
2371 return ret;
2375 /***********************************************************************
2376 * DeleteFile (KERNEL.146)
2378 BOOL16 WINAPI DeleteFile16( LPCSTR path )
2380 return DeleteFileA( path );
2384 /***********************************************************************
2385 * DeleteFileW (KERNEL32.@)
2387 BOOL WINAPI DeleteFileW( LPCWSTR path )
2389 DOS_FULL_NAME full_name;
2390 HANDLE hFile;
2392 if (!path)
2394 SetLastError(ERROR_INVALID_PARAMETER);
2395 return FALSE;
2397 TRACE("%s\n", debugstr_w(path) );
2399 if (!*path)
2401 ERR("Empty path passed\n");
2402 return FALSE;
2404 if (DOSFS_GetDevice( path ))
2406 WARN("cannot remove DOS device %s!\n", debugstr_w(path));
2407 SetLastError( ERROR_FILE_NOT_FOUND );
2408 return FALSE;
2411 if (!DOSFS_GetFullName( path, TRUE, &full_name )) return FALSE;
2413 /* check if we are allowed to delete the source */
2414 hFile = FILE_CreateFile( full_name.long_name, GENERIC_READ|GENERIC_WRITE, 0,
2415 NULL, OPEN_EXISTING, 0, 0, TRUE,
2416 GetDriveTypeW( full_name.short_name ) );
2417 if (!hFile) return FALSE;
2419 if (unlink( full_name.long_name ) == -1)
2421 FILE_SetDosError();
2422 CloseHandle(hFile);
2423 return FALSE;
2425 CloseHandle(hFile);
2426 return TRUE;
2430 /***********************************************************************
2431 * DeleteFileA (KERNEL32.@)
2433 BOOL WINAPI DeleteFileA( LPCSTR path )
2435 UNICODE_STRING pathW;
2436 BOOL ret = FALSE;
2438 if (!path)
2440 SetLastError(ERROR_INVALID_PARAMETER);
2441 return FALSE;
2444 if (RtlCreateUnicodeStringFromAsciiz(&pathW, path))
2446 ret = DeleteFileW(pathW.Buffer);
2447 RtlFreeUnicodeString(&pathW);
2449 else
2450 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
2451 return ret;
2455 /***********************************************************************
2456 * GetFileType (KERNEL32.@)
2458 DWORD WINAPI GetFileType( HANDLE hFile )
2460 DWORD ret = FILE_TYPE_UNKNOWN;
2461 SERVER_START_REQ( get_file_info )
2463 req->handle = hFile;
2464 if (!wine_server_call_err( req )) ret = reply->type;
2466 SERVER_END_REQ;
2467 return ret;
2471 /* check if a file name is for an executable file (.exe or .com) */
2472 inline static BOOL is_executable( const char *name )
2474 int len = strlen(name);
2476 if (len < 4) return FALSE;
2477 return (!strcasecmp( name + len - 4, ".exe" ) ||
2478 !strcasecmp( name + len - 4, ".com" ));
2482 /***********************************************************************
2483 * FILE_AddBootRenameEntry
2485 * Adds an entry to the registry that is loaded when windows boots and
2486 * checks if there are some files to be removed or renamed/moved.
2487 * <fn1> has to be valid and <fn2> may be NULL. If both pointers are
2488 * non-NULL then the file is moved, otherwise it is deleted. The
2489 * entry of the registrykey is always appended with two zero
2490 * terminated strings. If <fn2> is NULL then the second entry is
2491 * simply a single 0-byte. Otherwise the second filename goes
2492 * there. The entries are prepended with \??\ before the path and the
2493 * second filename gets also a '!' as the first character if
2494 * MOVEFILE_REPLACE_EXISTING is set. After the final string another
2495 * 0-byte follows to indicate the end of the strings.
2496 * i.e.:
2497 * \??\D:\test\file1[0]
2498 * !\??\D:\test\file1_renamed[0]
2499 * \??\D:\Test|delete[0]
2500 * [0] <- file is to be deleted, second string empty
2501 * \??\D:\test\file2[0]
2502 * !\??\D:\test\file2_renamed[0]
2503 * [0] <- indicates end of strings
2505 * or:
2506 * \??\D:\test\file1[0]
2507 * !\??\D:\test\file1_renamed[0]
2508 * \??\D:\Test|delete[0]
2509 * [0] <- file is to be deleted, second string empty
2510 * [0] <- indicates end of strings
2513 static BOOL FILE_AddBootRenameEntry( LPCWSTR fn1, LPCWSTR fn2, DWORD flags )
2515 static const WCHAR PreString[] = {'\\','?','?','\\',0};
2516 static const WCHAR ValueName[] = {'P','e','n','d','i','n','g',
2517 'F','i','l','e','R','e','n','a','m','e',
2518 'O','p','e','r','a','t','i','o','n','s',0};
2519 static const WCHAR SessionW[] = {'M','a','c','h','i','n','e','\\',
2520 'S','y','s','t','e','m','\\',
2521 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
2522 'C','o','n','t','r','o','l','\\',
2523 'S','e','s','s','i','o','n',' ','M','a','n','a','g','e','r',0};
2524 static const int info_size = FIELD_OFFSET( KEY_VALUE_PARTIAL_INFORMATION, Data );
2526 OBJECT_ATTRIBUTES attr;
2527 UNICODE_STRING nameW;
2528 KEY_VALUE_PARTIAL_INFORMATION *info;
2529 BOOL rc = FALSE;
2530 HKEY Reboot = 0;
2531 DWORD len0, len1, len2;
2532 DWORD DataSize = 0;
2533 BYTE *Buffer = NULL;
2534 WCHAR *p;
2536 attr.Length = sizeof(attr);
2537 attr.RootDirectory = 0;
2538 attr.ObjectName = &nameW;
2539 attr.Attributes = 0;
2540 attr.SecurityDescriptor = NULL;
2541 attr.SecurityQualityOfService = NULL;
2542 RtlInitUnicodeString( &nameW, SessionW );
2544 if (NtCreateKey( &Reboot, KEY_ALL_ACCESS, &attr, 0, NULL, 0, NULL ) != STATUS_SUCCESS)
2546 WARN("Error creating key for reboot managment [%s]\n",
2547 "SYSTEM\\CurrentControlSet\\Control\\Session Manager");
2548 return FALSE;
2551 len0 = strlenW(PreString);
2552 len1 = strlenW(fn1) + len0 + 1;
2553 if (fn2)
2555 len2 = strlenW(fn2) + len0 + 1;
2556 if (flags & MOVEFILE_REPLACE_EXISTING) len2++; /* Plus 1 because of the leading '!' */
2558 else len2 = 1; /* minimum is the 0 characters for the empty second string */
2560 /* convert characters to bytes */
2561 len0 *= sizeof(WCHAR);
2562 len1 *= sizeof(WCHAR);
2563 len2 *= sizeof(WCHAR);
2565 RtlInitUnicodeString( &nameW, ValueName );
2567 /* First we check if the key exists and if so how many bytes it already contains. */
2568 if (NtQueryValueKey( Reboot, &nameW, KeyValuePartialInformation,
2569 NULL, 0, &DataSize ) == STATUS_BUFFER_OVERFLOW)
2571 if (!(Buffer = HeapAlloc( GetProcessHeap(), 0, DataSize + len1 + len2 + sizeof(WCHAR) )))
2572 goto Quit;
2573 if (NtQueryValueKey( Reboot, &nameW, KeyValuePartialInformation,
2574 Buffer, DataSize, &DataSize )) goto Quit;
2575 info = (KEY_VALUE_PARTIAL_INFORMATION *)Buffer;
2576 if (info->Type != REG_MULTI_SZ) goto Quit;
2577 if (DataSize > sizeof(info)) DataSize -= sizeof(WCHAR); /* remove terminating null (will be added back later) */
2579 else
2581 DataSize = info_size;
2582 if (!(Buffer = HeapAlloc( GetProcessHeap(), 0, DataSize + len1 + len2 + sizeof(WCHAR) )))
2583 goto Quit;
2586 p = (WCHAR *)(Buffer + DataSize);
2587 strcpyW( p, PreString );
2588 strcatW( p, fn1 );
2589 DataSize += len1;
2590 if (fn2)
2592 p = (WCHAR *)(Buffer + DataSize);
2593 if (flags & MOVEFILE_REPLACE_EXISTING)
2594 *p++ = '!';
2595 strcpyW( p, PreString );
2596 strcatW( p, fn2 );
2597 DataSize += len2;
2599 else
2601 p = (WCHAR *)(Buffer + DataSize);
2602 *p = 0;
2603 DataSize += sizeof(WCHAR);
2606 /* add final null */
2607 p = (WCHAR *)(Buffer + DataSize);
2608 *p = 0;
2609 DataSize += sizeof(WCHAR);
2611 rc = !NtSetValueKey(Reboot, &nameW, 0, REG_MULTI_SZ, Buffer + info_size, DataSize - info_size);
2613 Quit:
2614 if (Reboot) NtClose(Reboot);
2615 if (Buffer) HeapFree( GetProcessHeap(), 0, Buffer );
2616 return(rc);
2620 /**************************************************************************
2621 * MoveFileExW (KERNEL32.@)
2623 BOOL WINAPI MoveFileExW( LPCWSTR fn1, LPCWSTR fn2, DWORD flag )
2625 DOS_FULL_NAME full_name1, full_name2;
2626 HANDLE hFile;
2627 DWORD attr = INVALID_FILE_ATTRIBUTES;
2629 TRACE("(%s,%s,%04lx)\n", debugstr_w(fn1), debugstr_w(fn2), flag);
2631 /* FIXME: <Gerhard W. Gruber>sparhawk@gmx.at
2632 In case of W9x and lesser this function should return 120 (ERROR_CALL_NOT_IMPLEMENTED)
2633 to be really compatible. Most programs wont have any problems though. In case
2634 you encounter one, this is what you should return here. I don't know what's up
2635 with NT 3.5. Is this function available there or not?
2636 Does anybody really care about 3.5? :)
2639 /* Filename1 has to be always set to a valid path. Filename2 may be NULL
2640 if the source file has to be deleted.
2642 if (!fn1) {
2643 SetLastError(ERROR_INVALID_PARAMETER);
2644 return FALSE;
2647 /* This function has to be run through in order to process the name properly.
2648 If the BOOTDELAY flag is set, the file doesn't need to exist though. At least
2649 that is the behaviour on NT 4.0. The operation accepts the filenames as
2650 they are given but it can't reply with a reasonable returncode. Success
2651 means in that case success for entering the values into the registry.
2653 if(!DOSFS_GetFullName( fn1, TRUE, &full_name1 ))
2655 if(!(flag & MOVEFILE_DELAY_UNTIL_REBOOT))
2656 return FALSE;
2659 if (fn2) /* !fn2 means delete fn1 */
2661 if (DOSFS_GetFullName( fn2, TRUE, &full_name2 ))
2663 if(!(flag & MOVEFILE_DELAY_UNTIL_REBOOT))
2665 /* target exists, check if we may overwrite */
2666 if (!(flag & MOVEFILE_REPLACE_EXISTING))
2668 SetLastError( ERROR_FILE_EXISTS );
2669 return FALSE;
2673 else
2675 if (!DOSFS_GetFullName( fn2, FALSE, &full_name2 ))
2677 if(!(flag & MOVEFILE_DELAY_UNTIL_REBOOT))
2678 return FALSE;
2682 /* Source name and target path are valid */
2684 if (flag & MOVEFILE_DELAY_UNTIL_REBOOT)
2686 /* FIXME: (bon@elektron.ikp.physik.th-darmstadt.de 970706)
2687 Perhaps we should queue these command and execute it
2688 when exiting... What about using on_exit(2)
2690 FIXME("Please move existing file %s to file %s when Wine has finished\n",
2691 debugstr_w(fn1), debugstr_w(fn2));
2692 return FILE_AddBootRenameEntry( fn1, fn2, flag );
2695 attr = GetFileAttributesW( fn1 );
2696 if ( attr == INVALID_FILE_ATTRIBUTES ) return FALSE;
2698 /* check if we are allowed to rename the source */
2699 hFile = FILE_CreateFile( full_name1.long_name, 0, 0,
2700 NULL, OPEN_EXISTING, 0, 0, TRUE,
2701 GetDriveTypeW( full_name1.short_name ) );
2702 if (!hFile)
2704 if (GetLastError() != ERROR_ACCESS_DENIED) return FALSE;
2705 if ( !(attr & FILE_ATTRIBUTE_DIRECTORY) ) return FALSE;
2706 /* if it's a directory we can continue */
2708 else CloseHandle(hFile);
2710 /* check, if we are allowed to delete the destination,
2711 ** (but the file not being there is fine) */
2712 hFile = FILE_CreateFile( full_name2.long_name, GENERIC_READ|GENERIC_WRITE, 0,
2713 NULL, OPEN_EXISTING, 0, 0, TRUE,
2714 GetDriveTypeW( full_name2.short_name ) );
2715 if(!hFile && GetLastError() != ERROR_FILE_NOT_FOUND) return FALSE;
2716 CloseHandle(hFile);
2718 if (full_name1.drive != full_name2.drive)
2720 if (!(flag & MOVEFILE_COPY_ALLOWED))
2722 SetLastError( ERROR_NOT_SAME_DEVICE );
2723 return FALSE;
2725 else if ( attr & FILE_ATTRIBUTE_DIRECTORY )
2727 /* Strange, but that's what Windows returns */
2728 SetLastError ( ERROR_ACCESS_DENIED );
2729 return FALSE;
2732 if (rename( full_name1.long_name, full_name2.long_name ) == -1)
2733 /* Try copy/delete unless it's a directory. */
2734 /* FIXME: This does not handle the (unlikely) case that the two locations
2735 are on the same Wine drive, but on different Unix file systems. */
2737 if ( attr & FILE_ATTRIBUTE_DIRECTORY )
2739 FILE_SetDosError();
2740 return FALSE;
2742 else
2744 if ( ! CopyFileW( fn1, fn2, !(flag & MOVEFILE_REPLACE_EXISTING) ))
2745 return FALSE;
2746 if ( ! DeleteFileW ( fn1 ) )
2747 return FALSE;
2750 if (is_executable( full_name1.long_name ) != is_executable( full_name2.long_name ))
2752 struct stat fstat;
2753 if (stat( full_name2.long_name, &fstat ) != -1)
2755 if (is_executable( full_name2.long_name ))
2756 /* set executable bit where read bit is set */
2757 fstat.st_mode |= (fstat.st_mode & 0444) >> 2;
2758 else
2759 fstat.st_mode &= ~0111;
2760 chmod( full_name2.long_name, fstat.st_mode );
2763 return TRUE;
2765 else /* fn2 == NULL means delete source */
2767 if (flag & MOVEFILE_DELAY_UNTIL_REBOOT)
2769 if (flag & MOVEFILE_COPY_ALLOWED) {
2770 WARN("Illegal flag\n");
2771 SetLastError( ERROR_GEN_FAILURE );
2772 return FALSE;
2774 /* FIXME: (bon@elektron.ikp.physik.th-darmstadt.de 970706)
2775 Perhaps we should queue these command and execute it
2776 when exiting... What about using on_exit(2)
2778 FIXME("Please delete file %s when Wine has finished\n", debugstr_w(fn1));
2779 return FILE_AddBootRenameEntry( fn1, NULL, flag );
2782 if (unlink( full_name1.long_name ) == -1)
2784 FILE_SetDosError();
2785 return FALSE;
2787 return TRUE; /* successfully deleted */
2791 /**************************************************************************
2792 * MoveFileExA (KERNEL32.@)
2794 BOOL WINAPI MoveFileExA( LPCSTR fn1, LPCSTR fn2, DWORD flag )
2796 UNICODE_STRING fn1W, fn2W;
2797 BOOL ret;
2799 if (!fn1)
2801 SetLastError(ERROR_INVALID_PARAMETER);
2802 return FALSE;
2805 RtlCreateUnicodeStringFromAsciiz(&fn1W, fn1);
2806 if (fn2) RtlCreateUnicodeStringFromAsciiz(&fn2W, fn2);
2807 else fn2W.Buffer = NULL;
2809 ret = MoveFileExW( fn1W.Buffer, fn2W.Buffer, flag );
2811 RtlFreeUnicodeString(&fn1W);
2812 RtlFreeUnicodeString(&fn2W);
2813 return ret;
2817 /**************************************************************************
2818 * MoveFileW (KERNEL32.@)
2820 * Move file or directory
2822 BOOL WINAPI MoveFileW( LPCWSTR fn1, LPCWSTR fn2 )
2824 DOS_FULL_NAME full_name1, full_name2;
2825 struct stat fstat;
2827 if (!fn1 || !fn2)
2829 SetLastError(ERROR_INVALID_PARAMETER);
2830 return FALSE;
2833 TRACE("(%s,%s)\n", debugstr_w(fn1), debugstr_w(fn2) );
2835 if (!DOSFS_GetFullName( fn1, TRUE, &full_name1 )) return FALSE;
2836 if (DOSFS_GetFullName( fn2, TRUE, &full_name2 )) {
2837 /* The new name must not already exist */
2838 SetLastError(ERROR_ALREADY_EXISTS);
2839 return FALSE;
2841 if (!DOSFS_GetFullName( fn2, FALSE, &full_name2 )) return FALSE;
2843 if (full_name1.drive == full_name2.drive) /* move */
2844 return MoveFileExW( fn1, fn2, MOVEFILE_COPY_ALLOWED );
2846 /* copy */
2847 if (stat( full_name1.long_name, &fstat ))
2849 WARN("Invalid source file %s\n",
2850 full_name1.long_name);
2851 FILE_SetDosError();
2852 return FALSE;
2854 if (S_ISDIR(fstat.st_mode)) {
2855 /* No Move for directories across file systems */
2856 /* FIXME: Use right error code */
2857 SetLastError( ERROR_GEN_FAILURE );
2858 return FALSE;
2860 return CopyFileW(fn1, fn2, TRUE); /*fail, if exist */
2864 /**************************************************************************
2865 * MoveFileA (KERNEL32.@)
2867 BOOL WINAPI MoveFileA( LPCSTR fn1, LPCSTR fn2 )
2869 UNICODE_STRING fn1W, fn2W;
2870 BOOL ret;
2872 if (!fn1 || !fn2)
2874 SetLastError(ERROR_INVALID_PARAMETER);
2875 return FALSE;
2878 RtlCreateUnicodeStringFromAsciiz(&fn1W, fn1);
2879 RtlCreateUnicodeStringFromAsciiz(&fn2W, fn2);
2881 ret = MoveFileW( fn1W.Buffer, fn2W.Buffer );
2883 RtlFreeUnicodeString(&fn1W);
2884 RtlFreeUnicodeString(&fn2W);
2885 return ret;
2889 /**************************************************************************
2890 * CopyFileW (KERNEL32.@)
2892 BOOL WINAPI CopyFileW( LPCWSTR source, LPCWSTR dest, BOOL fail_if_exists )
2894 HANDLE h1, h2;
2895 BY_HANDLE_FILE_INFORMATION info;
2896 DWORD count;
2897 BOOL ret = FALSE;
2898 char buffer[2048];
2900 if (!source || !dest)
2902 SetLastError(ERROR_INVALID_PARAMETER);
2903 return FALSE;
2906 TRACE("%s -> %s\n", debugstr_w(source), debugstr_w(dest));
2908 if ((h1 = CreateFileW(source, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE,
2909 NULL, OPEN_EXISTING, 0, 0)) == INVALID_HANDLE_VALUE)
2911 WARN("Unable to open source %s\n", debugstr_w(source));
2912 return FALSE;
2915 if (!GetFileInformationByHandle( h1, &info ))
2917 WARN("GetFileInformationByHandle returned error for %s\n", debugstr_w(source));
2918 CloseHandle( h1 );
2919 return FALSE;
2922 if ((h2 = CreateFileW( dest, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
2923 fail_if_exists ? CREATE_NEW : CREATE_ALWAYS,
2924 info.dwFileAttributes, h1 )) == INVALID_HANDLE_VALUE)
2926 WARN("Unable to open dest %s\n", debugstr_w(dest));
2927 CloseHandle( h1 );
2928 return FALSE;
2931 while (ReadFile( h1, buffer, sizeof(buffer), &count, NULL ) && count)
2933 char *p = buffer;
2934 while (count != 0)
2936 DWORD res;
2937 if (!WriteFile( h2, p, count, &res, NULL ) || !res) goto done;
2938 p += res;
2939 count -= res;
2942 ret = TRUE;
2943 done:
2944 CloseHandle( h1 );
2945 CloseHandle( h2 );
2946 return ret;
2950 /**************************************************************************
2951 * CopyFileA (KERNEL32.@)
2953 BOOL WINAPI CopyFileA( LPCSTR source, LPCSTR dest, BOOL fail_if_exists)
2955 UNICODE_STRING sourceW, destW;
2956 BOOL ret;
2958 if (!source || !dest)
2960 SetLastError(ERROR_INVALID_PARAMETER);
2961 return FALSE;
2964 RtlCreateUnicodeStringFromAsciiz(&sourceW, source);
2965 RtlCreateUnicodeStringFromAsciiz(&destW, dest);
2967 ret = CopyFileW(sourceW.Buffer, destW.Buffer, fail_if_exists);
2969 RtlFreeUnicodeString(&sourceW);
2970 RtlFreeUnicodeString(&destW);
2971 return ret;
2975 /**************************************************************************
2976 * CopyFileExW (KERNEL32.@)
2978 * This implementation ignores most of the extra parameters passed-in into
2979 * the "ex" version of the method and calls the CopyFile method.
2980 * It will have to be fixed eventually.
2982 BOOL WINAPI CopyFileExW(LPCWSTR sourceFilename, LPCWSTR destFilename,
2983 LPPROGRESS_ROUTINE progressRoutine, LPVOID appData,
2984 LPBOOL cancelFlagPointer, DWORD copyFlags)
2987 * Interpret the only flag that CopyFile can interpret.
2989 return CopyFileW(sourceFilename, destFilename, (copyFlags & COPY_FILE_FAIL_IF_EXISTS) != 0);
2992 /**************************************************************************
2993 * CopyFileExA (KERNEL32.@)
2995 BOOL WINAPI CopyFileExA(LPCSTR sourceFilename, LPCSTR destFilename,
2996 LPPROGRESS_ROUTINE progressRoutine, LPVOID appData,
2997 LPBOOL cancelFlagPointer, DWORD copyFlags)
2999 UNICODE_STRING sourceW, destW;
3000 BOOL ret;
3002 if (!sourceFilename || !destFilename)
3004 SetLastError(ERROR_INVALID_PARAMETER);
3005 return FALSE;
3008 RtlCreateUnicodeStringFromAsciiz(&sourceW, sourceFilename);
3009 RtlCreateUnicodeStringFromAsciiz(&destW, destFilename);
3011 ret = CopyFileExW(sourceW.Buffer, destW.Buffer, progressRoutine, appData,
3012 cancelFlagPointer, copyFlags);
3014 RtlFreeUnicodeString(&sourceW);
3015 RtlFreeUnicodeString(&destW);
3016 return ret;
3020 /***********************************************************************
3021 * SetFileTime (KERNEL32.@)
3023 BOOL WINAPI SetFileTime( HANDLE hFile,
3024 const FILETIME *lpCreationTime,
3025 const FILETIME *lpLastAccessTime,
3026 const FILETIME *lpLastWriteTime )
3028 BOOL ret;
3029 SERVER_START_REQ( set_file_time )
3031 req->handle = hFile;
3032 if (lpLastAccessTime)
3033 RtlTimeToSecondsSince1970( (PLARGE_INTEGER) lpLastAccessTime, (DWORD *)&req->access_time );
3034 else
3035 req->access_time = 0; /* FIXME */
3036 if (lpLastWriteTime)
3037 RtlTimeToSecondsSince1970( (PLARGE_INTEGER) lpLastWriteTime, (DWORD *)&req->write_time );
3038 else
3039 req->write_time = 0; /* FIXME */
3040 ret = !wine_server_call_err( req );
3042 SERVER_END_REQ;
3043 return ret;
3047 /**************************************************************************
3048 * LockFile (KERNEL32.@)
3050 BOOL WINAPI LockFile( HANDLE hFile, DWORD dwFileOffsetLow, DWORD dwFileOffsetHigh,
3051 DWORD nNumberOfBytesToLockLow, DWORD nNumberOfBytesToLockHigh )
3053 BOOL ret;
3055 FIXME("not implemented in server\n");
3057 SERVER_START_REQ( lock_file )
3059 req->handle = hFile;
3060 req->offset_low = dwFileOffsetLow;
3061 req->offset_high = dwFileOffsetHigh;
3062 req->count_low = nNumberOfBytesToLockLow;
3063 req->count_high = nNumberOfBytesToLockHigh;
3064 ret = !wine_server_call_err( req );
3066 SERVER_END_REQ;
3067 return ret;
3070 /**************************************************************************
3071 * LockFileEx [KERNEL32.@]
3073 * Locks a byte range within an open file for shared or exclusive access.
3075 * RETURNS
3076 * success: TRUE
3077 * failure: FALSE
3079 * NOTES
3080 * Per Microsoft docs, the third parameter (reserved) must be set to 0.
3082 BOOL WINAPI LockFileEx( HANDLE hFile, DWORD flags, DWORD reserved,
3083 DWORD nNumberOfBytesToLockLow, DWORD nNumberOfBytesToLockHigh,
3084 LPOVERLAPPED pOverlapped )
3086 FIXME("hFile=%d,flags=%ld,reserved=%ld,lowbytes=%ld,highbytes=%ld,overlapped=%p: stub.\n",
3087 hFile, flags, reserved, nNumberOfBytesToLockLow, nNumberOfBytesToLockHigh,
3088 pOverlapped);
3089 if (reserved == 0)
3090 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
3091 else
3093 ERR("reserved == %ld: Supposed to be 0??\n", reserved);
3094 SetLastError(ERROR_INVALID_PARAMETER);
3097 return FALSE;
3101 /**************************************************************************
3102 * UnlockFile (KERNEL32.@)
3104 BOOL WINAPI UnlockFile( HANDLE hFile, DWORD dwFileOffsetLow, DWORD dwFileOffsetHigh,
3105 DWORD nNumberOfBytesToUnlockLow, DWORD nNumberOfBytesToUnlockHigh )
3107 BOOL ret;
3109 FIXME("not implemented in server\n");
3111 SERVER_START_REQ( unlock_file )
3113 req->handle = hFile;
3114 req->offset_low = dwFileOffsetLow;
3115 req->offset_high = dwFileOffsetHigh;
3116 req->count_low = nNumberOfBytesToUnlockLow;
3117 req->count_high = nNumberOfBytesToUnlockHigh;
3118 ret = !wine_server_call_err( req );
3120 SERVER_END_REQ;
3121 return ret;
3125 /**************************************************************************
3126 * UnlockFileEx (KERNEL32.@)
3128 BOOL WINAPI UnlockFileEx(
3129 HANDLE hFile,
3130 DWORD dwReserved,
3131 DWORD nNumberOfBytesToUnlockLow,
3132 DWORD nNumberOfBytesToUnlockHigh,
3133 LPOVERLAPPED lpOverlapped
3136 FIXME("hFile=%d,reserved=%ld,lowbytes=%ld,highbytes=%ld,overlapped=%p: stub.\n",
3137 hFile, dwReserved, nNumberOfBytesToUnlockLow, nNumberOfBytesToUnlockHigh,
3138 lpOverlapped);
3139 if (dwReserved == 0)
3140 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
3141 else
3143 ERR("reserved == %ld: Supposed to be 0??\n", dwReserved);
3144 SetLastError(ERROR_INVALID_PARAMETER);
3147 return FALSE;
3151 #if 0
3153 struct DOS_FILE_LOCK {
3154 struct DOS_FILE_LOCK * next;
3155 DWORD base;
3156 DWORD len;
3157 DWORD processId;
3158 FILE_OBJECT * dos_file;
3159 /* char * unix_name;*/
3162 typedef struct DOS_FILE_LOCK DOS_FILE_LOCK;
3164 static DOS_FILE_LOCK *locks = NULL;
3165 static void DOS_RemoveFileLocks(FILE_OBJECT *file);
3168 /* Locks need to be mirrored because unix file locking is based
3169 * on the pid. Inside of wine there can be multiple WINE processes
3170 * that share the same unix pid.
3171 * Read's and writes should check these locks also - not sure
3172 * how critical that is at this point (FIXME).
3175 static BOOL DOS_AddLock(FILE_OBJECT *file, struct flock *f)
3177 DOS_FILE_LOCK *curr;
3178 DWORD processId;
3180 processId = GetCurrentProcessId();
3182 /* check if lock overlaps a current lock for the same file */
3183 #if 0
3184 for (curr = locks; curr; curr = curr->next) {
3185 if (strcmp(curr->unix_name, file->unix_name) == 0) {
3186 if ((f->l_start == curr->base) && (f->l_len == curr->len))
3187 return TRUE;/* region is identic */
3188 if ((f->l_start < (curr->base + curr->len)) &&
3189 ((f->l_start + f->l_len) > curr->base)) {
3190 /* region overlaps */
3191 return FALSE;
3195 #endif
3197 curr = HeapAlloc( GetProcessHeap(), 0, sizeof(DOS_FILE_LOCK) );
3198 curr->processId = GetCurrentProcessId();
3199 curr->base = f->l_start;
3200 curr->len = f->l_len;
3201 /* curr->unix_name = HEAP_strdupA( GetProcessHeap(), 0, file->unix_name);*/
3202 curr->next = locks;
3203 curr->dos_file = file;
3204 locks = curr;
3205 return TRUE;
3208 static void DOS_RemoveFileLocks(FILE_OBJECT *file)
3210 DWORD processId;
3211 DOS_FILE_LOCK **curr;
3212 DOS_FILE_LOCK *rem;
3214 processId = GetCurrentProcessId();
3215 curr = &locks;
3216 while (*curr) {
3217 if ((*curr)->dos_file == file) {
3218 rem = *curr;
3219 *curr = (*curr)->next;
3220 /* HeapFree( GetProcessHeap(), 0, rem->unix_name );*/
3221 HeapFree( GetProcessHeap(), 0, rem );
3223 else
3224 curr = &(*curr)->next;
3228 static BOOL DOS_RemoveLock(FILE_OBJECT *file, struct flock *f)
3230 DWORD processId;
3231 DOS_FILE_LOCK **curr;
3232 DOS_FILE_LOCK *rem;
3234 processId = GetCurrentProcessId();
3235 for (curr = &locks; *curr; curr = &(*curr)->next) {
3236 if ((*curr)->processId == processId &&
3237 (*curr)->dos_file == file &&
3238 (*curr)->base == f->l_start &&
3239 (*curr)->len == f->l_len) {
3240 /* this is the same lock */
3241 rem = *curr;
3242 *curr = (*curr)->next;
3243 /* HeapFree( GetProcessHeap(), 0, rem->unix_name );*/
3244 HeapFree( GetProcessHeap(), 0, rem );
3245 return TRUE;
3248 /* no matching lock found */
3249 return FALSE;
3253 /**************************************************************************
3254 * LockFile (KERNEL32.@)
3256 BOOL WINAPI LockFile(
3257 HANDLE hFile,DWORD dwFileOffsetLow,DWORD dwFileOffsetHigh,
3258 DWORD nNumberOfBytesToLockLow,DWORD nNumberOfBytesToLockHigh )
3260 struct flock f;
3261 FILE_OBJECT *file;
3263 TRACE("handle %d offsetlow=%ld offsethigh=%ld nbyteslow=%ld nbyteshigh=%ld\n",
3264 hFile, dwFileOffsetLow, dwFileOffsetHigh,
3265 nNumberOfBytesToLockLow, nNumberOfBytesToLockHigh);
3267 if (dwFileOffsetHigh || nNumberOfBytesToLockHigh) {
3268 FIXME("Unimplemented bytes > 32bits\n");
3269 return FALSE;
3272 f.l_start = dwFileOffsetLow;
3273 f.l_len = nNumberOfBytesToLockLow;
3274 f.l_whence = SEEK_SET;
3275 f.l_pid = 0;
3276 f.l_type = F_WRLCK;
3278 if (!(file = FILE_GetFile(hFile,0,NULL))) return FALSE;
3280 /* shadow locks internally */
3281 if (!DOS_AddLock(file, &f)) {
3282 SetLastError( ERROR_LOCK_VIOLATION );
3283 return FALSE;
3286 /* FIXME: Unix locking commented out for now, doesn't work with Excel */
3287 #ifdef USE_UNIX_LOCKS
3288 if (fcntl(file->unix_handle, F_SETLK, &f) == -1) {
3289 if (errno == EACCES || errno == EAGAIN) {
3290 SetLastError( ERROR_LOCK_VIOLATION );
3292 else {
3293 FILE_SetDosError();
3295 /* remove our internal copy of the lock */
3296 DOS_RemoveLock(file, &f);
3297 return FALSE;
3299 #endif
3300 return TRUE;
3304 /**************************************************************************
3305 * UnlockFile (KERNEL32.@)
3307 BOOL WINAPI UnlockFile(
3308 HANDLE hFile,DWORD dwFileOffsetLow,DWORD dwFileOffsetHigh,
3309 DWORD nNumberOfBytesToUnlockLow,DWORD nNumberOfBytesToUnlockHigh )
3311 FILE_OBJECT *file;
3312 struct flock f;
3314 TRACE("handle %d offsetlow=%ld offsethigh=%ld nbyteslow=%ld nbyteshigh=%ld\n",
3315 hFile, dwFileOffsetLow, dwFileOffsetHigh,
3316 nNumberOfBytesToUnlockLow, nNumberOfBytesToUnlockHigh);
3318 if (dwFileOffsetHigh || nNumberOfBytesToUnlockHigh) {
3319 WARN("Unimplemented bytes > 32bits\n");
3320 return FALSE;
3323 f.l_start = dwFileOffsetLow;
3324 f.l_len = nNumberOfBytesToUnlockLow;
3325 f.l_whence = SEEK_SET;
3326 f.l_pid = 0;
3327 f.l_type = F_UNLCK;
3329 if (!(file = FILE_GetFile(hFile,0,NULL))) return FALSE;
3331 DOS_RemoveLock(file, &f); /* ok if fails - may be another wine */
3333 /* FIXME: Unix locking commented out for now, doesn't work with Excel */
3334 #ifdef USE_UNIX_LOCKS
3335 if (fcntl(file->unix_handle, F_SETLK, &f) == -1) {
3336 FILE_SetDosError();
3337 return FALSE;
3339 #endif
3340 return TRUE;
3342 #endif
3344 /**************************************************************************
3345 * GetFileAttributesExW (KERNEL32.@)
3347 BOOL WINAPI GetFileAttributesExW(
3348 LPCWSTR lpFileName, GET_FILEEX_INFO_LEVELS fInfoLevelId,
3349 LPVOID lpFileInformation)
3351 DOS_FULL_NAME full_name;
3352 BY_HANDLE_FILE_INFORMATION info;
3354 if (!lpFileName || !lpFileInformation)
3356 SetLastError(ERROR_INVALID_PARAMETER);
3357 return FALSE;
3360 if (fInfoLevelId == GetFileExInfoStandard) {
3361 LPWIN32_FILE_ATTRIBUTE_DATA lpFad =
3362 (LPWIN32_FILE_ATTRIBUTE_DATA) lpFileInformation;
3363 if (!DOSFS_GetFullName( lpFileName, TRUE, &full_name )) return FALSE;
3364 if (!FILE_Stat( full_name.long_name, &info )) return FALSE;
3366 lpFad->dwFileAttributes = info.dwFileAttributes;
3367 lpFad->ftCreationTime = info.ftCreationTime;
3368 lpFad->ftLastAccessTime = info.ftLastAccessTime;
3369 lpFad->ftLastWriteTime = info.ftLastWriteTime;
3370 lpFad->nFileSizeHigh = info.nFileSizeHigh;
3371 lpFad->nFileSizeLow = info.nFileSizeLow;
3373 else {
3374 FIXME("invalid info level %d!\n", fInfoLevelId);
3375 return FALSE;
3378 return TRUE;
3382 /**************************************************************************
3383 * GetFileAttributesExA (KERNEL32.@)
3385 BOOL WINAPI GetFileAttributesExA(
3386 LPCSTR filename, GET_FILEEX_INFO_LEVELS fInfoLevelId,
3387 LPVOID lpFileInformation)
3389 UNICODE_STRING filenameW;
3390 BOOL ret = FALSE;
3392 if (!filename || !lpFileInformation)
3394 SetLastError(ERROR_INVALID_PARAMETER);
3395 return FALSE;
3398 if (RtlCreateUnicodeStringFromAsciiz(&filenameW, filename))
3400 ret = GetFileAttributesExW(filenameW.Buffer, fInfoLevelId, lpFileInformation);
3401 RtlFreeUnicodeString(&filenameW);
3403 else
3404 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
3405 return ret;