Add upper limit for the number of pending timer interrupts.
[wine.git] / files / file.c
blobe50eccd06875f61905b5c25a8ea4c7c011067092
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 <stdarg.h>
35 #include <stdio.h>
36 #include <string.h>
37 #ifdef HAVE_SYS_ERRNO_H
38 #include <sys/errno.h>
39 #endif
40 #include <sys/types.h>
41 #include <sys/stat.h>
42 #ifdef HAVE_SYS_MMAN_H
43 #include <sys/mman.h>
44 #endif
45 #ifdef HAVE_SYS_TIME_H
46 # include <sys/time.h>
47 #endif
48 #ifdef HAVE_SYS_POLL_H
49 # include <sys/poll.h>
50 #endif
51 #include <time.h>
52 #ifdef HAVE_UNISTD_H
53 # include <unistd.h>
54 #endif
55 #ifdef HAVE_UTIME_H
56 # include <utime.h>
57 #endif
59 #define NONAMELESSUNION
60 #define NONAMELESSSTRUCT
61 #include "winerror.h"
62 #include "ntstatus.h"
63 #include "windef.h"
64 #include "winbase.h"
65 #include "winreg.h"
66 #include "winternl.h"
67 #include "wine/winbase16.h"
68 #include "wine/server.h"
70 #include "drive.h"
71 #include "file.h"
72 #include "wincon.h"
73 #include "kernel_private.h"
75 #include "smb.h"
76 #include "wine/unicode.h"
77 #include "wine/debug.h"
79 WINE_DEFAULT_DEBUG_CHANNEL(file);
81 #if defined(MAP_ANONYMOUS) && !defined(MAP_ANON)
82 #define MAP_ANON MAP_ANONYMOUS
83 #endif
85 #define IS_OPTION_TRUE(ch) ((ch) == 'y' || (ch) == 'Y' || (ch) == 't' || (ch) == 'T' || (ch) == '1')
87 HANDLE dos_handles[DOS_TABLE_SIZE];
88 mode_t FILE_umask;
90 /***********************************************************************
91 * FILE_ConvertOFMode
93 * Convert OF_* mode into flags for CreateFile.
95 void FILE_ConvertOFMode( INT mode, DWORD *access, DWORD *sharing )
97 switch(mode & 0x03)
99 case OF_READ: *access = GENERIC_READ; break;
100 case OF_WRITE: *access = GENERIC_WRITE; break;
101 case OF_READWRITE: *access = GENERIC_READ | GENERIC_WRITE; break;
102 default: *access = 0; break;
104 switch(mode & 0x70)
106 case OF_SHARE_EXCLUSIVE: *sharing = 0; break;
107 case OF_SHARE_DENY_WRITE: *sharing = FILE_SHARE_READ; break;
108 case OF_SHARE_DENY_READ: *sharing = FILE_SHARE_WRITE; break;
109 case OF_SHARE_DENY_NONE:
110 case OF_SHARE_COMPAT:
111 default: *sharing = FILE_SHARE_READ | FILE_SHARE_WRITE; break;
116 /***********************************************************************
117 * FILE_strcasecmp
119 * locale-independent case conversion for file I/O
121 int FILE_strcasecmp( const char *str1, const char *str2 )
123 int ret = 0;
124 for ( ; ; str1++, str2++)
125 if ((ret = FILE_toupper(*str1) - FILE_toupper(*str2)) || !*str1) break;
126 return ret;
130 /***********************************************************************
131 * FILE_strncasecmp
133 * locale-independent case conversion for file I/O
135 int FILE_strncasecmp( const char *str1, const char *str2, int len )
137 int ret = 0;
138 for ( ; len > 0; len--, str1++, str2++)
139 if ((ret = FILE_toupper(*str1) - FILE_toupper(*str2)) || !*str1) break;
140 return ret;
144 /***********************************************************************
145 * FILE_SetDosError
147 * Set the DOS error code from errno.
149 void FILE_SetDosError(void)
151 int save_errno = errno; /* errno gets overwritten by printf */
153 TRACE("errno = %d %s\n", errno, strerror(errno));
154 switch (save_errno)
156 case EAGAIN:
157 SetLastError( ERROR_SHARING_VIOLATION );
158 break;
159 case EBADF:
160 SetLastError( ERROR_INVALID_HANDLE );
161 break;
162 case ENOSPC:
163 SetLastError( ERROR_HANDLE_DISK_FULL );
164 break;
165 case EACCES:
166 case EPERM:
167 case EROFS:
168 SetLastError( ERROR_ACCESS_DENIED );
169 break;
170 case EBUSY:
171 SetLastError( ERROR_LOCK_VIOLATION );
172 break;
173 case ENOENT:
174 SetLastError( ERROR_FILE_NOT_FOUND );
175 break;
176 case EISDIR:
177 SetLastError( ERROR_CANNOT_MAKE );
178 break;
179 case ENFILE:
180 case EMFILE:
181 SetLastError( ERROR_NO_MORE_FILES );
182 break;
183 case EEXIST:
184 SetLastError( ERROR_FILE_EXISTS );
185 break;
186 case EINVAL:
187 case ESPIPE:
188 SetLastError( ERROR_SEEK );
189 break;
190 case ENOTEMPTY:
191 SetLastError( ERROR_DIR_NOT_EMPTY );
192 break;
193 case ENOEXEC:
194 SetLastError( ERROR_BAD_FORMAT );
195 break;
196 default:
197 WARN("unknown file error: %s\n", strerror(save_errno) );
198 SetLastError( ERROR_GEN_FAILURE );
199 break;
201 errno = save_errno;
205 /***********************************************************************
206 * FILE_GetUnixHandleType
208 * Retrieve the Unix handle corresponding to a file handle.
209 * Returns -1 on failure.
211 static int FILE_GetUnixHandleType( HANDLE handle, DWORD access, enum fd_type *type, int *flags_ptr )
213 int ret, flags, fd = -1;
215 ret = wine_server_handle_to_fd( handle, access, &fd, type, &flags );
216 if (flags_ptr) *flags_ptr = flags;
217 if (ret) SetLastError( RtlNtStatusToDosError(ret) );
218 else if (((access & GENERIC_READ) && (flags & FD_FLAG_RECV_SHUTDOWN)) ||
219 ((access & GENERIC_WRITE) && (flags & FD_FLAG_SEND_SHUTDOWN)))
221 close (fd);
222 SetLastError ( ERROR_PIPE_NOT_CONNECTED );
223 return -1;
225 return fd;
228 /***********************************************************************
229 * FILE_GetUnixHandle
231 * Retrieve the Unix handle corresponding to a file handle.
232 * Returns -1 on failure.
234 int FILE_GetUnixHandle( HANDLE handle, DWORD access )
236 return FILE_GetUnixHandleType( handle, access, NULL, NULL );
239 /******************************************************************
240 * OpenConsoleW (KERNEL32.@)
242 * Undocumented
243 * Open a handle to the current process console.
244 * Returns INVALID_HANDLE_VALUE on failure.
246 HANDLE WINAPI OpenConsoleW(LPCWSTR name, DWORD access, LPSECURITY_ATTRIBUTES sa,
247 DWORD creation)
249 static const WCHAR coninW[] = {'C','O','N','I','N','$',0};
250 static const WCHAR conoutW[] = {'C','O','N','O','U','T','$',0};
251 BOOL output;
252 HANDLE ret;
254 if (strcmpW(coninW, name) == 0)
255 output = FALSE;
256 else if (strcmpW(conoutW, name) == 0)
257 output = TRUE;
258 else
260 SetLastError(ERROR_INVALID_NAME);
261 return INVALID_HANDLE_VALUE;
263 if (creation != OPEN_EXISTING)
265 SetLastError(ERROR_INVALID_PARAMETER);
266 return INVALID_HANDLE_VALUE;
269 SERVER_START_REQ( open_console )
271 req->from = output;
272 req->access = access;
273 req->share = FILE_SHARE_READ | FILE_SHARE_WRITE;
274 req->inherit = (sa && (sa->nLength>=sizeof(*sa)) && sa->bInheritHandle);
275 SetLastError(0);
276 wine_server_call_err( req );
277 ret = reply->handle;
279 SERVER_END_REQ;
280 return ret ? console_handle_map(ret) : INVALID_HANDLE_VALUE;
283 /******************************************************************
284 * VerifyConsoleIoHandle (KERNEL32.@)
286 * Undocumented
288 BOOL WINAPI VerifyConsoleIoHandle(HANDLE handle)
290 BOOL ret;
292 if (!is_console_handle(handle)) return FALSE;
293 SERVER_START_REQ(get_console_mode)
295 req->handle = console_handle_unmap(handle);
296 ret = !wine_server_call_err( req );
298 SERVER_END_REQ;
299 return ret;
302 /******************************************************************
303 * DuplicateConsoleHandle (KERNEL32.@)
305 * Undocumented
307 HANDLE WINAPI DuplicateConsoleHandle(HANDLE handle, DWORD access, BOOL inherit,
308 DWORD options)
310 HANDLE ret;
312 if (!is_console_handle(handle) ||
313 !DuplicateHandle(GetCurrentProcess(), console_handle_unmap(handle),
314 GetCurrentProcess(), &ret, access, inherit, options))
315 return INVALID_HANDLE_VALUE;
316 return console_handle_map(ret);
319 /******************************************************************
320 * CloseConsoleHandle (KERNEL32.@)
322 * Undocumented
324 BOOL WINAPI CloseConsoleHandle(HANDLE handle)
326 if (!is_console_handle(handle))
328 SetLastError(ERROR_INVALID_PARAMETER);
329 return FALSE;
331 return CloseHandle(console_handle_unmap(handle));
334 /******************************************************************
335 * GetConsoleInputWaitHandle (KERNEL32.@)
337 * Undocumented
339 HANDLE WINAPI GetConsoleInputWaitHandle(void)
341 static HANDLE console_wait_event;
343 /* FIXME: this is not thread safe */
344 if (!console_wait_event)
346 SERVER_START_REQ(get_console_wait_event)
348 if (!wine_server_call_err( req )) console_wait_event = reply->handle;
350 SERVER_END_REQ;
352 return console_wait_event;
354 /* end of FIXME */
357 /* FIXME: those routines defined as pointers are needed, because this file is
358 * currently compiled into NTDLL whereas it belongs to kernel32.
359 * this shall go away once all the DLL separation process is done
361 typedef BOOL (WINAPI* pRW)(HANDLE, const void*, DWORD, DWORD*, void*);
363 static BOOL FILE_ReadConsole(HANDLE hCon, void* buf, DWORD nb, DWORD* nr, void* p)
365 static HANDLE hKernel /* = 0 */;
366 static pRW pReadConsole /* = 0 */;
368 if ((!hKernel && !(hKernel = LoadLibraryA("kernel32"))) ||
369 (!pReadConsole &&
370 !(pReadConsole = GetProcAddress(hKernel, "ReadConsoleA"))))
372 *nr = 0;
373 return 0;
375 return (pReadConsole)(hCon, buf, nb, nr, p);
378 static BOOL FILE_WriteConsole(HANDLE hCon, const void* buf, DWORD nb, DWORD* nr, void* p)
380 static HANDLE hKernel /* = 0 */;
381 static pRW pWriteConsole /* = 0 */;
383 if ((!hKernel && !(hKernel = LoadLibraryA("kernel32"))) ||
384 (!pWriteConsole &&
385 !(pWriteConsole = GetProcAddress(hKernel, "WriteConsoleA"))))
387 *nr = 0;
388 return 0;
390 return (pWriteConsole)(hCon, buf, nb, nr, p);
392 /* end of FIXME */
394 /***********************************************************************
395 * FILE_CreateFile
397 * Implementation of CreateFile. Takes a Unix path name.
398 * Returns 0 on failure.
400 HANDLE FILE_CreateFile( LPCSTR filename, DWORD access, DWORD sharing,
401 LPSECURITY_ATTRIBUTES sa, DWORD creation,
402 DWORD attributes, HANDLE template, BOOL fail_read_only,
403 UINT drive_type )
405 unsigned int err;
406 HANDLE ret;
408 for (;;)
410 SERVER_START_REQ( create_file )
412 req->access = access;
413 req->inherit = (sa && (sa->nLength>=sizeof(*sa)) && sa->bInheritHandle);
414 req->sharing = sharing;
415 req->create = creation;
416 req->attrs = attributes;
417 req->removable = (drive_type == DRIVE_REMOVABLE || drive_type == DRIVE_CDROM);
418 wine_server_add_data( req, filename, strlen(filename) );
419 SetLastError(0);
420 err = wine_server_call( req );
421 ret = reply->handle;
423 SERVER_END_REQ;
425 /* If write access failed, retry without GENERIC_WRITE */
427 if (!ret && !fail_read_only && (access & GENERIC_WRITE))
429 if ((err == STATUS_MEDIA_WRITE_PROTECTED) || (err == STATUS_ACCESS_DENIED))
431 TRACE("Write access failed for file '%s', trying without "
432 "write access\n", filename);
433 access &= ~GENERIC_WRITE;
434 continue;
438 if (err)
440 /* In the case file creation was rejected due to CREATE_NEW flag
441 * was specified and file with that name already exists, correct
442 * last error is ERROR_FILE_EXISTS and not ERROR_ALREADY_EXISTS.
443 * Note: RtlNtStatusToDosError is not the subject to blame here.
445 if (err == STATUS_OBJECT_NAME_COLLISION)
446 SetLastError( ERROR_FILE_EXISTS );
447 else
448 SetLastError( RtlNtStatusToDosError(err) );
451 if (!ret) WARN("Unable to create file '%s' (GLE %ld)\n", filename, GetLastError());
452 return ret;
457 /***********************************************************************
458 * FILE_CreateDevice
460 * Same as FILE_CreateFile but for a device
461 * Returns 0 on failure.
463 HANDLE FILE_CreateDevice( int client_id, DWORD access, LPSECURITY_ATTRIBUTES sa )
465 HANDLE ret;
466 SERVER_START_REQ( create_device )
468 req->access = access;
469 req->inherit = (sa && (sa->nLength>=sizeof(*sa)) && sa->bInheritHandle);
470 req->id = client_id;
471 SetLastError(0);
472 wine_server_call_err( req );
473 ret = reply->handle;
475 SERVER_END_REQ;
476 return ret;
479 static HANDLE FILE_OpenPipe(LPCWSTR name, DWORD access, LPSECURITY_ATTRIBUTES sa )
481 HANDLE ret;
482 DWORD len = 0;
484 if (name && (len = strlenW(name)) > MAX_PATH)
486 SetLastError( ERROR_FILENAME_EXCED_RANGE );
487 return 0;
489 SERVER_START_REQ( open_named_pipe )
491 req->access = access;
492 req->inherit = (sa && (sa->nLength>=sizeof(*sa)) && sa->bInheritHandle);
493 SetLastError(0);
494 wine_server_add_data( req, name, len * sizeof(WCHAR) );
495 wine_server_call_err( req );
496 ret = reply->handle;
498 SERVER_END_REQ;
499 TRACE("Returned %p\n",ret);
500 return ret;
503 /*************************************************************************
504 * CreateFileW [KERNEL32.@] Creates or opens a file or other object
506 * Creates or opens an object, and returns a handle that can be used to
507 * access that object.
509 * PARAMS
511 * filename [in] pointer to filename to be accessed
512 * access [in] access mode requested
513 * sharing [in] share mode
514 * sa [in] pointer to security attributes
515 * creation [in] how to create the file
516 * attributes [in] attributes for newly created file
517 * template [in] handle to file with extended attributes to copy
519 * RETURNS
520 * Success: Open handle to specified file
521 * Failure: INVALID_HANDLE_VALUE
523 * NOTES
524 * Should call SetLastError() on failure.
526 * BUGS
528 * Doesn't support character devices, template files, or a
529 * lot of the 'attributes' flags yet.
531 HANDLE WINAPI CreateFileW( LPCWSTR filename, DWORD access, DWORD sharing,
532 LPSECURITY_ATTRIBUTES sa, DWORD creation,
533 DWORD attributes, HANDLE template )
535 DOS_FULL_NAME full_name;
536 HANDLE ret;
537 static const WCHAR bkslashes_with_question_markW[] = {'\\','\\','?','\\',0};
538 static const WCHAR bkslashes_with_dotW[] = {'\\','\\','.','\\',0};
539 static const WCHAR bkslashesW[] = {'\\','\\',0};
540 static const WCHAR coninW[] = {'C','O','N','I','N','$',0};
541 static const WCHAR conoutW[] = {'C','O','N','O','U','T','$',0};
543 if (!filename)
545 SetLastError( ERROR_INVALID_PARAMETER );
546 return INVALID_HANDLE_VALUE;
548 TRACE("%s %s%s%s%s%s%s%s attributes 0x%lx\n", debugstr_w(filename),
549 ((access & GENERIC_READ)==GENERIC_READ)?"GENERIC_READ ":"",
550 ((access & GENERIC_WRITE)==GENERIC_WRITE)?"GENERIC_WRITE ":"",
551 (!access)?"QUERY_ACCESS ":"",
552 ((sharing & FILE_SHARE_READ)==FILE_SHARE_READ)?"FILE_SHARE_READ ":"",
553 ((sharing & FILE_SHARE_WRITE)==FILE_SHARE_WRITE)?"FILE_SHARE_WRITE ":"",
554 ((sharing & FILE_SHARE_DELETE)==FILE_SHARE_DELETE)?"FILE_SHARE_DELETE ":"",
555 (creation ==CREATE_NEW)?"CREATE_NEW":
556 (creation ==CREATE_ALWAYS)?"CREATE_ALWAYS ":
557 (creation ==OPEN_EXISTING)?"OPEN_EXISTING ":
558 (creation ==OPEN_ALWAYS)?"OPEN_ALWAYS ":
559 (creation ==TRUNCATE_EXISTING)?"TRUNCATE_EXISTING ":"", attributes);
561 /* If the name starts with '\\?\', ignore the first 4 chars. */
562 if (!strncmpW(filename, bkslashes_with_question_markW, 4))
564 static const WCHAR uncW[] = {'U','N','C','\\',0};
565 filename += 4;
566 if (!strncmpiW(filename, uncW, 4))
568 FIXME("UNC name (%s) not supported.\n", debugstr_w(filename) );
569 SetLastError( ERROR_PATH_NOT_FOUND );
570 return INVALID_HANDLE_VALUE;
574 if (!strncmpW(filename, bkslashes_with_dotW, 4))
576 static const WCHAR pipeW[] = {'P','I','P','E','\\',0};
577 if(!strncmpiW(filename + 4, pipeW, 5))
579 TRACE("Opening a pipe: %s\n", debugstr_w(filename));
580 ret = FILE_OpenPipe( filename, access, sa );
581 goto done;
583 else if (isalphaW(filename[4]) && filename[5] == ':' && filename[6] == '\0')
585 ret = FILE_CreateDevice( (toupperW(filename[4]) - 'A') | 0x20000, access, sa );
586 goto done;
588 else if (!DOSFS_GetDevice( filename ))
590 ret = DEVICE_Open( filename+4, access, sa );
591 goto done;
593 else
594 filename+=4; /* fall into DOSFS_Device case below */
597 /* If the name still starts with '\\', it's a UNC name. */
598 if (!strncmpW(filename, bkslashesW, 2))
600 ret = SMB_CreateFileW(filename, access, sharing, sa, creation, attributes, template );
601 goto done;
604 /* If the name contains a DOS wild card (* or ?), do no create a file */
605 if(strchrW(filename, '*') || strchrW(filename, '?'))
607 SetLastError(ERROR_BAD_PATHNAME);
608 return INVALID_HANDLE_VALUE;
611 /* Open a console for CONIN$ or CONOUT$ */
612 if (!strcmpiW(filename, coninW) || !strcmpiW(filename, conoutW))
614 ret = OpenConsoleW(filename, access, sa, creation);
615 goto done;
618 if (DOSFS_GetDevice( filename ))
620 TRACE("opening device %s\n", debugstr_w(filename) );
622 if (!(ret = DOSFS_OpenDevice( filename, access, attributes, sa )))
624 /* Do not silence this please. It is a critical error. -MM */
625 ERR("Couldn't open device %s!\n", debugstr_w(filename));
626 SetLastError( ERROR_FILE_NOT_FOUND );
628 goto done;
631 /* check for filename, don't check for last entry if creating */
632 if (!DOSFS_GetFullName( filename,
633 (creation == OPEN_EXISTING) ||
634 (creation == TRUNCATE_EXISTING),
635 &full_name )) {
636 WARN("Unable to get full filename from %s (GLE %ld)\n",
637 debugstr_w(filename), GetLastError());
638 return INVALID_HANDLE_VALUE;
641 ret = FILE_CreateFile( full_name.long_name, access, sharing,
642 sa, creation, attributes, template,
643 DRIVE_GetFlags(full_name.drive) & DRIVE_FAIL_READ_ONLY,
644 GetDriveTypeW( full_name.short_name ) );
645 done:
646 if (!ret) ret = INVALID_HANDLE_VALUE;
647 TRACE("returning %p\n", ret);
648 return ret;
653 /*************************************************************************
654 * CreateFileA (KERNEL32.@)
656 HANDLE WINAPI CreateFileA( LPCSTR filename, DWORD access, DWORD sharing,
657 LPSECURITY_ATTRIBUTES sa, DWORD creation,
658 DWORD attributes, HANDLE template)
660 UNICODE_STRING filenameW;
661 HANDLE ret = INVALID_HANDLE_VALUE;
663 if (!filename)
665 SetLastError( ERROR_INVALID_PARAMETER );
666 return INVALID_HANDLE_VALUE;
669 if (RtlCreateUnicodeStringFromAsciiz(&filenameW, filename))
671 ret = CreateFileW(filenameW.Buffer, access, sharing, sa, creation,
672 attributes, template);
673 RtlFreeUnicodeString(&filenameW);
675 else
676 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
677 return ret;
681 /***********************************************************************
682 * FILE_FillInfo
684 * Fill a file information from a struct stat.
686 static void FILE_FillInfo( struct stat *st, BY_HANDLE_FILE_INFORMATION *info )
688 if (S_ISDIR(st->st_mode))
689 info->dwFileAttributes = FILE_ATTRIBUTE_DIRECTORY;
690 else
691 info->dwFileAttributes = FILE_ATTRIBUTE_ARCHIVE;
692 if (!(st->st_mode & S_IWUSR))
693 info->dwFileAttributes |= FILE_ATTRIBUTE_READONLY;
695 RtlSecondsSince1970ToTime( st->st_mtime, (LARGE_INTEGER *)&info->ftCreationTime );
696 RtlSecondsSince1970ToTime( st->st_mtime, (LARGE_INTEGER *)&info->ftLastWriteTime );
697 RtlSecondsSince1970ToTime( st->st_atime, (LARGE_INTEGER *)&info->ftLastAccessTime );
699 info->dwVolumeSerialNumber = 0; /* FIXME */
700 info->nFileSizeHigh = 0;
701 info->nFileSizeLow = 0;
702 if (!S_ISDIR(st->st_mode)) {
703 info->nFileSizeHigh = st->st_size >> 32;
704 info->nFileSizeLow = st->st_size & 0xffffffff;
706 info->nNumberOfLinks = st->st_nlink;
707 info->nFileIndexHigh = 0;
708 info->nFileIndexLow = st->st_ino;
712 /***********************************************************************
713 * get_show_dot_files_option
715 static BOOL get_show_dot_files_option(void)
717 static const WCHAR WineW[] = {'M','a','c','h','i','n','e','\\',
718 'S','o','f','t','w','a','r','e','\\',
719 'W','i','n','e','\\','W','i','n','e','\\',
720 'C','o','n','f','i','g','\\','W','i','n','e',0};
721 static const WCHAR ShowDotFilesW[] = {'S','h','o','w','D','o','t','F','i','l','e','s',0};
723 char tmp[80];
724 HKEY hkey;
725 DWORD dummy;
726 OBJECT_ATTRIBUTES attr;
727 UNICODE_STRING nameW;
728 BOOL ret = FALSE;
730 attr.Length = sizeof(attr);
731 attr.RootDirectory = 0;
732 attr.ObjectName = &nameW;
733 attr.Attributes = 0;
734 attr.SecurityDescriptor = NULL;
735 attr.SecurityQualityOfService = NULL;
736 RtlInitUnicodeString( &nameW, WineW );
738 if (!NtOpenKey( &hkey, KEY_ALL_ACCESS, &attr ))
740 RtlInitUnicodeString( &nameW, ShowDotFilesW );
741 if (!NtQueryValueKey( hkey, &nameW, KeyValuePartialInformation, tmp, sizeof(tmp), &dummy ))
743 WCHAR *str = (WCHAR *)((KEY_VALUE_PARTIAL_INFORMATION *)tmp)->Data;
744 ret = IS_OPTION_TRUE( str[0] );
746 NtClose( hkey );
748 return ret;
752 /***********************************************************************
753 * FILE_Stat
755 * Stat a Unix path name. Return TRUE if OK.
757 BOOL FILE_Stat( LPCSTR unixName, BY_HANDLE_FILE_INFORMATION *info, BOOL *is_symlink_ptr )
759 struct stat st;
760 int is_symlink;
761 LPCSTR p;
763 if (lstat( unixName, &st ) == -1)
765 FILE_SetDosError();
766 return FALSE;
768 is_symlink = S_ISLNK(st.st_mode);
769 if (is_symlink)
771 /* do a "real" stat to find out
772 about the type of the symlink destination */
773 if (stat( unixName, &st ) == -1)
775 FILE_SetDosError();
776 return FALSE;
780 /* fill in the information we gathered so far */
781 FILE_FillInfo( &st, info );
783 /* and now see if this is a hidden file, based on the name */
784 p = strrchr( unixName, '/');
785 p = p ? p + 1 : unixName;
786 if (*p == '.' && *(p+1) && (*(p+1) != '.' || *(p+2)))
788 static int show_dot_files = -1;
789 if (show_dot_files == -1)
790 show_dot_files = get_show_dot_files_option();
791 if (!show_dot_files)
792 info->dwFileAttributes |= FILE_ATTRIBUTE_HIDDEN;
794 if (is_symlink_ptr) *is_symlink_ptr = is_symlink;
795 return TRUE;
799 /***********************************************************************
800 * GetFileInformationByHandle (KERNEL32.@)
802 DWORD WINAPI GetFileInformationByHandle( HANDLE hFile,
803 BY_HANDLE_FILE_INFORMATION *info )
805 DWORD ret;
806 if (!info) return 0;
808 TRACE("%p\n", hFile);
810 SERVER_START_REQ( get_file_info )
812 req->handle = hFile;
813 if ((ret = !wine_server_call_err( req )))
815 /* FIXME: which file types are supported ?
816 * Serial ports (FILE_TYPE_CHAR) are not,
817 * and MSDN also says that pipes are not supported.
818 * FILE_TYPE_REMOTE seems to be supported according to
819 * MSDN q234741.txt */
820 if ((reply->type == FILE_TYPE_DISK) || (reply->type == FILE_TYPE_REMOTE))
822 RtlSecondsSince1970ToTime( reply->write_time, (LARGE_INTEGER *)&info->ftCreationTime );
823 RtlSecondsSince1970ToTime( reply->write_time, (LARGE_INTEGER *)&info->ftLastWriteTime );
824 RtlSecondsSince1970ToTime( reply->access_time, (LARGE_INTEGER *)&info->ftLastAccessTime );
825 info->dwFileAttributes = reply->attr;
826 info->dwVolumeSerialNumber = reply->serial;
827 info->nFileSizeHigh = reply->size_high;
828 info->nFileSizeLow = reply->size_low;
829 info->nNumberOfLinks = reply->links;
830 info->nFileIndexHigh = reply->index_high;
831 info->nFileIndexLow = reply->index_low;
833 else
835 SetLastError(ERROR_NOT_SUPPORTED);
836 ret = 0;
840 SERVER_END_REQ;
841 return ret;
845 /**************************************************************************
846 * GetFileAttributesW (KERNEL32.@)
848 DWORD WINAPI GetFileAttributesW( LPCWSTR name )
850 DOS_FULL_NAME full_name;
851 BY_HANDLE_FILE_INFORMATION info;
853 if (name == NULL)
855 SetLastError( ERROR_INVALID_PARAMETER );
856 return INVALID_FILE_ATTRIBUTES;
858 if (!DOSFS_GetFullName( name, TRUE, &full_name) )
859 return INVALID_FILE_ATTRIBUTES;
860 if (!FILE_Stat( full_name.long_name, &info, NULL ))
861 return INVALID_FILE_ATTRIBUTES;
862 return info.dwFileAttributes;
866 /**************************************************************************
867 * GetFileAttributesA (KERNEL32.@)
869 DWORD WINAPI GetFileAttributesA( LPCSTR name )
871 UNICODE_STRING nameW;
872 DWORD ret = INVALID_FILE_ATTRIBUTES;
874 if (!name)
876 SetLastError( ERROR_INVALID_PARAMETER );
877 return INVALID_FILE_ATTRIBUTES;
880 if (RtlCreateUnicodeStringFromAsciiz(&nameW, name))
882 ret = GetFileAttributesW(nameW.Buffer);
883 RtlFreeUnicodeString(&nameW);
885 else
886 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
887 return ret;
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 * GetCompressedFileSizeA [KERNEL32.@]
992 DWORD WINAPI GetCompressedFileSizeA(
993 LPCSTR lpFileName,
994 LPDWORD lpFileSizeHigh)
996 UNICODE_STRING filenameW;
997 DWORD ret;
999 if (RtlCreateUnicodeStringFromAsciiz(&filenameW, lpFileName))
1001 ret = GetCompressedFileSizeW(filenameW.Buffer, lpFileSizeHigh);
1002 RtlFreeUnicodeString(&filenameW);
1004 else
1006 ret = INVALID_FILE_SIZE;
1007 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1009 return ret;
1013 /******************************************************************************
1014 * GetCompressedFileSizeW [KERNEL32.@]
1016 * RETURNS
1017 * Success: Low-order doubleword of number of bytes
1018 * Failure: INVALID_FILE_SIZE
1020 DWORD WINAPI GetCompressedFileSizeW(
1021 LPCWSTR lpFileName, /* [in] Pointer to name of file */
1022 LPDWORD lpFileSizeHigh) /* [out] Receives high-order doubleword of size */
1024 DOS_FULL_NAME full_name;
1025 struct stat st;
1026 DWORD low;
1028 TRACE("(%s,%p)\n",debugstr_w(lpFileName),lpFileSizeHigh);
1030 if (!DOSFS_GetFullName( lpFileName, TRUE, &full_name )) return INVALID_FILE_SIZE;
1031 if (stat(full_name.long_name, &st) != 0)
1033 FILE_SetDosError();
1034 return INVALID_FILE_SIZE;
1036 #if HAVE_STRUCT_STAT_ST_BLOCKS
1037 /* blocks are 512 bytes long */
1038 if (lpFileSizeHigh) *lpFileSizeHigh = (st.st_blocks >> 23);
1039 low = (DWORD)(st.st_blocks << 9);
1040 #else
1041 if (lpFileSizeHigh) *lpFileSizeHigh = (st.st_size >> 32);
1042 low = (DWORD)st.st_size;
1043 #endif
1044 return low;
1048 /***********************************************************************
1049 * GetFileTime (KERNEL32.@)
1051 BOOL WINAPI GetFileTime( HANDLE hFile, FILETIME *lpCreationTime,
1052 FILETIME *lpLastAccessTime,
1053 FILETIME *lpLastWriteTime )
1055 BY_HANDLE_FILE_INFORMATION info;
1056 if (!GetFileInformationByHandle( hFile, &info )) return FALSE;
1057 if (lpCreationTime) *lpCreationTime = info.ftCreationTime;
1058 if (lpLastAccessTime) *lpLastAccessTime = info.ftLastAccessTime;
1059 if (lpLastWriteTime) *lpLastWriteTime = info.ftLastWriteTime;
1060 return TRUE;
1064 /***********************************************************************
1065 * GetTempFileNameA (KERNEL32.@)
1067 UINT WINAPI GetTempFileNameA( LPCSTR path, LPCSTR prefix, UINT unique,
1068 LPSTR buffer)
1070 UNICODE_STRING pathW, prefixW;
1071 WCHAR bufferW[MAX_PATH];
1072 UINT ret;
1074 if ( !path || !prefix || !buffer )
1076 SetLastError( ERROR_INVALID_PARAMETER );
1077 return 0;
1080 RtlCreateUnicodeStringFromAsciiz(&pathW, path);
1081 RtlCreateUnicodeStringFromAsciiz(&prefixW, prefix);
1083 ret = GetTempFileNameW(pathW.Buffer, prefixW.Buffer, unique, bufferW);
1084 if (ret)
1085 WideCharToMultiByte(CP_ACP, 0, bufferW, -1, buffer, MAX_PATH, NULL, NULL);
1087 RtlFreeUnicodeString(&pathW);
1088 RtlFreeUnicodeString(&prefixW);
1089 return ret;
1092 /***********************************************************************
1093 * GetTempFileNameW (KERNEL32.@)
1095 UINT WINAPI GetTempFileNameW( LPCWSTR path, LPCWSTR prefix, UINT unique,
1096 LPWSTR buffer )
1098 static const WCHAR formatW[] = {'%','0','4','x','.','t','m','p',0};
1100 DOS_FULL_NAME full_name;
1101 int i;
1102 LPWSTR p;
1104 if ( !path || !prefix || !buffer )
1106 SetLastError( ERROR_INVALID_PARAMETER );
1107 return 0;
1110 strcpyW( buffer, path );
1111 p = buffer + strlenW(buffer);
1113 /* add a \, if there isn't one and path is more than just the drive letter ... */
1114 if ( !((strlenW(buffer) == 2) && (buffer[1] == ':'))
1115 && ((p == buffer) || (p[-1] != '\\'))) *p++ = '\\';
1117 for (i = 3; (i > 0) && (*prefix); i--) *p++ = *prefix++;
1119 unique &= 0xffff;
1121 if (unique) sprintfW( p, formatW, unique );
1122 else
1124 /* get a "random" unique number and try to create the file */
1125 HANDLE handle;
1126 UINT num = GetTickCount() & 0xffff;
1128 if (!num) num = 1;
1129 unique = num;
1132 sprintfW( p, formatW, unique );
1133 handle = CreateFileW( buffer, GENERIC_WRITE, 0, NULL,
1134 CREATE_NEW, FILE_ATTRIBUTE_NORMAL, 0 );
1135 if (handle != INVALID_HANDLE_VALUE)
1136 { /* We created it */
1137 TRACE("created %s\n", debugstr_w(buffer) );
1138 CloseHandle( handle );
1139 break;
1141 if (GetLastError() != ERROR_FILE_EXISTS &&
1142 GetLastError() != ERROR_SHARING_VIOLATION)
1143 break; /* No need to go on */
1144 if (!(++unique & 0xffff)) unique = 1;
1145 } while (unique != num);
1148 /* Get the full path name */
1150 if (DOSFS_GetFullName( buffer, FALSE, &full_name ))
1152 char *slash;
1153 /* Check if we have write access in the directory */
1154 if ((slash = strrchr( full_name.long_name, '/' ))) *slash = '\0';
1155 if (access( full_name.long_name, W_OK ) == -1)
1156 WARN("returns %s, which doesn't seem to be writeable.\n",
1157 debugstr_w(buffer) );
1159 TRACE("returning %s\n", debugstr_w(buffer) );
1160 return unique;
1164 /***********************************************************************
1165 * FILE_DoOpenFile
1167 * Implementation of OpenFile16() and OpenFile32().
1169 static HFILE FILE_DoOpenFile( LPCSTR name, OFSTRUCT *ofs, UINT mode, BOOL win32 )
1171 HFILE hFileRet;
1172 HANDLE handle;
1173 FILETIME filetime;
1174 WORD filedatetime[2];
1175 DOS_FULL_NAME full_name;
1176 DWORD access, sharing;
1177 WCHAR *p;
1178 WCHAR buffer[MAX_PATH];
1179 LPWSTR nameW;
1181 if (!ofs) return HFILE_ERROR;
1183 TRACE("%s %s %s %s%s%s%s%s%s%s%s%s\n",name,
1184 ((mode & 0x3 )==OF_READ)?"OF_READ":
1185 ((mode & 0x3 )==OF_WRITE)?"OF_WRITE":
1186 ((mode & 0x3 )==OF_READWRITE)?"OF_READWRITE":"unknown",
1187 ((mode & 0x70 )==OF_SHARE_COMPAT)?"OF_SHARE_COMPAT":
1188 ((mode & 0x70 )==OF_SHARE_DENY_NONE)?"OF_SHARE_DENY_NONE":
1189 ((mode & 0x70 )==OF_SHARE_DENY_READ)?"OF_SHARE_DENY_READ":
1190 ((mode & 0x70 )==OF_SHARE_DENY_WRITE)?"OF_SHARE_DENY_WRITE":
1191 ((mode & 0x70 )==OF_SHARE_EXCLUSIVE)?"OF_SHARE_EXCLUSIVE":"unknown",
1192 ((mode & OF_PARSE )==OF_PARSE)?"OF_PARSE ":"",
1193 ((mode & OF_DELETE )==OF_DELETE)?"OF_DELETE ":"",
1194 ((mode & OF_VERIFY )==OF_VERIFY)?"OF_VERIFY ":"",
1195 ((mode & OF_SEARCH )==OF_SEARCH)?"OF_SEARCH ":"",
1196 ((mode & OF_CANCEL )==OF_CANCEL)?"OF_CANCEL ":"",
1197 ((mode & OF_CREATE )==OF_CREATE)?"OF_CREATE ":"",
1198 ((mode & OF_PROMPT )==OF_PROMPT)?"OF_PROMPT ":"",
1199 ((mode & OF_EXIST )==OF_EXIST)?"OF_EXIST ":"",
1200 ((mode & OF_REOPEN )==OF_REOPEN)?"OF_REOPEN ":""
1204 ofs->cBytes = sizeof(OFSTRUCT);
1205 ofs->nErrCode = 0;
1206 if (mode & OF_REOPEN) name = ofs->szPathName;
1208 if (!name) {
1209 ERR("called with `name' set to NULL ! Please debug.\n");
1210 return HFILE_ERROR;
1213 TRACE("%s %04x\n", name, mode );
1215 /* the watcom 10.6 IDE relies on a valid path returned in ofs->szPathName
1216 Are there any cases where getting the path here is wrong?
1217 Uwe Bonnes 1997 Apr 2 */
1218 if (!GetFullPathNameA( name, sizeof(ofs->szPathName),
1219 ofs->szPathName, NULL )) goto error;
1220 FILE_ConvertOFMode( mode, &access, &sharing );
1222 /* OF_PARSE simply fills the structure */
1224 if (mode & OF_PARSE)
1226 ofs->fFixedDisk = (GetDriveType16( ofs->szPathName[0]-'A' )
1227 != DRIVE_REMOVABLE);
1228 TRACE("(%s): OF_PARSE, res = '%s'\n",
1229 name, ofs->szPathName );
1230 return 0;
1233 /* OF_CREATE is completely different from all other options, so
1234 handle it first */
1236 if (mode & OF_CREATE)
1238 if ((handle = CreateFileA( name, GENERIC_READ | GENERIC_WRITE,
1239 sharing, NULL, CREATE_ALWAYS,
1240 FILE_ATTRIBUTE_NORMAL, 0 ))== INVALID_HANDLE_VALUE)
1241 goto error;
1242 goto success;
1245 MultiByteToWideChar(CP_ACP, 0, name, -1, buffer, MAX_PATH);
1246 nameW = buffer;
1248 /* If OF_SEARCH is set, ignore the given path */
1250 if ((mode & OF_SEARCH) && !(mode & OF_REOPEN))
1252 /* First try the file name as is */
1253 if (DOSFS_GetFullName( nameW, TRUE, &full_name )) goto found;
1254 /* Now remove the path */
1255 if (nameW[0] && (nameW[1] == ':')) nameW += 2;
1256 if ((p = strrchrW( nameW, '\\' ))) nameW = p + 1;
1257 if ((p = strrchrW( nameW, '/' ))) nameW = p + 1;
1258 if (!nameW[0]) goto not_found;
1261 /* Now look for the file */
1263 if (!DIR_SearchPath( NULL, nameW, NULL, &full_name, win32 )) goto not_found;
1265 found:
1266 TRACE("found %s = %s\n",
1267 full_name.long_name, debugstr_w(full_name.short_name) );
1268 WideCharToMultiByte(CP_ACP, 0, full_name.short_name, -1,
1269 ofs->szPathName, sizeof(ofs->szPathName), NULL, NULL);
1271 if (mode & OF_DELETE)
1273 handle = FILE_CreateFile( full_name.long_name, GENERIC_READ|GENERIC_WRITE, 0,
1274 NULL, OPEN_EXISTING, 0, 0, TRUE,
1275 GetDriveTypeW( full_name.short_name ) );
1276 if (!handle) goto error;
1277 CloseHandle( handle );
1278 if (unlink( full_name.long_name ) == -1) goto not_found;
1279 TRACE("(%s): OF_DELETE return = OK\n", name);
1280 return 1;
1283 handle = FILE_CreateFile( full_name.long_name, access, sharing,
1284 NULL, OPEN_EXISTING, 0, 0,
1285 DRIVE_GetFlags(full_name.drive) & DRIVE_FAIL_READ_ONLY,
1286 GetDriveTypeW( full_name.short_name ) );
1287 if (!handle) goto not_found;
1289 GetFileTime( handle, NULL, NULL, &filetime );
1290 FileTimeToDosDateTime( &filetime, &filedatetime[0], &filedatetime[1] );
1291 if ((mode & OF_VERIFY) && (mode & OF_REOPEN))
1293 if (ofs->Reserved1 != filedatetime[0] || ofs->Reserved2 != filedatetime[1] )
1295 CloseHandle( handle );
1296 WARN("(%s): OF_VERIFY failed\n", name );
1297 /* FIXME: what error here? */
1298 SetLastError( ERROR_FILE_NOT_FOUND );
1299 goto error;
1302 ofs->Reserved1 = filedatetime[0];
1303 ofs->Reserved2 = filedatetime[1];
1305 success: /* We get here if the open was successful */
1306 TRACE("(%s): OK, return = %p\n", name, handle );
1307 if (win32)
1309 hFileRet = (HFILE)handle;
1310 if (mode & OF_EXIST) /* Return the handle, but close it first */
1311 CloseHandle( handle );
1313 else
1315 hFileRet = Win32HandleToDosFileHandle( handle );
1316 if (hFileRet == HFILE_ERROR16) goto error;
1317 if (mode & OF_EXIST) /* Return the handle, but close it first */
1318 _lclose16( hFileRet );
1320 return hFileRet;
1322 not_found: /* We get here if the file does not exist */
1323 WARN("'%s' not found or sharing violation\n", name );
1324 SetLastError( ERROR_FILE_NOT_FOUND );
1325 /* fall through */
1327 error: /* We get here if there was an error opening the file */
1328 ofs->nErrCode = GetLastError();
1329 WARN("(%s): return = HFILE_ERROR error= %d\n",
1330 name,ofs->nErrCode );
1331 return HFILE_ERROR;
1335 /***********************************************************************
1336 * OpenFile (KERNEL.74)
1337 * OpenFileEx (KERNEL.360)
1339 HFILE16 WINAPI OpenFile16( LPCSTR name, OFSTRUCT *ofs, UINT16 mode )
1341 return FILE_DoOpenFile( name, ofs, mode, FALSE );
1345 /***********************************************************************
1346 * OpenFile (KERNEL32.@)
1348 HFILE WINAPI OpenFile( LPCSTR name, OFSTRUCT *ofs, UINT mode )
1350 return FILE_DoOpenFile( name, ofs, mode, TRUE );
1354 /***********************************************************************
1355 * FILE_InitProcessDosHandles
1357 * Allocates the default DOS handles for a process. Called either by
1358 * Win32HandleToDosFileHandle below or by the DOSVM stuff.
1360 static void FILE_InitProcessDosHandles( void )
1362 HANDLE cp = GetCurrentProcess();
1363 DuplicateHandle(cp, GetStdHandle(STD_INPUT_HANDLE), cp, &dos_handles[0],
1364 0, TRUE, DUPLICATE_SAME_ACCESS);
1365 DuplicateHandle(cp, GetStdHandle(STD_OUTPUT_HANDLE), cp, &dos_handles[1],
1366 0, TRUE, DUPLICATE_SAME_ACCESS);
1367 DuplicateHandle(cp, GetStdHandle(STD_ERROR_HANDLE), cp, &dos_handles[2],
1368 0, TRUE, DUPLICATE_SAME_ACCESS);
1369 DuplicateHandle(cp, GetStdHandle(STD_ERROR_HANDLE), cp, &dos_handles[3],
1370 0, TRUE, DUPLICATE_SAME_ACCESS);
1371 DuplicateHandle(cp, GetStdHandle(STD_ERROR_HANDLE), cp, &dos_handles[4],
1372 0, TRUE, DUPLICATE_SAME_ACCESS);
1375 /***********************************************************************
1376 * Win32HandleToDosFileHandle (KERNEL32.21)
1378 * Allocate a DOS handle for a Win32 handle. The Win32 handle is no
1379 * longer valid after this function (even on failure).
1381 * Note: this is not exactly right, since on Win95 the Win32 handles
1382 * are on top of DOS handles and we do it the other way
1383 * around. Should be good enough though.
1385 HFILE WINAPI Win32HandleToDosFileHandle( HANDLE handle )
1387 int i;
1389 if (!handle || (handle == INVALID_HANDLE_VALUE))
1390 return HFILE_ERROR;
1392 for (i = 5; i < DOS_TABLE_SIZE; i++)
1393 if (!dos_handles[i])
1395 dos_handles[i] = handle;
1396 TRACE("Got %d for h32 %p\n", i, handle );
1397 return (HFILE)i;
1399 CloseHandle( handle );
1400 SetLastError( ERROR_TOO_MANY_OPEN_FILES );
1401 return HFILE_ERROR;
1405 /***********************************************************************
1406 * DosFileHandleToWin32Handle (KERNEL32.20)
1408 * Return the Win32 handle for a DOS handle.
1410 * Note: this is not exactly right, since on Win95 the Win32 handles
1411 * are on top of DOS handles and we do it the other way
1412 * around. Should be good enough though.
1414 HANDLE WINAPI DosFileHandleToWin32Handle( HFILE handle )
1416 HFILE16 hfile = (HFILE16)handle;
1417 if (hfile < 5 && !dos_handles[hfile]) FILE_InitProcessDosHandles();
1418 if ((hfile >= DOS_TABLE_SIZE) || !dos_handles[hfile])
1420 SetLastError( ERROR_INVALID_HANDLE );
1421 return INVALID_HANDLE_VALUE;
1423 return dos_handles[hfile];
1427 /***********************************************************************
1428 * DisposeLZ32Handle (KERNEL32.22)
1430 * Note: this is not entirely correct, we should only close the
1431 * 32-bit handle and not the 16-bit one, but we cannot do
1432 * this because of the way our DOS handles are implemented.
1433 * It shouldn't break anything though.
1435 void WINAPI DisposeLZ32Handle( HANDLE handle )
1437 int i;
1439 if (!handle || (handle == INVALID_HANDLE_VALUE)) return;
1441 for (i = 5; i < DOS_TABLE_SIZE; i++)
1442 if (dos_handles[i] == handle)
1444 dos_handles[i] = 0;
1445 CloseHandle( handle );
1446 break;
1451 /***********************************************************************
1452 * FILE_Dup2
1454 * dup2() function for DOS handles.
1456 HFILE16 FILE_Dup2( HFILE16 hFile1, HFILE16 hFile2 )
1458 HANDLE new_handle;
1460 if (hFile1 < 5 && !dos_handles[hFile1]) FILE_InitProcessDosHandles();
1462 if ((hFile1 >= DOS_TABLE_SIZE) || (hFile2 >= DOS_TABLE_SIZE) || !dos_handles[hFile1])
1464 SetLastError( ERROR_INVALID_HANDLE );
1465 return HFILE_ERROR16;
1467 if (!DuplicateHandle( GetCurrentProcess(), dos_handles[hFile1],
1468 GetCurrentProcess(), &new_handle,
1469 0, FALSE, DUPLICATE_SAME_ACCESS ))
1470 return HFILE_ERROR16;
1471 if (dos_handles[hFile2]) CloseHandle( dos_handles[hFile2] );
1472 dos_handles[hFile2] = new_handle;
1473 return hFile2;
1477 /***********************************************************************
1478 * _lclose (KERNEL.81)
1480 HFILE16 WINAPI _lclose16( HFILE16 hFile )
1482 if ((hFile >= DOS_TABLE_SIZE) || !dos_handles[hFile])
1484 SetLastError( ERROR_INVALID_HANDLE );
1485 return HFILE_ERROR16;
1487 TRACE("%d (handle32=%p)\n", hFile, dos_handles[hFile] );
1488 CloseHandle( dos_handles[hFile] );
1489 dos_handles[hFile] = 0;
1490 return 0;
1494 /******************************************************************
1495 * FILE_ReadWriteApc (internal)
1499 static void WINAPI FILE_ReadWriteApc(void* apc_user, PIO_STATUS_BLOCK io_status, ULONG len)
1501 LPOVERLAPPED_COMPLETION_ROUTINE cr = (LPOVERLAPPED_COMPLETION_ROUTINE)apc_user;
1503 cr(RtlNtStatusToDosError(io_status->u.Status), len, (LPOVERLAPPED)io_status);
1506 /***********************************************************************
1507 * ReadFileEx (KERNEL32.@)
1509 BOOL WINAPI ReadFileEx(HANDLE hFile, LPVOID buffer, DWORD bytesToRead,
1510 LPOVERLAPPED overlapped,
1511 LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine)
1513 LARGE_INTEGER offset;
1514 NTSTATUS status;
1515 PIO_STATUS_BLOCK io_status;
1517 if (!overlapped)
1519 SetLastError(ERROR_INVALID_PARAMETER);
1520 return FALSE;
1523 offset.s.LowPart = overlapped->Offset;
1524 offset.s.HighPart = overlapped->OffsetHigh;
1525 io_status = (PIO_STATUS_BLOCK)overlapped;
1526 io_status->u.Status = STATUS_PENDING;
1528 status = NtReadFile(hFile, NULL, FILE_ReadWriteApc, lpCompletionRoutine,
1529 io_status, buffer, bytesToRead, &offset, NULL);
1531 if (status)
1533 SetLastError( RtlNtStatusToDosError(status) );
1534 return FALSE;
1536 return TRUE;
1539 /***********************************************************************
1540 * ReadFile (KERNEL32.@)
1542 BOOL WINAPI ReadFile( HANDLE hFile, LPVOID buffer, DWORD bytesToRead,
1543 LPDWORD bytesRead, LPOVERLAPPED overlapped )
1545 LARGE_INTEGER offset;
1546 PLARGE_INTEGER poffset = NULL;
1547 IO_STATUS_BLOCK iosb;
1548 PIO_STATUS_BLOCK io_status = &iosb;
1549 HANDLE hEvent = 0;
1550 NTSTATUS status;
1552 TRACE("%p %p %ld %p %p\n", hFile, buffer, bytesToRead,
1553 bytesRead, overlapped );
1555 if (bytesRead) *bytesRead = 0; /* Do this before anything else */
1556 if (!bytesToRead) return TRUE;
1558 if (IsBadReadPtr(buffer, bytesToRead))
1560 SetLastError(ERROR_WRITE_FAULT); /* FIXME */
1561 return FALSE;
1563 if (is_console_handle(hFile))
1564 return FILE_ReadConsole(hFile, buffer, bytesToRead, bytesRead, NULL);
1566 if (overlapped != NULL)
1568 offset.s.LowPart = overlapped->Offset;
1569 offset.s.HighPart = overlapped->OffsetHigh;
1570 poffset = &offset;
1571 hEvent = overlapped->hEvent;
1572 io_status = (PIO_STATUS_BLOCK)overlapped;
1574 io_status->u.Status = STATUS_PENDING;
1575 io_status->Information = 0;
1577 status = NtReadFile(hFile, hEvent, NULL, NULL, io_status, buffer, bytesToRead, poffset, NULL);
1579 if (status != STATUS_PENDING && bytesRead)
1580 *bytesRead = io_status->Information;
1582 if (status && status != STATUS_END_OF_FILE)
1584 SetLastError( RtlNtStatusToDosError(status) );
1585 return FALSE;
1587 return TRUE;
1591 /***********************************************************************
1592 * WriteFileEx (KERNEL32.@)
1594 BOOL WINAPI WriteFileEx(HANDLE hFile, LPCVOID buffer, DWORD bytesToWrite,
1595 LPOVERLAPPED overlapped,
1596 LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine)
1598 LARGE_INTEGER offset;
1599 NTSTATUS status;
1600 PIO_STATUS_BLOCK io_status;
1602 TRACE("%p %p %ld %p %p\n",
1603 hFile, buffer, bytesToWrite, overlapped, lpCompletionRoutine);
1605 if (overlapped == NULL)
1607 SetLastError(ERROR_INVALID_PARAMETER);
1608 return FALSE;
1610 offset.s.LowPart = overlapped->Offset;
1611 offset.s.HighPart = overlapped->OffsetHigh;
1613 io_status = (PIO_STATUS_BLOCK)overlapped;
1614 io_status->u.Status = STATUS_PENDING;
1616 status = NtWriteFile(hFile, NULL, FILE_ReadWriteApc, lpCompletionRoutine,
1617 io_status, buffer, bytesToWrite, &offset, NULL);
1619 if (status) SetLastError( RtlNtStatusToDosError(status) );
1620 return !status;
1623 /***********************************************************************
1624 * WriteFile (KERNEL32.@)
1626 BOOL WINAPI WriteFile( HANDLE hFile, LPCVOID buffer, DWORD bytesToWrite,
1627 LPDWORD bytesWritten, LPOVERLAPPED overlapped )
1629 HANDLE hEvent = NULL;
1630 LARGE_INTEGER offset;
1631 PLARGE_INTEGER poffset = NULL;
1632 NTSTATUS status;
1633 IO_STATUS_BLOCK iosb;
1634 PIO_STATUS_BLOCK piosb = &iosb;
1636 TRACE("%p %p %ld %p %p\n",
1637 hFile, buffer, bytesToWrite, bytesWritten, overlapped );
1639 if (is_console_handle(hFile))
1640 return FILE_WriteConsole(hFile, buffer, bytesToWrite, bytesWritten, NULL);
1642 if (IsBadReadPtr(buffer, bytesToWrite))
1644 SetLastError(ERROR_READ_FAULT); /* FIXME */
1645 return FALSE;
1648 if (overlapped)
1650 offset.s.LowPart = overlapped->Offset;
1651 offset.s.HighPart = overlapped->OffsetHigh;
1652 poffset = &offset;
1653 hEvent = overlapped->hEvent;
1654 piosb = (PIO_STATUS_BLOCK)overlapped;
1656 piosb->u.Status = STATUS_PENDING;
1657 piosb->Information = 0;
1659 status = NtWriteFile(hFile, hEvent, NULL, NULL, piosb,
1660 buffer, bytesToWrite, poffset, NULL);
1661 if (status)
1663 SetLastError( RtlNtStatusToDosError(status) );
1664 return FALSE;
1666 if (bytesWritten) *bytesWritten = piosb->Information;
1668 return TRUE;
1672 /***********************************************************************
1673 * SetFilePointer (KERNEL32.@)
1675 DWORD WINAPI SetFilePointer( HANDLE hFile, LONG distance, LONG *highword,
1676 DWORD method )
1678 DWORD ret = INVALID_SET_FILE_POINTER;
1680 TRACE("handle %p offset %ld high %ld origin %ld\n",
1681 hFile, distance, highword?*highword:0, method );
1683 SERVER_START_REQ( set_file_pointer )
1685 req->handle = hFile;
1686 req->low = distance;
1687 req->high = highword ? *highword : (distance >= 0) ? 0 : -1;
1688 /* FIXME: assumes 1:1 mapping between Windows and Unix seek constants */
1689 req->whence = method;
1690 SetLastError( 0 );
1691 if (!wine_server_call_err( req ))
1693 ret = reply->new_low;
1694 if (highword) *highword = reply->new_high;
1697 SERVER_END_REQ;
1698 return ret;
1702 /*************************************************************************
1703 * SetHandleCount (KERNEL32.@)
1705 UINT WINAPI SetHandleCount( UINT count )
1707 return min( 256, count );
1711 /**************************************************************************
1712 * SetEndOfFile (KERNEL32.@)
1714 BOOL WINAPI SetEndOfFile( HANDLE hFile )
1716 BOOL ret;
1717 SERVER_START_REQ( truncate_file )
1719 req->handle = hFile;
1720 ret = !wine_server_call_err( req );
1722 SERVER_END_REQ;
1723 return ret;
1727 /***********************************************************************
1728 * DeleteFileW (KERNEL32.@)
1730 BOOL WINAPI DeleteFileW( LPCWSTR path )
1732 DOS_FULL_NAME full_name;
1733 HANDLE hFile;
1735 TRACE("%s\n", debugstr_w(path) );
1736 if (!path || !*path)
1738 SetLastError(ERROR_PATH_NOT_FOUND);
1739 return FALSE;
1741 if (DOSFS_GetDevice( path ))
1743 WARN("cannot remove DOS device %s!\n", debugstr_w(path));
1744 SetLastError( ERROR_FILE_NOT_FOUND );
1745 return FALSE;
1748 if (!DOSFS_GetFullName( path, TRUE, &full_name )) return FALSE;
1750 /* check if we are allowed to delete the source */
1751 hFile = FILE_CreateFile( full_name.long_name, GENERIC_READ|GENERIC_WRITE, 0,
1752 NULL, OPEN_EXISTING, 0, 0, TRUE,
1753 GetDriveTypeW( full_name.short_name ) );
1754 if (!hFile) return FALSE;
1756 if (unlink( full_name.long_name ) == -1)
1758 FILE_SetDosError();
1759 CloseHandle(hFile);
1760 return FALSE;
1762 CloseHandle(hFile);
1763 return TRUE;
1767 /***********************************************************************
1768 * DeleteFileA (KERNEL32.@)
1770 BOOL WINAPI DeleteFileA( LPCSTR path )
1772 UNICODE_STRING pathW;
1773 BOOL ret = FALSE;
1775 if (!path)
1777 SetLastError(ERROR_INVALID_PARAMETER);
1778 return FALSE;
1781 if (RtlCreateUnicodeStringFromAsciiz(&pathW, path))
1783 ret = DeleteFileW(pathW.Buffer);
1784 RtlFreeUnicodeString(&pathW);
1786 else
1787 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1788 return ret;
1792 /***********************************************************************
1793 * GetFileType (KERNEL32.@)
1795 DWORD WINAPI GetFileType( HANDLE hFile )
1797 DWORD ret = FILE_TYPE_UNKNOWN;
1799 if (is_console_handle( hFile ))
1800 return FILE_TYPE_CHAR;
1802 SERVER_START_REQ( get_file_info )
1804 req->handle = hFile;
1805 if (!wine_server_call_err( req )) ret = reply->type;
1807 SERVER_END_REQ;
1808 return ret;
1812 /* check if a file name is for an executable file (.exe or .com) */
1813 inline static BOOL is_executable( const char *name )
1815 int len = strlen(name);
1817 if (len < 4) return FALSE;
1818 return (!strcasecmp( name + len - 4, ".exe" ) ||
1819 !strcasecmp( name + len - 4, ".com" ));
1823 /***********************************************************************
1824 * FILE_AddBootRenameEntry
1826 * Adds an entry to the registry that is loaded when windows boots and
1827 * checks if there are some files to be removed or renamed/moved.
1828 * <fn1> has to be valid and <fn2> may be NULL. If both pointers are
1829 * non-NULL then the file is moved, otherwise it is deleted. The
1830 * entry of the registrykey is always appended with two zero
1831 * terminated strings. If <fn2> is NULL then the second entry is
1832 * simply a single 0-byte. Otherwise the second filename goes
1833 * there. The entries are prepended with \??\ before the path and the
1834 * second filename gets also a '!' as the first character if
1835 * MOVEFILE_REPLACE_EXISTING is set. After the final string another
1836 * 0-byte follows to indicate the end of the strings.
1837 * i.e.:
1838 * \??\D:\test\file1[0]
1839 * !\??\D:\test\file1_renamed[0]
1840 * \??\D:\Test|delete[0]
1841 * [0] <- file is to be deleted, second string empty
1842 * \??\D:\test\file2[0]
1843 * !\??\D:\test\file2_renamed[0]
1844 * [0] <- indicates end of strings
1846 * or:
1847 * \??\D:\test\file1[0]
1848 * !\??\D:\test\file1_renamed[0]
1849 * \??\D:\Test|delete[0]
1850 * [0] <- file is to be deleted, second string empty
1851 * [0] <- indicates end of strings
1854 static BOOL FILE_AddBootRenameEntry( LPCWSTR fn1, LPCWSTR fn2, DWORD flags )
1856 static const WCHAR PreString[] = {'\\','?','?','\\',0};
1857 static const WCHAR ValueName[] = {'P','e','n','d','i','n','g',
1858 'F','i','l','e','R','e','n','a','m','e',
1859 'O','p','e','r','a','t','i','o','n','s',0};
1860 static const WCHAR SessionW[] = {'M','a','c','h','i','n','e','\\',
1861 'S','y','s','t','e','m','\\',
1862 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
1863 'C','o','n','t','r','o','l','\\',
1864 'S','e','s','s','i','o','n',' ','M','a','n','a','g','e','r',0};
1865 static const int info_size = FIELD_OFFSET( KEY_VALUE_PARTIAL_INFORMATION, Data );
1867 OBJECT_ATTRIBUTES attr;
1868 UNICODE_STRING nameW;
1869 KEY_VALUE_PARTIAL_INFORMATION *info;
1870 BOOL rc = FALSE;
1871 HKEY Reboot = 0;
1872 DWORD len0, len1, len2;
1873 DWORD DataSize = 0;
1874 BYTE *Buffer = NULL;
1875 WCHAR *p;
1877 attr.Length = sizeof(attr);
1878 attr.RootDirectory = 0;
1879 attr.ObjectName = &nameW;
1880 attr.Attributes = 0;
1881 attr.SecurityDescriptor = NULL;
1882 attr.SecurityQualityOfService = NULL;
1883 RtlInitUnicodeString( &nameW, SessionW );
1885 if (NtCreateKey( &Reboot, KEY_ALL_ACCESS, &attr, 0, NULL, 0, NULL ) != STATUS_SUCCESS)
1887 WARN("Error creating key for reboot managment [%s]\n",
1888 "SYSTEM\\CurrentControlSet\\Control\\Session Manager");
1889 return FALSE;
1892 len0 = strlenW(PreString);
1893 len1 = strlenW(fn1) + len0 + 1;
1894 if (fn2)
1896 len2 = strlenW(fn2) + len0 + 1;
1897 if (flags & MOVEFILE_REPLACE_EXISTING) len2++; /* Plus 1 because of the leading '!' */
1899 else len2 = 1; /* minimum is the 0 characters for the empty second string */
1901 /* convert characters to bytes */
1902 len0 *= sizeof(WCHAR);
1903 len1 *= sizeof(WCHAR);
1904 len2 *= sizeof(WCHAR);
1906 RtlInitUnicodeString( &nameW, ValueName );
1908 /* First we check if the key exists and if so how many bytes it already contains. */
1909 if (NtQueryValueKey( Reboot, &nameW, KeyValuePartialInformation,
1910 NULL, 0, &DataSize ) == STATUS_BUFFER_OVERFLOW)
1912 if (!(Buffer = HeapAlloc( GetProcessHeap(), 0, DataSize + len1 + len2 + sizeof(WCHAR) )))
1913 goto Quit;
1914 if (NtQueryValueKey( Reboot, &nameW, KeyValuePartialInformation,
1915 Buffer, DataSize, &DataSize )) goto Quit;
1916 info = (KEY_VALUE_PARTIAL_INFORMATION *)Buffer;
1917 if (info->Type != REG_MULTI_SZ) goto Quit;
1918 if (DataSize > sizeof(info)) DataSize -= sizeof(WCHAR); /* remove terminating null (will be added back later) */
1920 else
1922 DataSize = info_size;
1923 if (!(Buffer = HeapAlloc( GetProcessHeap(), 0, DataSize + len1 + len2 + sizeof(WCHAR) )))
1924 goto Quit;
1927 p = (WCHAR *)(Buffer + DataSize);
1928 strcpyW( p, PreString );
1929 strcatW( p, fn1 );
1930 DataSize += len1;
1931 if (fn2)
1933 p = (WCHAR *)(Buffer + DataSize);
1934 if (flags & MOVEFILE_REPLACE_EXISTING)
1935 *p++ = '!';
1936 strcpyW( p, PreString );
1937 strcatW( p, fn2 );
1938 DataSize += len2;
1940 else
1942 p = (WCHAR *)(Buffer + DataSize);
1943 *p = 0;
1944 DataSize += sizeof(WCHAR);
1947 /* add final null */
1948 p = (WCHAR *)(Buffer + DataSize);
1949 *p = 0;
1950 DataSize += sizeof(WCHAR);
1952 rc = !NtSetValueKey(Reboot, &nameW, 0, REG_MULTI_SZ, Buffer + info_size, DataSize - info_size);
1954 Quit:
1955 if (Reboot) NtClose(Reboot);
1956 if (Buffer) HeapFree( GetProcessHeap(), 0, Buffer );
1957 return(rc);
1961 /**************************************************************************
1962 * MoveFileExW (KERNEL32.@)
1964 BOOL WINAPI MoveFileExW( LPCWSTR fn1, LPCWSTR fn2, DWORD flag )
1966 DOS_FULL_NAME full_name1, full_name2;
1967 HANDLE hFile;
1968 DWORD attr = INVALID_FILE_ATTRIBUTES;
1970 TRACE("(%s,%s,%04lx)\n", debugstr_w(fn1), debugstr_w(fn2), flag);
1972 /* FIXME: <Gerhard W. Gruber>sparhawk@gmx.at
1973 In case of W9x and lesser this function should return 120 (ERROR_CALL_NOT_IMPLEMENTED)
1974 to be really compatible. Most programs wont have any problems though. In case
1975 you encounter one, this is what you should return here. I don't know what's up
1976 with NT 3.5. Is this function available there or not?
1977 Does anybody really care about 3.5? :)
1980 /* Filename1 has to be always set to a valid path. Filename2 may be NULL
1981 if the source file has to be deleted.
1983 if (!fn1) {
1984 SetLastError(ERROR_INVALID_PARAMETER);
1985 return FALSE;
1988 /* This function has to be run through in order to process the name properly.
1989 If the BOOTDELAY flag is set, the file doesn't need to exist though. At least
1990 that is the behaviour on NT 4.0. The operation accepts the filenames as
1991 they are given but it can't reply with a reasonable returncode. Success
1992 means in that case success for entering the values into the registry.
1994 if(!DOSFS_GetFullName( fn1, TRUE, &full_name1 ))
1996 if(!(flag & MOVEFILE_DELAY_UNTIL_REBOOT))
1997 return FALSE;
2000 if (fn2) /* !fn2 means delete fn1 */
2002 if (DOSFS_GetFullName( fn2, TRUE, &full_name2 ))
2004 if(!(flag & MOVEFILE_DELAY_UNTIL_REBOOT))
2006 /* target exists, check if we may overwrite */
2007 if (!(flag & MOVEFILE_REPLACE_EXISTING))
2009 SetLastError( ERROR_FILE_EXISTS );
2010 return FALSE;
2014 else
2016 if (!DOSFS_GetFullName( fn2, FALSE, &full_name2 ))
2018 if(!(flag & MOVEFILE_DELAY_UNTIL_REBOOT))
2019 return FALSE;
2023 /* Source name and target path are valid */
2025 if (flag & MOVEFILE_DELAY_UNTIL_REBOOT)
2027 return FILE_AddBootRenameEntry( fn1, fn2, flag );
2030 attr = GetFileAttributesW( fn1 );
2031 if ( attr == INVALID_FILE_ATTRIBUTES ) return FALSE;
2033 /* check if we are allowed to rename the source */
2034 hFile = FILE_CreateFile( full_name1.long_name, 0, 0,
2035 NULL, OPEN_EXISTING, 0, 0, TRUE,
2036 GetDriveTypeW( full_name1.short_name ) );
2037 if (!hFile)
2039 if (GetLastError() != ERROR_ACCESS_DENIED) return FALSE;
2040 if ( !(attr & FILE_ATTRIBUTE_DIRECTORY) ) return FALSE;
2041 /* if it's a directory we can continue */
2043 else CloseHandle(hFile);
2045 /* check, if we are allowed to delete the destination,
2046 ** (but the file not being there is fine) */
2047 hFile = FILE_CreateFile( full_name2.long_name, GENERIC_READ|GENERIC_WRITE, 0,
2048 NULL, OPEN_EXISTING, 0, 0, TRUE,
2049 GetDriveTypeW( full_name2.short_name ) );
2050 if(!hFile && GetLastError() != ERROR_FILE_NOT_FOUND) return FALSE;
2051 CloseHandle(hFile);
2053 if (full_name1.drive != full_name2.drive)
2055 if (!(flag & MOVEFILE_COPY_ALLOWED))
2057 SetLastError( ERROR_NOT_SAME_DEVICE );
2058 return FALSE;
2060 else if ( attr & FILE_ATTRIBUTE_DIRECTORY )
2062 /* Strange, but that's what Windows returns */
2063 SetLastError ( ERROR_ACCESS_DENIED );
2064 return FALSE;
2067 if (rename( full_name1.long_name, full_name2.long_name ) == -1)
2068 /* Try copy/delete unless it's a directory. */
2069 /* FIXME: This does not handle the (unlikely) case that the two locations
2070 are on the same Wine drive, but on different Unix file systems. */
2072 if ( attr & FILE_ATTRIBUTE_DIRECTORY )
2074 FILE_SetDosError();
2075 return FALSE;
2077 else
2079 if ( ! CopyFileW( fn1, fn2, !(flag & MOVEFILE_REPLACE_EXISTING) ))
2080 return FALSE;
2081 if ( ! DeleteFileW ( fn1 ) )
2082 return FALSE;
2085 if (is_executable( full_name1.long_name ) != is_executable( full_name2.long_name ))
2087 struct stat fstat;
2088 if (stat( full_name2.long_name, &fstat ) != -1)
2090 if (is_executable( full_name2.long_name ))
2091 /* set executable bit where read bit is set */
2092 fstat.st_mode |= (fstat.st_mode & 0444) >> 2;
2093 else
2094 fstat.st_mode &= ~0111;
2095 chmod( full_name2.long_name, fstat.st_mode );
2098 return TRUE;
2100 else /* fn2 == NULL means delete source */
2102 if (flag & MOVEFILE_DELAY_UNTIL_REBOOT)
2104 if (flag & MOVEFILE_COPY_ALLOWED) {
2105 WARN("Illegal flag\n");
2106 SetLastError( ERROR_GEN_FAILURE );
2107 return FALSE;
2110 return FILE_AddBootRenameEntry( fn1, NULL, flag );
2113 if (unlink( full_name1.long_name ) == -1)
2115 FILE_SetDosError();
2116 return FALSE;
2118 return TRUE; /* successfully deleted */
2122 /**************************************************************************
2123 * MoveFileExA (KERNEL32.@)
2125 BOOL WINAPI MoveFileExA( LPCSTR fn1, LPCSTR fn2, DWORD flag )
2127 UNICODE_STRING fn1W, fn2W;
2128 BOOL ret;
2130 if (!fn1)
2132 SetLastError(ERROR_INVALID_PARAMETER);
2133 return FALSE;
2136 RtlCreateUnicodeStringFromAsciiz(&fn1W, fn1);
2137 if (fn2) RtlCreateUnicodeStringFromAsciiz(&fn2W, fn2);
2138 else fn2W.Buffer = NULL;
2140 ret = MoveFileExW( fn1W.Buffer, fn2W.Buffer, flag );
2142 RtlFreeUnicodeString(&fn1W);
2143 RtlFreeUnicodeString(&fn2W);
2144 return ret;
2148 /**************************************************************************
2149 * MoveFileW (KERNEL32.@)
2151 * Move file or directory
2153 BOOL WINAPI MoveFileW( LPCWSTR fn1, LPCWSTR fn2 )
2155 return MoveFileExW( fn1, fn2, MOVEFILE_COPY_ALLOWED );
2159 /**************************************************************************
2160 * MoveFileA (KERNEL32.@)
2162 BOOL WINAPI MoveFileA( LPCSTR fn1, LPCSTR fn2 )
2164 return MoveFileExA( fn1, fn2, MOVEFILE_COPY_ALLOWED );
2168 /**************************************************************************
2169 * CopyFileW (KERNEL32.@)
2171 BOOL WINAPI CopyFileW( LPCWSTR source, LPCWSTR dest, BOOL fail_if_exists )
2173 HANDLE h1, h2;
2174 BY_HANDLE_FILE_INFORMATION info;
2175 DWORD count;
2176 BOOL ret = FALSE;
2177 char buffer[2048];
2179 if (!source || !dest)
2181 SetLastError(ERROR_INVALID_PARAMETER);
2182 return FALSE;
2185 TRACE("%s -> %s\n", debugstr_w(source), debugstr_w(dest));
2187 if ((h1 = CreateFileW(source, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE,
2188 NULL, OPEN_EXISTING, 0, 0)) == INVALID_HANDLE_VALUE)
2190 WARN("Unable to open source %s\n", debugstr_w(source));
2191 return FALSE;
2194 if (!GetFileInformationByHandle( h1, &info ))
2196 WARN("GetFileInformationByHandle returned error for %s\n", debugstr_w(source));
2197 CloseHandle( h1 );
2198 return FALSE;
2201 if ((h2 = CreateFileW( dest, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
2202 fail_if_exists ? CREATE_NEW : CREATE_ALWAYS,
2203 info.dwFileAttributes, h1 )) == INVALID_HANDLE_VALUE)
2205 WARN("Unable to open dest %s\n", debugstr_w(dest));
2206 CloseHandle( h1 );
2207 return FALSE;
2210 while (ReadFile( h1, buffer, sizeof(buffer), &count, NULL ) && count)
2212 char *p = buffer;
2213 while (count != 0)
2215 DWORD res;
2216 if (!WriteFile( h2, p, count, &res, NULL ) || !res) goto done;
2217 p += res;
2218 count -= res;
2221 ret = TRUE;
2222 done:
2223 CloseHandle( h1 );
2224 CloseHandle( h2 );
2225 return ret;
2229 /**************************************************************************
2230 * CopyFileA (KERNEL32.@)
2232 BOOL WINAPI CopyFileA( LPCSTR source, LPCSTR dest, BOOL fail_if_exists)
2234 UNICODE_STRING sourceW, destW;
2235 BOOL ret;
2237 if (!source || !dest)
2239 SetLastError(ERROR_INVALID_PARAMETER);
2240 return FALSE;
2243 RtlCreateUnicodeStringFromAsciiz(&sourceW, source);
2244 RtlCreateUnicodeStringFromAsciiz(&destW, dest);
2246 ret = CopyFileW(sourceW.Buffer, destW.Buffer, fail_if_exists);
2248 RtlFreeUnicodeString(&sourceW);
2249 RtlFreeUnicodeString(&destW);
2250 return ret;
2254 /**************************************************************************
2255 * CopyFileExW (KERNEL32.@)
2257 * This implementation ignores most of the extra parameters passed-in into
2258 * the "ex" version of the method and calls the CopyFile method.
2259 * It will have to be fixed eventually.
2261 BOOL WINAPI CopyFileExW(LPCWSTR sourceFilename, LPCWSTR destFilename,
2262 LPPROGRESS_ROUTINE progressRoutine, LPVOID appData,
2263 LPBOOL cancelFlagPointer, DWORD copyFlags)
2266 * Interpret the only flag that CopyFile can interpret.
2268 return CopyFileW(sourceFilename, destFilename, (copyFlags & COPY_FILE_FAIL_IF_EXISTS) != 0);
2272 /**************************************************************************
2273 * CopyFileExA (KERNEL32.@)
2275 BOOL WINAPI CopyFileExA(LPCSTR sourceFilename, LPCSTR destFilename,
2276 LPPROGRESS_ROUTINE progressRoutine, LPVOID appData,
2277 LPBOOL cancelFlagPointer, DWORD copyFlags)
2279 UNICODE_STRING sourceW, destW;
2280 BOOL ret;
2282 if (!sourceFilename || !destFilename)
2284 SetLastError(ERROR_INVALID_PARAMETER);
2285 return FALSE;
2288 RtlCreateUnicodeStringFromAsciiz(&sourceW, sourceFilename);
2289 RtlCreateUnicodeStringFromAsciiz(&destW, destFilename);
2291 ret = CopyFileExW(sourceW.Buffer, destW.Buffer, progressRoutine, appData,
2292 cancelFlagPointer, copyFlags);
2294 RtlFreeUnicodeString(&sourceW);
2295 RtlFreeUnicodeString(&destW);
2296 return ret;
2300 /***********************************************************************
2301 * SetFileTime (KERNEL32.@)
2303 BOOL WINAPI SetFileTime( HANDLE hFile,
2304 const FILETIME *lpCreationTime,
2305 const FILETIME *lpLastAccessTime,
2306 const FILETIME *lpLastWriteTime )
2308 BOOL ret;
2309 SERVER_START_REQ( set_file_time )
2311 req->handle = hFile;
2312 if (lpLastAccessTime)
2313 RtlTimeToSecondsSince1970( (PLARGE_INTEGER) lpLastAccessTime, (DWORD *)&req->access_time );
2314 else
2315 req->access_time = 0; /* FIXME */
2316 if (lpLastWriteTime)
2317 RtlTimeToSecondsSince1970( (PLARGE_INTEGER) lpLastWriteTime, (DWORD *)&req->write_time );
2318 else
2319 req->write_time = 0; /* FIXME */
2320 ret = !wine_server_call_err( req );
2322 SERVER_END_REQ;
2323 return ret;
2327 /**************************************************************************
2328 * GetFileAttributesExW (KERNEL32.@)
2330 BOOL WINAPI GetFileAttributesExW(
2331 LPCWSTR lpFileName, GET_FILEEX_INFO_LEVELS fInfoLevelId,
2332 LPVOID lpFileInformation)
2334 DOS_FULL_NAME full_name;
2335 BY_HANDLE_FILE_INFORMATION info;
2337 if (!lpFileName || !lpFileInformation)
2339 SetLastError(ERROR_INVALID_PARAMETER);
2340 return FALSE;
2343 if (fInfoLevelId == GetFileExInfoStandard) {
2344 LPWIN32_FILE_ATTRIBUTE_DATA lpFad =
2345 (LPWIN32_FILE_ATTRIBUTE_DATA) lpFileInformation;
2346 if (!DOSFS_GetFullName( lpFileName, TRUE, &full_name )) return FALSE;
2347 if (!FILE_Stat( full_name.long_name, &info, NULL )) return FALSE;
2349 lpFad->dwFileAttributes = info.dwFileAttributes;
2350 lpFad->ftCreationTime = info.ftCreationTime;
2351 lpFad->ftLastAccessTime = info.ftLastAccessTime;
2352 lpFad->ftLastWriteTime = info.ftLastWriteTime;
2353 lpFad->nFileSizeHigh = info.nFileSizeHigh;
2354 lpFad->nFileSizeLow = info.nFileSizeLow;
2356 else {
2357 FIXME("invalid info level %d!\n", fInfoLevelId);
2358 return FALSE;
2361 return TRUE;
2365 /**************************************************************************
2366 * GetFileAttributesExA (KERNEL32.@)
2368 BOOL WINAPI GetFileAttributesExA(
2369 LPCSTR filename, GET_FILEEX_INFO_LEVELS fInfoLevelId,
2370 LPVOID lpFileInformation)
2372 UNICODE_STRING filenameW;
2373 BOOL ret = FALSE;
2375 if (!filename || !lpFileInformation)
2377 SetLastError(ERROR_INVALID_PARAMETER);
2378 return FALSE;
2381 if (RtlCreateUnicodeStringFromAsciiz(&filenameW, filename))
2383 ret = GetFileAttributesExW(filenameW.Buffer, fInfoLevelId, lpFileInformation);
2384 RtlFreeUnicodeString(&filenameW);
2386 else
2387 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
2388 return ret;