Implemented GetCompressedFileSize[AW].
[wine.git] / files / file.c
blobb219a27989ef7caf892ebe48b9e7aaf8daac92fc
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 "heap.h"
73 #include "msdos.h"
74 #include "wincon.h"
75 #include "../kernel/kernel_private.h"
77 #include "smb.h"
78 #include "wine/unicode.h"
79 #include "wine/debug.h"
81 WINE_DEFAULT_DEBUG_CHANNEL(file);
83 #if defined(MAP_ANONYMOUS) && !defined(MAP_ANON)
84 #define MAP_ANON MAP_ANONYMOUS
85 #endif
87 #define IS_OPTION_TRUE(ch) ((ch) == 'y' || (ch) == 'Y' || (ch) == 't' || (ch) == 'T' || (ch) == '1')
89 HANDLE dos_handles[DOS_TABLE_SIZE];
90 mode_t FILE_umask;
92 /***********************************************************************
93 * FILE_ConvertOFMode
95 * Convert OF_* mode into flags for CreateFile.
97 void FILE_ConvertOFMode( INT mode, DWORD *access, DWORD *sharing )
99 switch(mode & 0x03)
101 case OF_READ: *access = GENERIC_READ; break;
102 case OF_WRITE: *access = GENERIC_WRITE; break;
103 case OF_READWRITE: *access = GENERIC_READ | GENERIC_WRITE; break;
104 default: *access = 0; break;
106 switch(mode & 0x70)
108 case OF_SHARE_EXCLUSIVE: *sharing = 0; break;
109 case OF_SHARE_DENY_WRITE: *sharing = FILE_SHARE_READ; break;
110 case OF_SHARE_DENY_READ: *sharing = FILE_SHARE_WRITE; break;
111 case OF_SHARE_DENY_NONE:
112 case OF_SHARE_COMPAT:
113 default: *sharing = FILE_SHARE_READ | FILE_SHARE_WRITE; break;
118 /***********************************************************************
119 * FILE_strcasecmp
121 * locale-independent case conversion for file I/O
123 int FILE_strcasecmp( const char *str1, const char *str2 )
125 int ret = 0;
126 for ( ; ; str1++, str2++)
127 if ((ret = FILE_toupper(*str1) - FILE_toupper(*str2)) || !*str1) break;
128 return ret;
132 /***********************************************************************
133 * FILE_strncasecmp
135 * locale-independent case conversion for file I/O
137 int FILE_strncasecmp( const char *str1, const char *str2, int len )
139 int ret = 0;
140 for ( ; len > 0; len--, str1++, str2++)
141 if ((ret = FILE_toupper(*str1) - FILE_toupper(*str2)) || !*str1) break;
142 return ret;
146 /***********************************************************************
147 * FILE_SetDosError
149 * Set the DOS error code from errno.
151 void FILE_SetDosError(void)
153 int save_errno = errno; /* errno gets overwritten by printf */
155 TRACE("errno = %d %s\n", errno, strerror(errno));
156 switch (save_errno)
158 case EAGAIN:
159 SetLastError( ERROR_SHARING_VIOLATION );
160 break;
161 case EBADF:
162 SetLastError( ERROR_INVALID_HANDLE );
163 break;
164 case ENOSPC:
165 SetLastError( ERROR_HANDLE_DISK_FULL );
166 break;
167 case EACCES:
168 case EPERM:
169 case EROFS:
170 SetLastError( ERROR_ACCESS_DENIED );
171 break;
172 case EBUSY:
173 SetLastError( ERROR_LOCK_VIOLATION );
174 break;
175 case ENOENT:
176 SetLastError( ERROR_FILE_NOT_FOUND );
177 break;
178 case EISDIR:
179 SetLastError( ERROR_CANNOT_MAKE );
180 break;
181 case ENFILE:
182 case EMFILE:
183 SetLastError( ERROR_NO_MORE_FILES );
184 break;
185 case EEXIST:
186 SetLastError( ERROR_FILE_EXISTS );
187 break;
188 case EINVAL:
189 case ESPIPE:
190 SetLastError( ERROR_SEEK );
191 break;
192 case ENOTEMPTY:
193 SetLastError( ERROR_DIR_NOT_EMPTY );
194 break;
195 case ENOEXEC:
196 SetLastError( ERROR_BAD_FORMAT );
197 break;
198 default:
199 WARN("unknown file error: %s\n", strerror(save_errno) );
200 SetLastError( ERROR_GEN_FAILURE );
201 break;
203 errno = save_errno;
207 /***********************************************************************
208 * FILE_GetUnixHandleType
210 * Retrieve the Unix handle corresponding to a file handle.
211 * Returns -1 on failure.
213 static int FILE_GetUnixHandleType( HANDLE handle, DWORD access, enum fd_type *type, int *flags_ptr )
215 int ret, flags, fd = -1;
217 ret = wine_server_handle_to_fd( handle, access, &fd, type, &flags );
218 if (flags_ptr) *flags_ptr = flags;
219 if (ret) SetLastError( RtlNtStatusToDosError(ret) );
220 else if (((access & GENERIC_READ) && (flags & FD_FLAG_RECV_SHUTDOWN)) ||
221 ((access & GENERIC_WRITE) && (flags & FD_FLAG_SEND_SHUTDOWN)))
223 close (fd);
224 SetLastError ( ERROR_PIPE_NOT_CONNECTED );
225 return -1;
227 return fd;
230 /***********************************************************************
231 * FILE_GetUnixHandle
233 * Retrieve the Unix handle corresponding to a file handle.
234 * Returns -1 on failure.
236 int FILE_GetUnixHandle( HANDLE handle, DWORD access )
238 return FILE_GetUnixHandleType( handle, access, NULL, NULL );
241 /******************************************************************
242 * OpenConsoleW (KERNEL32.@)
244 * Undocumented
245 * Open a handle to the current process console.
246 * Returns INVALID_HANDLE_VALUE on failure.
248 HANDLE WINAPI OpenConsoleW(LPCWSTR name, DWORD access, LPSECURITY_ATTRIBUTES sa,
249 DWORD creation)
251 static const WCHAR coninW[] = {'C','O','N','I','N','$',0};
252 static const WCHAR conoutW[] = {'C','O','N','O','U','T','$',0};
253 BOOL output;
254 HANDLE ret;
256 if (strcmpW(coninW, name) == 0)
257 output = FALSE;
258 else if (strcmpW(conoutW, name) == 0)
259 output = TRUE;
260 else
262 SetLastError(ERROR_INVALID_NAME);
263 return INVALID_HANDLE_VALUE;
265 if (creation != OPEN_EXISTING)
267 SetLastError(ERROR_INVALID_PARAMETER);
268 return INVALID_HANDLE_VALUE;
271 SERVER_START_REQ( open_console )
273 req->from = output;
274 req->access = access;
275 req->share = FILE_SHARE_READ | FILE_SHARE_WRITE;
276 req->inherit = (sa && (sa->nLength>=sizeof(*sa)) && sa->bInheritHandle);
277 SetLastError(0);
278 wine_server_call_err( req );
279 ret = reply->handle;
281 SERVER_END_REQ;
282 return ret ? console_handle_map(ret) : INVALID_HANDLE_VALUE;
285 /******************************************************************
286 * VerifyConsoleIoHandle (KERNEL32.@)
288 * Undocumented
290 BOOL WINAPI VerifyConsoleIoHandle(HANDLE handle)
292 BOOL ret;
294 if (!is_console_handle(handle)) return FALSE;
295 SERVER_START_REQ(get_console_mode)
297 req->handle = console_handle_unmap(handle);
298 ret = !wine_server_call_err( req );
300 SERVER_END_REQ;
301 return ret;
304 /******************************************************************
305 * DuplicateConsoleHandle (KERNEL32.@)
307 * Undocumented
309 HANDLE WINAPI DuplicateConsoleHandle(HANDLE handle, DWORD access, BOOL inherit,
310 DWORD options)
312 HANDLE ret;
314 if (!is_console_handle(handle) ||
315 !DuplicateHandle(GetCurrentProcess(), console_handle_unmap(handle),
316 GetCurrentProcess(), &ret, access, inherit, options))
317 return INVALID_HANDLE_VALUE;
318 return console_handle_map(ret);
321 /******************************************************************
322 * CloseConsoleHandle (KERNEL32.@)
324 * Undocumented
326 BOOL WINAPI CloseConsoleHandle(HANDLE handle)
328 if (!is_console_handle(handle))
330 SetLastError(ERROR_INVALID_PARAMETER);
331 return FALSE;
333 return CloseHandle(console_handle_unmap(handle));
336 /******************************************************************
337 * GetConsoleInputWaitHandle (KERNEL32.@)
339 * Undocumented
341 HANDLE WINAPI GetConsoleInputWaitHandle(void)
343 static HANDLE console_wait_event;
345 /* FIXME: this is not thread safe */
346 if (!console_wait_event)
348 SERVER_START_REQ(get_console_wait_event)
350 if (!wine_server_call_err( req )) console_wait_event = reply->handle;
352 SERVER_END_REQ;
354 return console_wait_event;
356 /* end of FIXME */
359 /* FIXME: those routines defined as pointers are needed, because this file is
360 * currently compiled into NTDLL whereas it belongs to kernel32.
361 * this shall go away once all the DLL separation process is done
363 typedef BOOL (WINAPI* pRW)(HANDLE, const void*, DWORD, DWORD*, void*);
365 static BOOL FILE_ReadConsole(HANDLE hCon, void* buf, DWORD nb, DWORD* nr, void* p)
367 static HANDLE hKernel /* = 0 */;
368 static pRW pReadConsole /* = 0 */;
370 if ((!hKernel && !(hKernel = LoadLibraryA("kernel32"))) ||
371 (!pReadConsole &&
372 !(pReadConsole = GetProcAddress(hKernel, "ReadConsoleA"))))
374 *nr = 0;
375 return 0;
377 return (pReadConsole)(hCon, buf, nb, nr, p);
380 static BOOL FILE_WriteConsole(HANDLE hCon, const void* buf, DWORD nb, DWORD* nr, void* p)
382 static HANDLE hKernel /* = 0 */;
383 static pRW pWriteConsole /* = 0 */;
385 if ((!hKernel && !(hKernel = LoadLibraryA("kernel32"))) ||
386 (!pWriteConsole &&
387 !(pWriteConsole = GetProcAddress(hKernel, "WriteConsoleA"))))
389 *nr = 0;
390 return 0;
392 return (pWriteConsole)(hCon, buf, nb, nr, p);
394 /* end of FIXME */
396 /***********************************************************************
397 * FILE_CreateFile
399 * Implementation of CreateFile. Takes a Unix path name.
400 * Returns 0 on failure.
402 HANDLE FILE_CreateFile( LPCSTR filename, DWORD access, DWORD sharing,
403 LPSECURITY_ATTRIBUTES sa, DWORD creation,
404 DWORD attributes, HANDLE template, BOOL fail_read_only,
405 UINT drive_type )
407 unsigned int err;
408 HANDLE ret;
410 for (;;)
412 SERVER_START_REQ( create_file )
414 req->access = access;
415 req->inherit = (sa && (sa->nLength>=sizeof(*sa)) && sa->bInheritHandle);
416 req->sharing = sharing;
417 req->create = creation;
418 req->attrs = attributes;
419 req->drive_type = drive_type;
420 wine_server_add_data( req, filename, strlen(filename) );
421 SetLastError(0);
422 err = wine_server_call( req );
423 ret = reply->handle;
425 SERVER_END_REQ;
427 /* If write access failed, retry without GENERIC_WRITE */
429 if (!ret && !fail_read_only && (access & GENERIC_WRITE))
431 if ((err == STATUS_MEDIA_WRITE_PROTECTED) || (err == STATUS_ACCESS_DENIED))
433 TRACE("Write access failed for file '%s', trying without "
434 "write access\n", filename);
435 access &= ~GENERIC_WRITE;
436 continue;
440 if (err)
442 /* In the case file creation was rejected due to CREATE_NEW flag
443 * was specified and file with that name already exists, correct
444 * last error is ERROR_FILE_EXISTS and not ERROR_ALREADY_EXISTS.
445 * Note: RtlNtStatusToDosError is not the subject to blame here.
447 if (err == STATUS_OBJECT_NAME_COLLISION)
448 SetLastError( ERROR_FILE_EXISTS );
449 else
450 SetLastError( RtlNtStatusToDosError(err) );
453 if (!ret) WARN("Unable to create file '%s' (GLE %ld)\n", filename, GetLastError());
454 return ret;
459 /***********************************************************************
460 * FILE_CreateDevice
462 * Same as FILE_CreateFile but for a device
463 * Returns 0 on failure.
465 HANDLE FILE_CreateDevice( int client_id, DWORD access, LPSECURITY_ATTRIBUTES sa )
467 HANDLE ret;
468 SERVER_START_REQ( create_device )
470 req->access = access;
471 req->inherit = (sa && (sa->nLength>=sizeof(*sa)) && sa->bInheritHandle);
472 req->id = client_id;
473 SetLastError(0);
474 wine_server_call_err( req );
475 ret = reply->handle;
477 SERVER_END_REQ;
478 return ret;
481 static HANDLE FILE_OpenPipe(LPCWSTR name, DWORD access, LPSECURITY_ATTRIBUTES sa )
483 HANDLE ret;
484 DWORD len = 0;
486 if (name && (len = strlenW(name)) > MAX_PATH)
488 SetLastError( ERROR_FILENAME_EXCED_RANGE );
489 return 0;
491 SERVER_START_REQ( open_named_pipe )
493 req->access = access;
494 req->inherit = (sa && (sa->nLength>=sizeof(*sa)) && sa->bInheritHandle);
495 SetLastError(0);
496 wine_server_add_data( req, name, len * sizeof(WCHAR) );
497 wine_server_call_err( req );
498 ret = reply->handle;
500 SERVER_END_REQ;
501 TRACE("Returned %p\n",ret);
502 return ret;
505 /*************************************************************************
506 * CreateFileW [KERNEL32.@] Creates or opens a file or other object
508 * Creates or opens an object, and returns a handle that can be used to
509 * access that object.
511 * PARAMS
513 * filename [in] pointer to filename to be accessed
514 * access [in] access mode requested
515 * sharing [in] share mode
516 * sa [in] pointer to security attributes
517 * creation [in] how to create the file
518 * attributes [in] attributes for newly created file
519 * template [in] handle to file with extended attributes to copy
521 * RETURNS
522 * Success: Open handle to specified file
523 * Failure: INVALID_HANDLE_VALUE
525 * NOTES
526 * Should call SetLastError() on failure.
528 * BUGS
530 * Doesn't support character devices, template files, or a
531 * lot of the 'attributes' flags yet.
533 HANDLE WINAPI CreateFileW( LPCWSTR filename, DWORD access, DWORD sharing,
534 LPSECURITY_ATTRIBUTES sa, DWORD creation,
535 DWORD attributes, HANDLE template )
537 DOS_FULL_NAME full_name;
538 HANDLE ret;
539 static const WCHAR bkslashes_with_question_markW[] = {'\\','\\','?','\\',0};
540 static const WCHAR bkslashes_with_dotW[] = {'\\','\\','.','\\',0};
541 static const WCHAR bkslashesW[] = {'\\','\\',0};
542 static const WCHAR coninW[] = {'C','O','N','I','N','$',0};
543 static const WCHAR conoutW[] = {'C','O','N','O','U','T','$',0};
545 if (!filename)
547 SetLastError( ERROR_INVALID_PARAMETER );
548 return INVALID_HANDLE_VALUE;
550 TRACE("%s %s%s%s%s%s%s%s attributes 0x%lx\n", debugstr_w(filename),
551 ((access & GENERIC_READ)==GENERIC_READ)?"GENERIC_READ ":"",
552 ((access & GENERIC_WRITE)==GENERIC_WRITE)?"GENERIC_WRITE ":"",
553 (!access)?"QUERY_ACCESS ":"",
554 ((sharing & FILE_SHARE_READ)==FILE_SHARE_READ)?"FILE_SHARE_READ ":"",
555 ((sharing & FILE_SHARE_WRITE)==FILE_SHARE_WRITE)?"FILE_SHARE_WRITE ":"",
556 ((sharing & FILE_SHARE_DELETE)==FILE_SHARE_DELETE)?"FILE_SHARE_DELETE ":"",
557 (creation ==CREATE_NEW)?"CREATE_NEW":
558 (creation ==CREATE_ALWAYS)?"CREATE_ALWAYS ":
559 (creation ==OPEN_EXISTING)?"OPEN_EXISTING ":
560 (creation ==OPEN_ALWAYS)?"OPEN_ALWAYS ":
561 (creation ==TRUNCATE_EXISTING)?"TRUNCATE_EXISTING ":"", attributes);
563 /* If the name starts with '\\?\', ignore the first 4 chars. */
564 if (!strncmpW(filename, bkslashes_with_question_markW, 4))
566 static const WCHAR uncW[] = {'U','N','C','\\',0};
567 filename += 4;
568 if (!strncmpiW(filename, uncW, 4))
570 FIXME("UNC name (%s) not supported.\n", debugstr_w(filename) );
571 SetLastError( ERROR_PATH_NOT_FOUND );
572 return INVALID_HANDLE_VALUE;
576 if (!strncmpW(filename, bkslashes_with_dotW, 4))
578 static const WCHAR pipeW[] = {'P','I','P','E','\\',0};
579 if(!strncmpiW(filename + 4, pipeW, 5))
581 TRACE("Opening a pipe: %s\n", debugstr_w(filename));
582 ret = FILE_OpenPipe( filename, access, sa );
583 goto done;
585 else if (isalphaW(filename[4]) && filename[5] == ':' && filename[6] == '\0')
587 ret = FILE_CreateDevice( (toupperW(filename[4]) - 'A') | 0x20000, access, sa );
588 goto done;
590 else if (!DOSFS_GetDevice( filename ))
592 ret = DEVICE_Open( filename+4, access, sa );
593 goto done;
595 else
596 filename+=4; /* fall into DOSFS_Device case below */
599 /* If the name still starts with '\\', it's a UNC name. */
600 if (!strncmpW(filename, bkslashesW, 2))
602 ret = SMB_CreateFileW(filename, access, sharing, sa, creation, attributes, template );
603 goto done;
606 /* If the name contains a DOS wild card (* or ?), do no create a file */
607 if(strchrW(filename, '*') || strchrW(filename, '?'))
609 SetLastError(ERROR_BAD_PATHNAME);
610 return INVALID_HANDLE_VALUE;
613 /* Open a console for CONIN$ or CONOUT$ */
614 if (!strcmpiW(filename, coninW) || !strcmpiW(filename, conoutW))
616 ret = OpenConsoleW(filename, access, sa, creation);
617 goto done;
620 if (DOSFS_GetDevice( filename ))
622 TRACE("opening device %s\n", debugstr_w(filename) );
624 if (!(ret = DOSFS_OpenDevice( filename, access, attributes, sa )))
626 /* Do not silence this please. It is a critical error. -MM */
627 ERR("Couldn't open device %s!\n", debugstr_w(filename));
628 SetLastError( ERROR_FILE_NOT_FOUND );
630 goto done;
633 /* check for filename, don't check for last entry if creating */
634 if (!DOSFS_GetFullName( filename,
635 (creation == OPEN_EXISTING) ||
636 (creation == TRUNCATE_EXISTING),
637 &full_name )) {
638 WARN("Unable to get full filename from %s (GLE %ld)\n",
639 debugstr_w(filename), GetLastError());
640 return INVALID_HANDLE_VALUE;
643 ret = FILE_CreateFile( full_name.long_name, access, sharing,
644 sa, creation, attributes, template,
645 DRIVE_GetFlags(full_name.drive) & DRIVE_FAIL_READ_ONLY,
646 GetDriveTypeW( full_name.short_name ) );
647 done:
648 if (!ret) ret = INVALID_HANDLE_VALUE;
649 TRACE("returning %p\n", ret);
650 return ret;
655 /*************************************************************************
656 * CreateFileA (KERNEL32.@)
658 HANDLE WINAPI CreateFileA( LPCSTR filename, DWORD access, DWORD sharing,
659 LPSECURITY_ATTRIBUTES sa, DWORD creation,
660 DWORD attributes, HANDLE template)
662 UNICODE_STRING filenameW;
663 HANDLE ret = INVALID_HANDLE_VALUE;
665 if (!filename)
667 SetLastError( ERROR_INVALID_PARAMETER );
668 return INVALID_HANDLE_VALUE;
671 if (RtlCreateUnicodeStringFromAsciiz(&filenameW, filename))
673 ret = CreateFileW(filenameW.Buffer, access, sharing, sa, creation,
674 attributes, template);
675 RtlFreeUnicodeString(&filenameW);
677 else
678 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
679 return ret;
683 /***********************************************************************
684 * FILE_FillInfo
686 * Fill a file information from a struct stat.
688 static void FILE_FillInfo( struct stat *st, BY_HANDLE_FILE_INFORMATION *info )
690 if (S_ISDIR(st->st_mode))
691 info->dwFileAttributes = FILE_ATTRIBUTE_DIRECTORY;
692 else
693 info->dwFileAttributes = FILE_ATTRIBUTE_ARCHIVE;
694 if (!(st->st_mode & S_IWUSR))
695 info->dwFileAttributes |= FILE_ATTRIBUTE_READONLY;
697 RtlSecondsSince1970ToTime( st->st_mtime, (LARGE_INTEGER *)&info->ftCreationTime );
698 RtlSecondsSince1970ToTime( st->st_mtime, (LARGE_INTEGER *)&info->ftLastWriteTime );
699 RtlSecondsSince1970ToTime( st->st_atime, (LARGE_INTEGER *)&info->ftLastAccessTime );
701 info->dwVolumeSerialNumber = 0; /* FIXME */
702 info->nFileSizeHigh = 0;
703 info->nFileSizeLow = 0;
704 if (!S_ISDIR(st->st_mode)) {
705 info->nFileSizeHigh = st->st_size >> 32;
706 info->nFileSizeLow = st->st_size & 0xffffffff;
708 info->nNumberOfLinks = st->st_nlink;
709 info->nFileIndexHigh = 0;
710 info->nFileIndexLow = st->st_ino;
714 /***********************************************************************
715 * get_show_dot_files_option
717 static BOOL get_show_dot_files_option(void)
719 static const WCHAR WineW[] = {'M','a','c','h','i','n','e','\\',
720 'S','o','f','t','w','a','r','e','\\',
721 'W','i','n','e','\\','W','i','n','e','\\',
722 'C','o','n','f','i','g','\\','W','i','n','e',0};
723 static const WCHAR ShowDotFilesW[] = {'S','h','o','w','D','o','t','F','i','l','e','s',0};
725 char tmp[80];
726 HKEY hkey;
727 DWORD dummy;
728 OBJECT_ATTRIBUTES attr;
729 UNICODE_STRING nameW;
730 BOOL ret = FALSE;
732 attr.Length = sizeof(attr);
733 attr.RootDirectory = 0;
734 attr.ObjectName = &nameW;
735 attr.Attributes = 0;
736 attr.SecurityDescriptor = NULL;
737 attr.SecurityQualityOfService = NULL;
738 RtlInitUnicodeString( &nameW, WineW );
740 if (!NtOpenKey( &hkey, KEY_ALL_ACCESS, &attr ))
742 RtlInitUnicodeString( &nameW, ShowDotFilesW );
743 if (!NtQueryValueKey( hkey, &nameW, KeyValuePartialInformation, tmp, sizeof(tmp), &dummy ))
745 WCHAR *str = (WCHAR *)((KEY_VALUE_PARTIAL_INFORMATION *)tmp)->Data;
746 ret = IS_OPTION_TRUE( str[0] );
748 NtClose( hkey );
750 return ret;
754 /***********************************************************************
755 * FILE_Stat
757 * Stat a Unix path name. Return TRUE if OK.
759 BOOL FILE_Stat( LPCSTR unixName, BY_HANDLE_FILE_INFORMATION *info, BOOL *is_symlink_ptr )
761 struct stat st;
762 int is_symlink;
763 LPCSTR p;
765 if (lstat( unixName, &st ) == -1)
767 FILE_SetDosError();
768 return FALSE;
770 is_symlink = S_ISLNK(st.st_mode);
771 if (is_symlink)
773 /* do a "real" stat to find out
774 about the type of the symlink destination */
775 if (stat( unixName, &st ) == -1)
777 FILE_SetDosError();
778 return FALSE;
782 /* fill in the information we gathered so far */
783 FILE_FillInfo( &st, info );
785 /* and now see if this is a hidden file, based on the name */
786 p = strrchr( unixName, '/');
787 p = p ? p + 1 : unixName;
788 if (*p == '.' && *(p+1) && (*(p+1) != '.' || *(p+2)))
790 static int show_dot_files = -1;
791 if (show_dot_files == -1)
792 show_dot_files = get_show_dot_files_option();
793 if (!show_dot_files)
794 info->dwFileAttributes |= FILE_ATTRIBUTE_HIDDEN;
796 if (is_symlink_ptr) *is_symlink_ptr = is_symlink;
797 return TRUE;
801 /***********************************************************************
802 * GetFileInformationByHandle (KERNEL32.@)
804 DWORD WINAPI GetFileInformationByHandle( HANDLE hFile,
805 BY_HANDLE_FILE_INFORMATION *info )
807 DWORD ret;
808 if (!info) return 0;
810 TRACE("%p\n", hFile);
812 SERVER_START_REQ( get_file_info )
814 req->handle = hFile;
815 if ((ret = !wine_server_call_err( req )))
817 /* FIXME: which file types are supported ?
818 * Serial ports (FILE_TYPE_CHAR) are not,
819 * and MSDN also says that pipes are not supported.
820 * FILE_TYPE_REMOTE seems to be supported according to
821 * MSDN q234741.txt */
822 if ((reply->type == FILE_TYPE_DISK) || (reply->type == FILE_TYPE_REMOTE))
824 RtlSecondsSince1970ToTime( reply->write_time, (LARGE_INTEGER *)&info->ftCreationTime );
825 RtlSecondsSince1970ToTime( reply->write_time, (LARGE_INTEGER *)&info->ftLastWriteTime );
826 RtlSecondsSince1970ToTime( reply->access_time, (LARGE_INTEGER *)&info->ftLastAccessTime );
827 info->dwFileAttributes = reply->attr;
828 info->dwVolumeSerialNumber = reply->serial;
829 info->nFileSizeHigh = reply->size_high;
830 info->nFileSizeLow = reply->size_low;
831 info->nNumberOfLinks = reply->links;
832 info->nFileIndexHigh = reply->index_high;
833 info->nFileIndexLow = reply->index_low;
835 else
837 SetLastError(ERROR_NOT_SUPPORTED);
838 ret = 0;
842 SERVER_END_REQ;
843 return ret;
847 /**************************************************************************
848 * GetFileAttributesW (KERNEL32.@)
850 DWORD WINAPI GetFileAttributesW( LPCWSTR name )
852 DOS_FULL_NAME full_name;
853 BY_HANDLE_FILE_INFORMATION info;
855 if (name == NULL)
857 SetLastError( ERROR_INVALID_PARAMETER );
858 return -1;
860 if (!DOSFS_GetFullName( name, TRUE, &full_name) )
861 return -1;
862 if (!FILE_Stat( full_name.long_name, &info, NULL )) return -1;
863 return info.dwFileAttributes;
867 /**************************************************************************
868 * GetFileAttributesA (KERNEL32.@)
870 DWORD WINAPI GetFileAttributesA( LPCSTR name )
872 UNICODE_STRING nameW;
873 DWORD ret = (DWORD)-1;
875 if (!name)
877 SetLastError( ERROR_INVALID_PARAMETER );
878 return (DWORD)-1;
881 if (RtlCreateUnicodeStringFromAsciiz(&nameW, name))
883 ret = GetFileAttributesW(nameW.Buffer);
884 RtlFreeUnicodeString(&nameW);
886 else
887 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
888 return ret;
892 /**************************************************************************
893 * SetFileAttributesW (KERNEL32.@)
895 BOOL WINAPI SetFileAttributesW(LPCWSTR lpFileName, DWORD attributes)
897 struct stat buf;
898 DOS_FULL_NAME full_name;
900 if (!lpFileName)
902 SetLastError( ERROR_INVALID_PARAMETER );
903 return FALSE;
906 TRACE("(%s,%lx)\n", debugstr_w(lpFileName), attributes);
908 if (!DOSFS_GetFullName( lpFileName, TRUE, &full_name ))
909 return FALSE;
911 if(stat(full_name.long_name,&buf)==-1)
913 FILE_SetDosError();
914 return FALSE;
916 if (attributes & FILE_ATTRIBUTE_READONLY)
918 if(S_ISDIR(buf.st_mode))
919 /* FIXME */
920 WARN("FILE_ATTRIBUTE_READONLY ignored for directory.\n");
921 else
922 buf.st_mode &= ~0222; /* octal!, clear write permission bits */
923 attributes &= ~FILE_ATTRIBUTE_READONLY;
925 else
927 /* add write permission */
928 buf.st_mode |= (0600 | ((buf.st_mode & 044) >> 1)) & (~FILE_umask);
930 if (attributes & FILE_ATTRIBUTE_DIRECTORY)
932 if (!S_ISDIR(buf.st_mode))
933 FIXME("SetFileAttributes expected the file %s to be a directory\n",
934 debugstr_w(lpFileName));
935 attributes &= ~FILE_ATTRIBUTE_DIRECTORY;
937 attributes &= ~(FILE_ATTRIBUTE_NORMAL|FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_HIDDEN|FILE_ATTRIBUTE_SYSTEM);
938 if (attributes)
939 FIXME("(%s):%lx attribute(s) not implemented.\n", debugstr_w(lpFileName), attributes);
940 if (-1==chmod(full_name.long_name,buf.st_mode))
942 if (GetDriveTypeW(lpFileName) == DRIVE_CDROM)
944 SetLastError( ERROR_ACCESS_DENIED );
945 return FALSE;
949 * FIXME: We don't return FALSE here because of differences between
950 * Linux and Windows privileges. Under Linux only the owner of
951 * the file is allowed to change file attributes. Under Windows,
952 * applications expect that if you can write to a file, you can also
953 * change its attributes (see GENERIC_WRITE). We could try to be
954 * clever here but that would break multi-user installations where
955 * users share read-only DLLs. This is because some installers like
956 * to change attributes of already installed DLLs.
958 FIXME("Couldn't set file attributes for existing file \"%s\".\n"
959 "Check permissions or set VFAT \"quiet\" mount flag\n", full_name.long_name);
961 return TRUE;
965 /**************************************************************************
966 * SetFileAttributesA (KERNEL32.@)
968 BOOL WINAPI SetFileAttributesA(LPCSTR lpFileName, DWORD attributes)
970 UNICODE_STRING filenameW;
971 BOOL ret = FALSE;
973 if (!lpFileName)
975 SetLastError( ERROR_INVALID_PARAMETER );
976 return FALSE;
979 if (RtlCreateUnicodeStringFromAsciiz(&filenameW, lpFileName))
981 ret = SetFileAttributesW(filenameW.Buffer, attributes);
982 RtlFreeUnicodeString(&filenameW);
984 else
985 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
986 return ret;
990 /******************************************************************************
991 * GetCompressedFileSizeA [KERNEL32.@]
993 DWORD WINAPI GetCompressedFileSizeA(
994 LPCSTR lpFileName,
995 LPDWORD lpFileSizeHigh)
997 UNICODE_STRING filenameW;
998 DWORD ret;
1000 if (RtlCreateUnicodeStringFromAsciiz(&filenameW, lpFileName))
1002 ret = GetCompressedFileSizeW(filenameW.Buffer, lpFileSizeHigh);
1003 RtlFreeUnicodeString(&filenameW);
1005 else
1007 ret = INVALID_FILE_SIZE;
1008 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1010 return ret;
1014 /******************************************************************************
1015 * GetCompressedFileSizeW [KERNEL32.@]
1017 * RETURNS
1018 * Success: Low-order doubleword of number of bytes
1019 * Failure: INVALID_FILE_SIZE
1021 DWORD WINAPI GetCompressedFileSizeW(
1022 LPCWSTR lpFileName, /* [in] Pointer to name of file */
1023 LPDWORD lpFileSizeHigh) /* [out] Receives high-order doubleword of size */
1025 DOS_FULL_NAME full_name;
1026 struct stat st;
1027 DWORD low;
1029 TRACE("(%s,%p)\n",debugstr_w(lpFileName),lpFileSizeHigh);
1031 if (!DOSFS_GetFullName( lpFileName, TRUE, &full_name )) return INVALID_FILE_SIZE;
1032 if (stat(full_name.long_name, &st) != 0)
1034 FILE_SetDosError();
1035 return INVALID_FILE_SIZE;
1037 #if HAVE_STRUCT_STAT_ST_BLOCKS
1038 /* blocks are 512 bytes long */
1039 if (lpFileSizeHigh) *lpFileSizeHigh = (st.st_blocks >> 23);
1040 low = (DWORD)(st.st_blocks << 9);
1041 #else
1042 if (lpFileSizeHigh) *lpFileSizeHigh = (st.st_size >> 32);
1043 low = (DWORD)st.st_size;
1044 #endif
1045 return low;
1049 /***********************************************************************
1050 * GetFileTime (KERNEL32.@)
1052 BOOL WINAPI GetFileTime( HANDLE hFile, FILETIME *lpCreationTime,
1053 FILETIME *lpLastAccessTime,
1054 FILETIME *lpLastWriteTime )
1056 BY_HANDLE_FILE_INFORMATION info;
1057 if (!GetFileInformationByHandle( hFile, &info )) return FALSE;
1058 if (lpCreationTime) *lpCreationTime = info.ftCreationTime;
1059 if (lpLastAccessTime) *lpLastAccessTime = info.ftLastAccessTime;
1060 if (lpLastWriteTime) *lpLastWriteTime = info.ftLastWriteTime;
1061 return TRUE;
1065 /***********************************************************************
1066 * FILE_GetTempFileName : utility for GetTempFileName
1068 static UINT FILE_GetTempFileName( LPCWSTR path, LPCWSTR prefix, UINT unique,
1069 LPWSTR buffer )
1071 static UINT unique_temp;
1072 DOS_FULL_NAME full_name;
1073 int i;
1074 LPWSTR p;
1075 UINT num;
1076 char buf[20];
1078 if ( !path || !prefix || !buffer )
1080 SetLastError( ERROR_INVALID_PARAMETER );
1081 return 0;
1084 if (!unique_temp) unique_temp = time(NULL) & 0xffff;
1085 num = unique ? (unique & 0xffff) : (unique_temp++ & 0xffff);
1087 strcpyW( buffer, path );
1088 p = buffer + strlenW(buffer);
1090 /* add a \, if there isn't one and path is more than just the drive letter ... */
1091 if ( !((strlenW(buffer) == 2) && (buffer[1] == ':'))
1092 && ((p == buffer) || (p[-1] != '\\'))) *p++ = '\\';
1094 for (i = 3; (i > 0) && (*prefix); i--) *p++ = *prefix++;
1096 sprintf( buf, "%04x.tmp", num );
1097 MultiByteToWideChar(CP_ACP, 0, buf, -1, p, 20);
1099 /* Now try to create it */
1101 if (!unique)
1105 HANDLE handle = CreateFileW( buffer, GENERIC_WRITE, 0, NULL,
1106 CREATE_NEW, FILE_ATTRIBUTE_NORMAL, 0 );
1107 if (handle != INVALID_HANDLE_VALUE)
1108 { /* We created it */
1109 TRACE("created %s\n", debugstr_w(buffer) );
1110 CloseHandle( handle );
1111 break;
1113 if (GetLastError() != ERROR_FILE_EXISTS &&
1114 GetLastError() != ERROR_SHARING_VIOLATION)
1115 break; /* No need to go on */
1116 num++;
1117 sprintf( buf, "%04x.tmp", num );
1118 MultiByteToWideChar(CP_ACP, 0, buf, -1, p, 20);
1119 } while (num != (unique & 0xffff));
1122 /* Get the full path name */
1124 if (DOSFS_GetFullName( buffer, FALSE, &full_name ))
1126 char *slash;
1127 /* Check if we have write access in the directory */
1128 if ((slash = strrchr( full_name.long_name, '/' ))) *slash = '\0';
1129 if (access( full_name.long_name, W_OK ) == -1)
1130 WARN("returns %s, which doesn't seem to be writeable.\n",
1131 debugstr_w(buffer) );
1133 TRACE("returning %s\n", debugstr_w(buffer) );
1134 return unique ? unique : num;
1138 /***********************************************************************
1139 * GetTempFileNameA (KERNEL32.@)
1141 UINT WINAPI GetTempFileNameA( LPCSTR path, LPCSTR prefix, UINT unique,
1142 LPSTR buffer)
1144 UNICODE_STRING pathW, prefixW;
1145 WCHAR bufferW[MAX_PATH];
1146 UINT ret;
1148 if ( !path || !prefix || !buffer )
1150 SetLastError( ERROR_INVALID_PARAMETER );
1151 return 0;
1154 RtlCreateUnicodeStringFromAsciiz(&pathW, path);
1155 RtlCreateUnicodeStringFromAsciiz(&prefixW, prefix);
1157 ret = GetTempFileNameW(pathW.Buffer, prefixW.Buffer, unique, bufferW);
1158 if (ret)
1159 WideCharToMultiByte(CP_ACP, 0, bufferW, -1, buffer, MAX_PATH, NULL, NULL);
1161 RtlFreeUnicodeString(&pathW);
1162 RtlFreeUnicodeString(&prefixW);
1163 return ret;
1166 /***********************************************************************
1167 * GetTempFileNameW (KERNEL32.@)
1169 UINT WINAPI GetTempFileNameW( LPCWSTR path, LPCWSTR prefix, UINT unique,
1170 LPWSTR buffer )
1172 return FILE_GetTempFileName( path, prefix, unique, buffer );
1176 /***********************************************************************
1177 * FILE_DoOpenFile
1179 * Implementation of OpenFile16() and OpenFile32().
1181 static HFILE FILE_DoOpenFile( LPCSTR name, OFSTRUCT *ofs, UINT mode, BOOL win32 )
1183 HFILE hFileRet;
1184 HANDLE handle;
1185 FILETIME filetime;
1186 WORD filedatetime[2];
1187 DOS_FULL_NAME full_name;
1188 DWORD access, sharing;
1189 WCHAR *p;
1190 WCHAR buffer[MAX_PATH];
1191 LPWSTR nameW;
1193 if (!ofs) return HFILE_ERROR;
1195 TRACE("%s %s %s %s%s%s%s%s%s%s%s%s\n",name,
1196 ((mode & 0x3 )==OF_READ)?"OF_READ":
1197 ((mode & 0x3 )==OF_WRITE)?"OF_WRITE":
1198 ((mode & 0x3 )==OF_READWRITE)?"OF_READWRITE":"unknown",
1199 ((mode & 0x70 )==OF_SHARE_COMPAT)?"OF_SHARE_COMPAT":
1200 ((mode & 0x70 )==OF_SHARE_DENY_NONE)?"OF_SHARE_DENY_NONE":
1201 ((mode & 0x70 )==OF_SHARE_DENY_READ)?"OF_SHARE_DENY_READ":
1202 ((mode & 0x70 )==OF_SHARE_DENY_WRITE)?"OF_SHARE_DENY_WRITE":
1203 ((mode & 0x70 )==OF_SHARE_EXCLUSIVE)?"OF_SHARE_EXCLUSIVE":"unknown",
1204 ((mode & OF_PARSE )==OF_PARSE)?"OF_PARSE ":"",
1205 ((mode & OF_DELETE )==OF_DELETE)?"OF_DELETE ":"",
1206 ((mode & OF_VERIFY )==OF_VERIFY)?"OF_VERIFY ":"",
1207 ((mode & OF_SEARCH )==OF_SEARCH)?"OF_SEARCH ":"",
1208 ((mode & OF_CANCEL )==OF_CANCEL)?"OF_CANCEL ":"",
1209 ((mode & OF_CREATE )==OF_CREATE)?"OF_CREATE ":"",
1210 ((mode & OF_PROMPT )==OF_PROMPT)?"OF_PROMPT ":"",
1211 ((mode & OF_EXIST )==OF_EXIST)?"OF_EXIST ":"",
1212 ((mode & OF_REOPEN )==OF_REOPEN)?"OF_REOPEN ":""
1216 ofs->cBytes = sizeof(OFSTRUCT);
1217 ofs->nErrCode = 0;
1218 if (mode & OF_REOPEN) name = ofs->szPathName;
1220 if (!name) {
1221 ERR("called with `name' set to NULL ! Please debug.\n");
1222 return HFILE_ERROR;
1225 TRACE("%s %04x\n", name, mode );
1227 /* the watcom 10.6 IDE relies on a valid path returned in ofs->szPathName
1228 Are there any cases where getting the path here is wrong?
1229 Uwe Bonnes 1997 Apr 2 */
1230 if (!GetFullPathNameA( name, sizeof(ofs->szPathName),
1231 ofs->szPathName, NULL )) goto error;
1232 FILE_ConvertOFMode( mode, &access, &sharing );
1234 /* OF_PARSE simply fills the structure */
1236 if (mode & OF_PARSE)
1238 ofs->fFixedDisk = (GetDriveType16( ofs->szPathName[0]-'A' )
1239 != DRIVE_REMOVABLE);
1240 TRACE("(%s): OF_PARSE, res = '%s'\n",
1241 name, ofs->szPathName );
1242 return 0;
1245 /* OF_CREATE is completely different from all other options, so
1246 handle it first */
1248 if (mode & OF_CREATE)
1250 if ((handle = CreateFileA( name, GENERIC_READ | GENERIC_WRITE,
1251 sharing, NULL, CREATE_ALWAYS,
1252 FILE_ATTRIBUTE_NORMAL, 0 ))== INVALID_HANDLE_VALUE)
1253 goto error;
1254 goto success;
1257 MultiByteToWideChar(CP_ACP, 0, name, -1, buffer, MAX_PATH);
1258 nameW = buffer;
1260 /* If OF_SEARCH is set, ignore the given path */
1262 if ((mode & OF_SEARCH) && !(mode & OF_REOPEN))
1264 /* First try the file name as is */
1265 if (DOSFS_GetFullName( nameW, TRUE, &full_name )) goto found;
1266 /* Now remove the path */
1267 if (nameW[0] && (nameW[1] == ':')) nameW += 2;
1268 if ((p = strrchrW( nameW, '\\' ))) nameW = p + 1;
1269 if ((p = strrchrW( nameW, '/' ))) nameW = p + 1;
1270 if (!nameW[0]) goto not_found;
1273 /* Now look for the file */
1275 if (!DIR_SearchPath( NULL, nameW, NULL, &full_name, win32 )) goto not_found;
1277 found:
1278 TRACE("found %s = %s\n",
1279 full_name.long_name, debugstr_w(full_name.short_name) );
1280 WideCharToMultiByte(CP_ACP, 0, full_name.short_name, -1,
1281 ofs->szPathName, sizeof(ofs->szPathName), NULL, NULL);
1283 if (mode & OF_DELETE)
1285 handle = FILE_CreateFile( full_name.long_name, GENERIC_READ|GENERIC_WRITE, 0,
1286 NULL, OPEN_EXISTING, 0, 0, TRUE,
1287 GetDriveTypeW( full_name.short_name ) );
1288 if (!handle) goto error;
1289 CloseHandle( handle );
1290 if (unlink( full_name.long_name ) == -1) goto not_found;
1291 TRACE("(%s): OF_DELETE return = OK\n", name);
1292 return 1;
1295 handle = FILE_CreateFile( full_name.long_name, access, sharing,
1296 NULL, OPEN_EXISTING, 0, 0,
1297 DRIVE_GetFlags(full_name.drive) & DRIVE_FAIL_READ_ONLY,
1298 GetDriveTypeW( full_name.short_name ) );
1299 if (!handle) goto not_found;
1301 GetFileTime( handle, NULL, NULL, &filetime );
1302 FileTimeToDosDateTime( &filetime, &filedatetime[0], &filedatetime[1] );
1303 if ((mode & OF_VERIFY) && (mode & OF_REOPEN))
1305 if (ofs->Reserved1 != filedatetime[0] || ofs->Reserved2 != filedatetime[1] )
1307 CloseHandle( handle );
1308 WARN("(%s): OF_VERIFY failed\n", name );
1309 /* FIXME: what error here? */
1310 SetLastError( ERROR_FILE_NOT_FOUND );
1311 goto error;
1314 ofs->Reserved1 = filedatetime[0];
1315 ofs->Reserved2 = filedatetime[1];
1317 success: /* We get here if the open was successful */
1318 TRACE("(%s): OK, return = %p\n", name, handle );
1319 if (win32)
1321 hFileRet = (HFILE)handle;
1322 if (mode & OF_EXIST) /* Return the handle, but close it first */
1323 CloseHandle( handle );
1325 else
1327 hFileRet = Win32HandleToDosFileHandle( handle );
1328 if (hFileRet == HFILE_ERROR16) goto error;
1329 if (mode & OF_EXIST) /* Return the handle, but close it first */
1330 _lclose16( hFileRet );
1332 return hFileRet;
1334 not_found: /* We get here if the file does not exist */
1335 WARN("'%s' not found or sharing violation\n", name );
1336 SetLastError( ERROR_FILE_NOT_FOUND );
1337 /* fall through */
1339 error: /* We get here if there was an error opening the file */
1340 ofs->nErrCode = GetLastError();
1341 WARN("(%s): return = HFILE_ERROR error= %d\n",
1342 name,ofs->nErrCode );
1343 return HFILE_ERROR;
1347 /***********************************************************************
1348 * OpenFile (KERNEL.74)
1349 * OpenFileEx (KERNEL.360)
1351 HFILE16 WINAPI OpenFile16( LPCSTR name, OFSTRUCT *ofs, UINT16 mode )
1353 return FILE_DoOpenFile( name, ofs, mode, FALSE );
1357 /***********************************************************************
1358 * OpenFile (KERNEL32.@)
1360 HFILE WINAPI OpenFile( LPCSTR name, OFSTRUCT *ofs, UINT mode )
1362 return FILE_DoOpenFile( name, ofs, mode, TRUE );
1366 /***********************************************************************
1367 * FILE_InitProcessDosHandles
1369 * Allocates the default DOS handles for a process. Called either by
1370 * Win32HandleToDosFileHandle below or by the DOSVM stuff.
1372 static void FILE_InitProcessDosHandles( void )
1374 HANDLE cp = GetCurrentProcess();
1375 DuplicateHandle(cp, GetStdHandle(STD_INPUT_HANDLE), cp, &dos_handles[0],
1376 0, TRUE, DUPLICATE_SAME_ACCESS);
1377 DuplicateHandle(cp, GetStdHandle(STD_OUTPUT_HANDLE), cp, &dos_handles[1],
1378 0, TRUE, DUPLICATE_SAME_ACCESS);
1379 DuplicateHandle(cp, GetStdHandle(STD_ERROR_HANDLE), cp, &dos_handles[2],
1380 0, TRUE, DUPLICATE_SAME_ACCESS);
1381 DuplicateHandle(cp, GetStdHandle(STD_ERROR_HANDLE), cp, &dos_handles[3],
1382 0, TRUE, DUPLICATE_SAME_ACCESS);
1383 DuplicateHandle(cp, GetStdHandle(STD_ERROR_HANDLE), cp, &dos_handles[4],
1384 0, TRUE, DUPLICATE_SAME_ACCESS);
1387 /***********************************************************************
1388 * Win32HandleToDosFileHandle (KERNEL32.21)
1390 * Allocate a DOS handle for a Win32 handle. The Win32 handle is no
1391 * longer valid after this function (even on failure).
1393 * Note: this is not exactly right, since on Win95 the Win32 handles
1394 * are on top of DOS handles and we do it the other way
1395 * around. Should be good enough though.
1397 HFILE WINAPI Win32HandleToDosFileHandle( HANDLE handle )
1399 int i;
1401 if (!handle || (handle == INVALID_HANDLE_VALUE))
1402 return HFILE_ERROR;
1404 for (i = 5; i < DOS_TABLE_SIZE; i++)
1405 if (!dos_handles[i])
1407 dos_handles[i] = handle;
1408 TRACE("Got %d for h32 %p\n", i, handle );
1409 return (HFILE)i;
1411 CloseHandle( handle );
1412 SetLastError( ERROR_TOO_MANY_OPEN_FILES );
1413 return HFILE_ERROR;
1417 /***********************************************************************
1418 * DosFileHandleToWin32Handle (KERNEL32.20)
1420 * Return the Win32 handle for a DOS handle.
1422 * Note: this is not exactly right, since on Win95 the Win32 handles
1423 * are on top of DOS handles and we do it the other way
1424 * around. Should be good enough though.
1426 HANDLE WINAPI DosFileHandleToWin32Handle( HFILE handle )
1428 HFILE16 hfile = (HFILE16)handle;
1429 if (hfile < 5 && !dos_handles[hfile]) FILE_InitProcessDosHandles();
1430 if ((hfile >= DOS_TABLE_SIZE) || !dos_handles[hfile])
1432 SetLastError( ERROR_INVALID_HANDLE );
1433 return INVALID_HANDLE_VALUE;
1435 return dos_handles[hfile];
1439 /***********************************************************************
1440 * DisposeLZ32Handle (KERNEL32.22)
1442 * Note: this is not entirely correct, we should only close the
1443 * 32-bit handle and not the 16-bit one, but we cannot do
1444 * this because of the way our DOS handles are implemented.
1445 * It shouldn't break anything though.
1447 void WINAPI DisposeLZ32Handle( HANDLE handle )
1449 int i;
1451 if (!handle || (handle == INVALID_HANDLE_VALUE)) return;
1453 for (i = 5; i < DOS_TABLE_SIZE; i++)
1454 if (dos_handles[i] == handle)
1456 dos_handles[i] = 0;
1457 CloseHandle( handle );
1458 break;
1463 /***********************************************************************
1464 * FILE_Dup2
1466 * dup2() function for DOS handles.
1468 HFILE16 FILE_Dup2( HFILE16 hFile1, HFILE16 hFile2 )
1470 HANDLE new_handle;
1472 if (hFile1 < 5 && !dos_handles[hFile1]) FILE_InitProcessDosHandles();
1474 if ((hFile1 >= DOS_TABLE_SIZE) || (hFile2 >= DOS_TABLE_SIZE) || !dos_handles[hFile1])
1476 SetLastError( ERROR_INVALID_HANDLE );
1477 return HFILE_ERROR16;
1479 if (!DuplicateHandle( GetCurrentProcess(), dos_handles[hFile1],
1480 GetCurrentProcess(), &new_handle,
1481 0, FALSE, DUPLICATE_SAME_ACCESS ))
1482 return HFILE_ERROR16;
1483 if (dos_handles[hFile2]) CloseHandle( dos_handles[hFile2] );
1484 dos_handles[hFile2] = new_handle;
1485 return hFile2;
1489 /***********************************************************************
1490 * _lclose (KERNEL.81)
1492 HFILE16 WINAPI _lclose16( HFILE16 hFile )
1494 if ((hFile >= DOS_TABLE_SIZE) || !dos_handles[hFile])
1496 SetLastError( ERROR_INVALID_HANDLE );
1497 return HFILE_ERROR16;
1499 TRACE("%d (handle32=%p)\n", hFile, dos_handles[hFile] );
1500 CloseHandle( dos_handles[hFile] );
1501 dos_handles[hFile] = 0;
1502 return 0;
1506 /******************************************************************
1507 * FILE_ReadWriteApc (internal)
1511 static void WINAPI FILE_ReadWriteApc(void* apc_user, PIO_STATUS_BLOCK io_status, ULONG len)
1513 LPOVERLAPPED_COMPLETION_ROUTINE cr = (LPOVERLAPPED_COMPLETION_ROUTINE)apc_user;
1515 cr(RtlNtStatusToDosError(io_status->u.Status), len, (LPOVERLAPPED)io_status);
1518 /***********************************************************************
1519 * ReadFileEx (KERNEL32.@)
1521 BOOL WINAPI ReadFileEx(HANDLE hFile, LPVOID buffer, DWORD bytesToRead,
1522 LPOVERLAPPED overlapped,
1523 LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine)
1525 LARGE_INTEGER offset;
1526 NTSTATUS status;
1527 PIO_STATUS_BLOCK io_status;
1529 if (!overlapped)
1531 SetLastError(ERROR_INVALID_PARAMETER);
1532 return FALSE;
1535 offset.s.LowPart = overlapped->Offset;
1536 offset.s.HighPart = overlapped->OffsetHigh;
1537 io_status = (PIO_STATUS_BLOCK)overlapped;
1538 io_status->u.Status = STATUS_PENDING;
1540 status = NtReadFile(hFile, NULL, FILE_ReadWriteApc, lpCompletionRoutine,
1541 io_status, buffer, bytesToRead, &offset, NULL);
1543 if (status)
1545 SetLastError( RtlNtStatusToDosError(status) );
1546 return FALSE;
1548 return TRUE;
1551 /***********************************************************************
1552 * ReadFile (KERNEL32.@)
1554 BOOL WINAPI ReadFile( HANDLE hFile, LPVOID buffer, DWORD bytesToRead,
1555 LPDWORD bytesRead, LPOVERLAPPED overlapped )
1557 LARGE_INTEGER offset;
1558 PLARGE_INTEGER poffset = NULL;
1559 IO_STATUS_BLOCK iosb;
1560 PIO_STATUS_BLOCK io_status = &iosb;
1561 HANDLE hEvent = 0;
1562 NTSTATUS status;
1564 TRACE("%p %p %ld %p %p\n", hFile, buffer, bytesToRead,
1565 bytesRead, overlapped );
1567 if (bytesRead) *bytesRead = 0; /* Do this before anything else */
1568 if (!bytesToRead) return TRUE;
1570 if (IsBadReadPtr(buffer, bytesToRead))
1572 SetLastError(ERROR_WRITE_FAULT); /* FIXME */
1573 return FALSE;
1575 if (is_console_handle(hFile))
1576 return FILE_ReadConsole(hFile, buffer, bytesToRead, bytesRead, NULL);
1578 if (overlapped != NULL)
1580 offset.s.LowPart = overlapped->Offset;
1581 offset.s.HighPart = overlapped->OffsetHigh;
1582 poffset = &offset;
1583 hEvent = overlapped->hEvent;
1584 io_status = (PIO_STATUS_BLOCK)overlapped;
1586 io_status->u.Status = STATUS_PENDING;
1587 io_status->Information = 0;
1589 status = NtReadFile(hFile, hEvent, NULL, NULL, io_status, buffer, bytesToRead, poffset, NULL);
1591 if (status != STATUS_PENDING && bytesRead)
1592 *bytesRead = io_status->Information;
1594 if (status && status != STATUS_END_OF_FILE)
1596 SetLastError( RtlNtStatusToDosError(status) );
1597 return FALSE;
1599 return TRUE;
1603 /***********************************************************************
1604 * WriteFileEx (KERNEL32.@)
1606 BOOL WINAPI WriteFileEx(HANDLE hFile, LPCVOID buffer, DWORD bytesToWrite,
1607 LPOVERLAPPED overlapped,
1608 LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine)
1610 LARGE_INTEGER offset;
1611 NTSTATUS status;
1612 PIO_STATUS_BLOCK io_status;
1614 TRACE("%p %p %ld %p %p\n",
1615 hFile, buffer, bytesToWrite, overlapped, lpCompletionRoutine);
1617 if (overlapped == NULL)
1619 SetLastError(ERROR_INVALID_PARAMETER);
1620 return FALSE;
1622 offset.s.LowPart = overlapped->Offset;
1623 offset.s.HighPart = overlapped->OffsetHigh;
1625 io_status = (PIO_STATUS_BLOCK)overlapped;
1626 io_status->u.Status = STATUS_PENDING;
1628 status = NtWriteFile(hFile, NULL, FILE_ReadWriteApc, lpCompletionRoutine,
1629 io_status, buffer, bytesToWrite, &offset, NULL);
1631 if (status) SetLastError( RtlNtStatusToDosError(status) );
1632 return !status;
1635 /***********************************************************************
1636 * WriteFile (KERNEL32.@)
1638 BOOL WINAPI WriteFile( HANDLE hFile, LPCVOID buffer, DWORD bytesToWrite,
1639 LPDWORD bytesWritten, LPOVERLAPPED overlapped )
1641 HANDLE hEvent = NULL;
1642 LARGE_INTEGER offset;
1643 PLARGE_INTEGER poffset = NULL;
1644 NTSTATUS status;
1645 IO_STATUS_BLOCK iosb;
1646 PIO_STATUS_BLOCK piosb = &iosb;
1648 TRACE("%p %p %ld %p %p\n",
1649 hFile, buffer, bytesToWrite, bytesWritten, overlapped );
1651 if (is_console_handle(hFile))
1652 return FILE_WriteConsole(hFile, buffer, bytesToWrite, bytesWritten, NULL);
1654 if (IsBadReadPtr(buffer, bytesToWrite))
1656 SetLastError(ERROR_READ_FAULT); /* FIXME */
1657 return FALSE;
1660 if (overlapped)
1662 offset.s.LowPart = overlapped->Offset;
1663 offset.s.HighPart = overlapped->OffsetHigh;
1664 poffset = &offset;
1665 hEvent = overlapped->hEvent;
1666 piosb = (PIO_STATUS_BLOCK)overlapped;
1668 piosb->u.Status = STATUS_PENDING;
1669 piosb->Information = 0;
1671 status = NtWriteFile(hFile, hEvent, NULL, NULL, piosb,
1672 buffer, bytesToWrite, poffset, NULL);
1673 if (status)
1675 SetLastError( RtlNtStatusToDosError(status) );
1676 return FALSE;
1678 if (bytesWritten) *bytesWritten = piosb->Information;
1680 return TRUE;
1684 /***********************************************************************
1685 * SetFilePointer (KERNEL32.@)
1687 DWORD WINAPI SetFilePointer( HANDLE hFile, LONG distance, LONG *highword,
1688 DWORD method )
1690 DWORD ret = INVALID_SET_FILE_POINTER;
1692 TRACE("handle %p offset %ld high %ld origin %ld\n",
1693 hFile, distance, highword?*highword:0, method );
1695 SERVER_START_REQ( set_file_pointer )
1697 req->handle = hFile;
1698 req->low = distance;
1699 req->high = highword ? *highword : (distance >= 0) ? 0 : -1;
1700 /* FIXME: assumes 1:1 mapping between Windows and Unix seek constants */
1701 req->whence = method;
1702 SetLastError( 0 );
1703 if (!wine_server_call_err( req ))
1705 ret = reply->new_low;
1706 if (highword) *highword = reply->new_high;
1709 SERVER_END_REQ;
1710 return ret;
1714 /*************************************************************************
1715 * SetHandleCount (KERNEL32.@)
1717 UINT WINAPI SetHandleCount( UINT count )
1719 return min( 256, count );
1723 /**************************************************************************
1724 * SetEndOfFile (KERNEL32.@)
1726 BOOL WINAPI SetEndOfFile( HANDLE hFile )
1728 BOOL ret;
1729 SERVER_START_REQ( truncate_file )
1731 req->handle = hFile;
1732 ret = !wine_server_call_err( req );
1734 SERVER_END_REQ;
1735 return ret;
1739 /***********************************************************************
1740 * DeleteFileW (KERNEL32.@)
1742 BOOL WINAPI DeleteFileW( LPCWSTR path )
1744 DOS_FULL_NAME full_name;
1745 HANDLE hFile;
1747 TRACE("%s\n", debugstr_w(path) );
1748 if (!path || !*path)
1750 SetLastError(ERROR_PATH_NOT_FOUND);
1751 return FALSE;
1753 if (DOSFS_GetDevice( path ))
1755 WARN("cannot remove DOS device %s!\n", debugstr_w(path));
1756 SetLastError( ERROR_FILE_NOT_FOUND );
1757 return FALSE;
1760 if (!DOSFS_GetFullName( path, TRUE, &full_name )) return FALSE;
1762 /* check if we are allowed to delete the source */
1763 hFile = FILE_CreateFile( full_name.long_name, GENERIC_READ|GENERIC_WRITE, 0,
1764 NULL, OPEN_EXISTING, 0, 0, TRUE,
1765 GetDriveTypeW( full_name.short_name ) );
1766 if (!hFile) return FALSE;
1768 if (unlink( full_name.long_name ) == -1)
1770 FILE_SetDosError();
1771 CloseHandle(hFile);
1772 return FALSE;
1774 CloseHandle(hFile);
1775 return TRUE;
1779 /***********************************************************************
1780 * DeleteFileA (KERNEL32.@)
1782 BOOL WINAPI DeleteFileA( LPCSTR path )
1784 UNICODE_STRING pathW;
1785 BOOL ret = FALSE;
1787 if (!path)
1789 SetLastError(ERROR_INVALID_PARAMETER);
1790 return FALSE;
1793 if (RtlCreateUnicodeStringFromAsciiz(&pathW, path))
1795 ret = DeleteFileW(pathW.Buffer);
1796 RtlFreeUnicodeString(&pathW);
1798 else
1799 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1800 return ret;
1804 /***********************************************************************
1805 * GetFileType (KERNEL32.@)
1807 DWORD WINAPI GetFileType( HANDLE hFile )
1809 DWORD ret = FILE_TYPE_UNKNOWN;
1811 if (is_console_handle( hFile ))
1812 return FILE_TYPE_CHAR;
1814 SERVER_START_REQ( get_file_info )
1816 req->handle = hFile;
1817 if (!wine_server_call_err( req )) ret = reply->type;
1819 SERVER_END_REQ;
1820 return ret;
1824 /* check if a file name is for an executable file (.exe or .com) */
1825 inline static BOOL is_executable( const char *name )
1827 int len = strlen(name);
1829 if (len < 4) return FALSE;
1830 return (!strcasecmp( name + len - 4, ".exe" ) ||
1831 !strcasecmp( name + len - 4, ".com" ));
1835 /***********************************************************************
1836 * FILE_AddBootRenameEntry
1838 * Adds an entry to the registry that is loaded when windows boots and
1839 * checks if there are some files to be removed or renamed/moved.
1840 * <fn1> has to be valid and <fn2> may be NULL. If both pointers are
1841 * non-NULL then the file is moved, otherwise it is deleted. The
1842 * entry of the registrykey is always appended with two zero
1843 * terminated strings. If <fn2> is NULL then the second entry is
1844 * simply a single 0-byte. Otherwise the second filename goes
1845 * there. The entries are prepended with \??\ before the path and the
1846 * second filename gets also a '!' as the first character if
1847 * MOVEFILE_REPLACE_EXISTING is set. After the final string another
1848 * 0-byte follows to indicate the end of the strings.
1849 * i.e.:
1850 * \??\D:\test\file1[0]
1851 * !\??\D:\test\file1_renamed[0]
1852 * \??\D:\Test|delete[0]
1853 * [0] <- file is to be deleted, second string empty
1854 * \??\D:\test\file2[0]
1855 * !\??\D:\test\file2_renamed[0]
1856 * [0] <- indicates end of strings
1858 * or:
1859 * \??\D:\test\file1[0]
1860 * !\??\D:\test\file1_renamed[0]
1861 * \??\D:\Test|delete[0]
1862 * [0] <- file is to be deleted, second string empty
1863 * [0] <- indicates end of strings
1866 static BOOL FILE_AddBootRenameEntry( LPCWSTR fn1, LPCWSTR fn2, DWORD flags )
1868 static const WCHAR PreString[] = {'\\','?','?','\\',0};
1869 static const WCHAR ValueName[] = {'P','e','n','d','i','n','g',
1870 'F','i','l','e','R','e','n','a','m','e',
1871 'O','p','e','r','a','t','i','o','n','s',0};
1872 static const WCHAR SessionW[] = {'M','a','c','h','i','n','e','\\',
1873 'S','y','s','t','e','m','\\',
1874 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
1875 'C','o','n','t','r','o','l','\\',
1876 'S','e','s','s','i','o','n',' ','M','a','n','a','g','e','r',0};
1877 static const int info_size = FIELD_OFFSET( KEY_VALUE_PARTIAL_INFORMATION, Data );
1879 OBJECT_ATTRIBUTES attr;
1880 UNICODE_STRING nameW;
1881 KEY_VALUE_PARTIAL_INFORMATION *info;
1882 BOOL rc = FALSE;
1883 HKEY Reboot = 0;
1884 DWORD len0, len1, len2;
1885 DWORD DataSize = 0;
1886 BYTE *Buffer = NULL;
1887 WCHAR *p;
1889 attr.Length = sizeof(attr);
1890 attr.RootDirectory = 0;
1891 attr.ObjectName = &nameW;
1892 attr.Attributes = 0;
1893 attr.SecurityDescriptor = NULL;
1894 attr.SecurityQualityOfService = NULL;
1895 RtlInitUnicodeString( &nameW, SessionW );
1897 if (NtCreateKey( &Reboot, KEY_ALL_ACCESS, &attr, 0, NULL, 0, NULL ) != STATUS_SUCCESS)
1899 WARN("Error creating key for reboot managment [%s]\n",
1900 "SYSTEM\\CurrentControlSet\\Control\\Session Manager");
1901 return FALSE;
1904 len0 = strlenW(PreString);
1905 len1 = strlenW(fn1) + len0 + 1;
1906 if (fn2)
1908 len2 = strlenW(fn2) + len0 + 1;
1909 if (flags & MOVEFILE_REPLACE_EXISTING) len2++; /* Plus 1 because of the leading '!' */
1911 else len2 = 1; /* minimum is the 0 characters for the empty second string */
1913 /* convert characters to bytes */
1914 len0 *= sizeof(WCHAR);
1915 len1 *= sizeof(WCHAR);
1916 len2 *= sizeof(WCHAR);
1918 RtlInitUnicodeString( &nameW, ValueName );
1920 /* First we check if the key exists and if so how many bytes it already contains. */
1921 if (NtQueryValueKey( Reboot, &nameW, KeyValuePartialInformation,
1922 NULL, 0, &DataSize ) == STATUS_BUFFER_OVERFLOW)
1924 if (!(Buffer = HeapAlloc( GetProcessHeap(), 0, DataSize + len1 + len2 + sizeof(WCHAR) )))
1925 goto Quit;
1926 if (NtQueryValueKey( Reboot, &nameW, KeyValuePartialInformation,
1927 Buffer, DataSize, &DataSize )) goto Quit;
1928 info = (KEY_VALUE_PARTIAL_INFORMATION *)Buffer;
1929 if (info->Type != REG_MULTI_SZ) goto Quit;
1930 if (DataSize > sizeof(info)) DataSize -= sizeof(WCHAR); /* remove terminating null (will be added back later) */
1932 else
1934 DataSize = info_size;
1935 if (!(Buffer = HeapAlloc( GetProcessHeap(), 0, DataSize + len1 + len2 + sizeof(WCHAR) )))
1936 goto Quit;
1939 p = (WCHAR *)(Buffer + DataSize);
1940 strcpyW( p, PreString );
1941 strcatW( p, fn1 );
1942 DataSize += len1;
1943 if (fn2)
1945 p = (WCHAR *)(Buffer + DataSize);
1946 if (flags & MOVEFILE_REPLACE_EXISTING)
1947 *p++ = '!';
1948 strcpyW( p, PreString );
1949 strcatW( p, fn2 );
1950 DataSize += len2;
1952 else
1954 p = (WCHAR *)(Buffer + DataSize);
1955 *p = 0;
1956 DataSize += sizeof(WCHAR);
1959 /* add final null */
1960 p = (WCHAR *)(Buffer + DataSize);
1961 *p = 0;
1962 DataSize += sizeof(WCHAR);
1964 rc = !NtSetValueKey(Reboot, &nameW, 0, REG_MULTI_SZ, Buffer + info_size, DataSize - info_size);
1966 Quit:
1967 if (Reboot) NtClose(Reboot);
1968 if (Buffer) HeapFree( GetProcessHeap(), 0, Buffer );
1969 return(rc);
1973 /**************************************************************************
1974 * MoveFileExW (KERNEL32.@)
1976 BOOL WINAPI MoveFileExW( LPCWSTR fn1, LPCWSTR fn2, DWORD flag )
1978 DOS_FULL_NAME full_name1, full_name2;
1979 HANDLE hFile;
1980 DWORD attr = INVALID_FILE_ATTRIBUTES;
1982 TRACE("(%s,%s,%04lx)\n", debugstr_w(fn1), debugstr_w(fn2), flag);
1984 /* FIXME: <Gerhard W. Gruber>sparhawk@gmx.at
1985 In case of W9x and lesser this function should return 120 (ERROR_CALL_NOT_IMPLEMENTED)
1986 to be really compatible. Most programs wont have any problems though. In case
1987 you encounter one, this is what you should return here. I don't know what's up
1988 with NT 3.5. Is this function available there or not?
1989 Does anybody really care about 3.5? :)
1992 /* Filename1 has to be always set to a valid path. Filename2 may be NULL
1993 if the source file has to be deleted.
1995 if (!fn1) {
1996 SetLastError(ERROR_INVALID_PARAMETER);
1997 return FALSE;
2000 /* This function has to be run through in order to process the name properly.
2001 If the BOOTDELAY flag is set, the file doesn't need to exist though. At least
2002 that is the behaviour on NT 4.0. The operation accepts the filenames as
2003 they are given but it can't reply with a reasonable returncode. Success
2004 means in that case success for entering the values into the registry.
2006 if(!DOSFS_GetFullName( fn1, TRUE, &full_name1 ))
2008 if(!(flag & MOVEFILE_DELAY_UNTIL_REBOOT))
2009 return FALSE;
2012 if (fn2) /* !fn2 means delete fn1 */
2014 if (DOSFS_GetFullName( fn2, TRUE, &full_name2 ))
2016 if(!(flag & MOVEFILE_DELAY_UNTIL_REBOOT))
2018 /* target exists, check if we may overwrite */
2019 if (!(flag & MOVEFILE_REPLACE_EXISTING))
2021 SetLastError( ERROR_FILE_EXISTS );
2022 return FALSE;
2026 else
2028 if (!DOSFS_GetFullName( fn2, FALSE, &full_name2 ))
2030 if(!(flag & MOVEFILE_DELAY_UNTIL_REBOOT))
2031 return FALSE;
2035 /* Source name and target path are valid */
2037 if (flag & MOVEFILE_DELAY_UNTIL_REBOOT)
2039 return FILE_AddBootRenameEntry( fn1, fn2, flag );
2042 attr = GetFileAttributesW( fn1 );
2043 if ( attr == INVALID_FILE_ATTRIBUTES ) return FALSE;
2045 /* check if we are allowed to rename the source */
2046 hFile = FILE_CreateFile( full_name1.long_name, 0, 0,
2047 NULL, OPEN_EXISTING, 0, 0, TRUE,
2048 GetDriveTypeW( full_name1.short_name ) );
2049 if (!hFile)
2051 if (GetLastError() != ERROR_ACCESS_DENIED) return FALSE;
2052 if ( !(attr & FILE_ATTRIBUTE_DIRECTORY) ) return FALSE;
2053 /* if it's a directory we can continue */
2055 else CloseHandle(hFile);
2057 /* check, if we are allowed to delete the destination,
2058 ** (but the file not being there is fine) */
2059 hFile = FILE_CreateFile( full_name2.long_name, GENERIC_READ|GENERIC_WRITE, 0,
2060 NULL, OPEN_EXISTING, 0, 0, TRUE,
2061 GetDriveTypeW( full_name2.short_name ) );
2062 if(!hFile && GetLastError() != ERROR_FILE_NOT_FOUND) return FALSE;
2063 CloseHandle(hFile);
2065 if (full_name1.drive != full_name2.drive)
2067 if (!(flag & MOVEFILE_COPY_ALLOWED))
2069 SetLastError( ERROR_NOT_SAME_DEVICE );
2070 return FALSE;
2072 else if ( attr & FILE_ATTRIBUTE_DIRECTORY )
2074 /* Strange, but that's what Windows returns */
2075 SetLastError ( ERROR_ACCESS_DENIED );
2076 return FALSE;
2079 if (rename( full_name1.long_name, full_name2.long_name ) == -1)
2080 /* Try copy/delete unless it's a directory. */
2081 /* FIXME: This does not handle the (unlikely) case that the two locations
2082 are on the same Wine drive, but on different Unix file systems. */
2084 if ( attr & FILE_ATTRIBUTE_DIRECTORY )
2086 FILE_SetDosError();
2087 return FALSE;
2089 else
2091 if ( ! CopyFileW( fn1, fn2, !(flag & MOVEFILE_REPLACE_EXISTING) ))
2092 return FALSE;
2093 if ( ! DeleteFileW ( fn1 ) )
2094 return FALSE;
2097 if (is_executable( full_name1.long_name ) != is_executable( full_name2.long_name ))
2099 struct stat fstat;
2100 if (stat( full_name2.long_name, &fstat ) != -1)
2102 if (is_executable( full_name2.long_name ))
2103 /* set executable bit where read bit is set */
2104 fstat.st_mode |= (fstat.st_mode & 0444) >> 2;
2105 else
2106 fstat.st_mode &= ~0111;
2107 chmod( full_name2.long_name, fstat.st_mode );
2110 return TRUE;
2112 else /* fn2 == NULL means delete source */
2114 if (flag & MOVEFILE_DELAY_UNTIL_REBOOT)
2116 if (flag & MOVEFILE_COPY_ALLOWED) {
2117 WARN("Illegal flag\n");
2118 SetLastError( ERROR_GEN_FAILURE );
2119 return FALSE;
2122 return FILE_AddBootRenameEntry( fn1, NULL, flag );
2125 if (unlink( full_name1.long_name ) == -1)
2127 FILE_SetDosError();
2128 return FALSE;
2130 return TRUE; /* successfully deleted */
2134 /**************************************************************************
2135 * MoveFileExA (KERNEL32.@)
2137 BOOL WINAPI MoveFileExA( LPCSTR fn1, LPCSTR fn2, DWORD flag )
2139 UNICODE_STRING fn1W, fn2W;
2140 BOOL ret;
2142 if (!fn1)
2144 SetLastError(ERROR_INVALID_PARAMETER);
2145 return FALSE;
2148 RtlCreateUnicodeStringFromAsciiz(&fn1W, fn1);
2149 if (fn2) RtlCreateUnicodeStringFromAsciiz(&fn2W, fn2);
2150 else fn2W.Buffer = NULL;
2152 ret = MoveFileExW( fn1W.Buffer, fn2W.Buffer, flag );
2154 RtlFreeUnicodeString(&fn1W);
2155 RtlFreeUnicodeString(&fn2W);
2156 return ret;
2160 /**************************************************************************
2161 * MoveFileW (KERNEL32.@)
2163 * Move file or directory
2165 BOOL WINAPI MoveFileW( LPCWSTR fn1, LPCWSTR fn2 )
2167 return MoveFileExW( fn1, fn2, MOVEFILE_COPY_ALLOWED );
2171 /**************************************************************************
2172 * MoveFileA (KERNEL32.@)
2174 BOOL WINAPI MoveFileA( LPCSTR fn1, LPCSTR fn2 )
2176 return MoveFileExA( fn1, fn2, MOVEFILE_COPY_ALLOWED );
2180 /**************************************************************************
2181 * CopyFileW (KERNEL32.@)
2183 BOOL WINAPI CopyFileW( LPCWSTR source, LPCWSTR dest, BOOL fail_if_exists )
2185 HANDLE h1, h2;
2186 BY_HANDLE_FILE_INFORMATION info;
2187 DWORD count;
2188 BOOL ret = FALSE;
2189 char buffer[2048];
2191 if (!source || !dest)
2193 SetLastError(ERROR_INVALID_PARAMETER);
2194 return FALSE;
2197 TRACE("%s -> %s\n", debugstr_w(source), debugstr_w(dest));
2199 if ((h1 = CreateFileW(source, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE,
2200 NULL, OPEN_EXISTING, 0, 0)) == INVALID_HANDLE_VALUE)
2202 WARN("Unable to open source %s\n", debugstr_w(source));
2203 return FALSE;
2206 if (!GetFileInformationByHandle( h1, &info ))
2208 WARN("GetFileInformationByHandle returned error for %s\n", debugstr_w(source));
2209 CloseHandle( h1 );
2210 return FALSE;
2213 if ((h2 = CreateFileW( dest, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
2214 fail_if_exists ? CREATE_NEW : CREATE_ALWAYS,
2215 info.dwFileAttributes, h1 )) == INVALID_HANDLE_VALUE)
2217 WARN("Unable to open dest %s\n", debugstr_w(dest));
2218 CloseHandle( h1 );
2219 return FALSE;
2222 while (ReadFile( h1, buffer, sizeof(buffer), &count, NULL ) && count)
2224 char *p = buffer;
2225 while (count != 0)
2227 DWORD res;
2228 if (!WriteFile( h2, p, count, &res, NULL ) || !res) goto done;
2229 p += res;
2230 count -= res;
2233 ret = TRUE;
2234 done:
2235 CloseHandle( h1 );
2236 CloseHandle( h2 );
2237 return ret;
2241 /**************************************************************************
2242 * CopyFileA (KERNEL32.@)
2244 BOOL WINAPI CopyFileA( LPCSTR source, LPCSTR dest, BOOL fail_if_exists)
2246 UNICODE_STRING sourceW, destW;
2247 BOOL ret;
2249 if (!source || !dest)
2251 SetLastError(ERROR_INVALID_PARAMETER);
2252 return FALSE;
2255 RtlCreateUnicodeStringFromAsciiz(&sourceW, source);
2256 RtlCreateUnicodeStringFromAsciiz(&destW, dest);
2258 ret = CopyFileW(sourceW.Buffer, destW.Buffer, fail_if_exists);
2260 RtlFreeUnicodeString(&sourceW);
2261 RtlFreeUnicodeString(&destW);
2262 return ret;
2266 /**************************************************************************
2267 * CopyFileExW (KERNEL32.@)
2269 * This implementation ignores most of the extra parameters passed-in into
2270 * the "ex" version of the method and calls the CopyFile method.
2271 * It will have to be fixed eventually.
2273 BOOL WINAPI CopyFileExW(LPCWSTR sourceFilename, LPCWSTR destFilename,
2274 LPPROGRESS_ROUTINE progressRoutine, LPVOID appData,
2275 LPBOOL cancelFlagPointer, DWORD copyFlags)
2278 * Interpret the only flag that CopyFile can interpret.
2280 return CopyFileW(sourceFilename, destFilename, (copyFlags & COPY_FILE_FAIL_IF_EXISTS) != 0);
2284 /**************************************************************************
2285 * CopyFileExA (KERNEL32.@)
2287 BOOL WINAPI CopyFileExA(LPCSTR sourceFilename, LPCSTR destFilename,
2288 LPPROGRESS_ROUTINE progressRoutine, LPVOID appData,
2289 LPBOOL cancelFlagPointer, DWORD copyFlags)
2291 UNICODE_STRING sourceW, destW;
2292 BOOL ret;
2294 if (!sourceFilename || !destFilename)
2296 SetLastError(ERROR_INVALID_PARAMETER);
2297 return FALSE;
2300 RtlCreateUnicodeStringFromAsciiz(&sourceW, sourceFilename);
2301 RtlCreateUnicodeStringFromAsciiz(&destW, destFilename);
2303 ret = CopyFileExW(sourceW.Buffer, destW.Buffer, progressRoutine, appData,
2304 cancelFlagPointer, copyFlags);
2306 RtlFreeUnicodeString(&sourceW);
2307 RtlFreeUnicodeString(&destW);
2308 return ret;
2312 /***********************************************************************
2313 * SetFileTime (KERNEL32.@)
2315 BOOL WINAPI SetFileTime( HANDLE hFile,
2316 const FILETIME *lpCreationTime,
2317 const FILETIME *lpLastAccessTime,
2318 const FILETIME *lpLastWriteTime )
2320 BOOL ret;
2321 SERVER_START_REQ( set_file_time )
2323 req->handle = hFile;
2324 if (lpLastAccessTime)
2325 RtlTimeToSecondsSince1970( (PLARGE_INTEGER) lpLastAccessTime, (DWORD *)&req->access_time );
2326 else
2327 req->access_time = 0; /* FIXME */
2328 if (lpLastWriteTime)
2329 RtlTimeToSecondsSince1970( (PLARGE_INTEGER) lpLastWriteTime, (DWORD *)&req->write_time );
2330 else
2331 req->write_time = 0; /* FIXME */
2332 ret = !wine_server_call_err( req );
2334 SERVER_END_REQ;
2335 return ret;
2339 /**************************************************************************
2340 * GetFileAttributesExW (KERNEL32.@)
2342 BOOL WINAPI GetFileAttributesExW(
2343 LPCWSTR lpFileName, GET_FILEEX_INFO_LEVELS fInfoLevelId,
2344 LPVOID lpFileInformation)
2346 DOS_FULL_NAME full_name;
2347 BY_HANDLE_FILE_INFORMATION info;
2349 if (!lpFileName || !lpFileInformation)
2351 SetLastError(ERROR_INVALID_PARAMETER);
2352 return FALSE;
2355 if (fInfoLevelId == GetFileExInfoStandard) {
2356 LPWIN32_FILE_ATTRIBUTE_DATA lpFad =
2357 (LPWIN32_FILE_ATTRIBUTE_DATA) lpFileInformation;
2358 if (!DOSFS_GetFullName( lpFileName, TRUE, &full_name )) return FALSE;
2359 if (!FILE_Stat( full_name.long_name, &info, NULL )) return FALSE;
2361 lpFad->dwFileAttributes = info.dwFileAttributes;
2362 lpFad->ftCreationTime = info.ftCreationTime;
2363 lpFad->ftLastAccessTime = info.ftLastAccessTime;
2364 lpFad->ftLastWriteTime = info.ftLastWriteTime;
2365 lpFad->nFileSizeHigh = info.nFileSizeHigh;
2366 lpFad->nFileSizeLow = info.nFileSizeLow;
2368 else {
2369 FIXME("invalid info level %d!\n", fInfoLevelId);
2370 return FALSE;
2373 return TRUE;
2377 /**************************************************************************
2378 * GetFileAttributesExA (KERNEL32.@)
2380 BOOL WINAPI GetFileAttributesExA(
2381 LPCSTR filename, GET_FILEEX_INFO_LEVELS fInfoLevelId,
2382 LPVOID lpFileInformation)
2384 UNICODE_STRING filenameW;
2385 BOOL ret = FALSE;
2387 if (!filename || !lpFileInformation)
2389 SetLastError(ERROR_INVALID_PARAMETER);
2390 return FALSE;
2393 if (RtlCreateUnicodeStringFromAsciiz(&filenameW, filename))
2395 ret = GetFileAttributesExW(filenameW.Buffer, fInfoLevelId, lpFileInformation);
2396 RtlFreeUnicodeString(&filenameW);
2398 else
2399 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
2400 return ret;