Remove unused variables EXE, BAT, CMD, and COM.
[wine/multimedia.git] / files / file.c
blobc366b98b2cdcf2a913c15983b53a3f40e1c74a1a
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->removable = (drive_type == DRIVE_REMOVABLE || drive_type == DRIVE_CDROM);
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 INVALID_FILE_ATTRIBUTES;
860 if (!DOSFS_GetFullName( name, TRUE, &full_name) )
861 return INVALID_FILE_ATTRIBUTES;
862 if (!FILE_Stat( full_name.long_name, &info, NULL ))
863 return INVALID_FILE_ATTRIBUTES;
864 return info.dwFileAttributes;
868 /**************************************************************************
869 * GetFileAttributesA (KERNEL32.@)
871 DWORD WINAPI GetFileAttributesA( LPCSTR name )
873 UNICODE_STRING nameW;
874 DWORD ret = INVALID_FILE_ATTRIBUTES;
876 if (!name)
878 SetLastError( ERROR_INVALID_PARAMETER );
879 return INVALID_FILE_ATTRIBUTES;
882 if (RtlCreateUnicodeStringFromAsciiz(&nameW, name))
884 ret = GetFileAttributesW(nameW.Buffer);
885 RtlFreeUnicodeString(&nameW);
887 else
888 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
889 return ret;
893 /**************************************************************************
894 * SetFileAttributesW (KERNEL32.@)
896 BOOL WINAPI SetFileAttributesW(LPCWSTR lpFileName, DWORD attributes)
898 struct stat buf;
899 DOS_FULL_NAME full_name;
901 if (!lpFileName)
903 SetLastError( ERROR_INVALID_PARAMETER );
904 return FALSE;
907 TRACE("(%s,%lx)\n", debugstr_w(lpFileName), attributes);
909 if (!DOSFS_GetFullName( lpFileName, TRUE, &full_name ))
910 return FALSE;
912 if(stat(full_name.long_name,&buf)==-1)
914 FILE_SetDosError();
915 return FALSE;
917 if (attributes & FILE_ATTRIBUTE_READONLY)
919 if(S_ISDIR(buf.st_mode))
920 /* FIXME */
921 WARN("FILE_ATTRIBUTE_READONLY ignored for directory.\n");
922 else
923 buf.st_mode &= ~0222; /* octal!, clear write permission bits */
924 attributes &= ~FILE_ATTRIBUTE_READONLY;
926 else
928 /* add write permission */
929 buf.st_mode |= (0600 | ((buf.st_mode & 044) >> 1)) & (~FILE_umask);
931 if (attributes & FILE_ATTRIBUTE_DIRECTORY)
933 if (!S_ISDIR(buf.st_mode))
934 FIXME("SetFileAttributes expected the file %s to be a directory\n",
935 debugstr_w(lpFileName));
936 attributes &= ~FILE_ATTRIBUTE_DIRECTORY;
938 attributes &= ~(FILE_ATTRIBUTE_NORMAL|FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_HIDDEN|FILE_ATTRIBUTE_SYSTEM);
939 if (attributes)
940 FIXME("(%s):%lx attribute(s) not implemented.\n", debugstr_w(lpFileName), attributes);
941 if (-1==chmod(full_name.long_name,buf.st_mode))
943 if (GetDriveTypeW(lpFileName) == DRIVE_CDROM)
945 SetLastError( ERROR_ACCESS_DENIED );
946 return FALSE;
950 * FIXME: We don't return FALSE here because of differences between
951 * Linux and Windows privileges. Under Linux only the owner of
952 * the file is allowed to change file attributes. Under Windows,
953 * applications expect that if you can write to a file, you can also
954 * change its attributes (see GENERIC_WRITE). We could try to be
955 * clever here but that would break multi-user installations where
956 * users share read-only DLLs. This is because some installers like
957 * to change attributes of already installed DLLs.
959 FIXME("Couldn't set file attributes for existing file \"%s\".\n"
960 "Check permissions or set VFAT \"quiet\" mount flag\n", full_name.long_name);
962 return TRUE;
966 /**************************************************************************
967 * SetFileAttributesA (KERNEL32.@)
969 BOOL WINAPI SetFileAttributesA(LPCSTR lpFileName, DWORD attributes)
971 UNICODE_STRING filenameW;
972 BOOL ret = FALSE;
974 if (!lpFileName)
976 SetLastError( ERROR_INVALID_PARAMETER );
977 return FALSE;
980 if (RtlCreateUnicodeStringFromAsciiz(&filenameW, lpFileName))
982 ret = SetFileAttributesW(filenameW.Buffer, attributes);
983 RtlFreeUnicodeString(&filenameW);
985 else
986 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
987 return ret;
991 /******************************************************************************
992 * GetCompressedFileSizeA [KERNEL32.@]
994 DWORD WINAPI GetCompressedFileSizeA(
995 LPCSTR lpFileName,
996 LPDWORD lpFileSizeHigh)
998 UNICODE_STRING filenameW;
999 DWORD ret;
1001 if (RtlCreateUnicodeStringFromAsciiz(&filenameW, lpFileName))
1003 ret = GetCompressedFileSizeW(filenameW.Buffer, lpFileSizeHigh);
1004 RtlFreeUnicodeString(&filenameW);
1006 else
1008 ret = INVALID_FILE_SIZE;
1009 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1011 return ret;
1015 /******************************************************************************
1016 * GetCompressedFileSizeW [KERNEL32.@]
1018 * RETURNS
1019 * Success: Low-order doubleword of number of bytes
1020 * Failure: INVALID_FILE_SIZE
1022 DWORD WINAPI GetCompressedFileSizeW(
1023 LPCWSTR lpFileName, /* [in] Pointer to name of file */
1024 LPDWORD lpFileSizeHigh) /* [out] Receives high-order doubleword of size */
1026 DOS_FULL_NAME full_name;
1027 struct stat st;
1028 DWORD low;
1030 TRACE("(%s,%p)\n",debugstr_w(lpFileName),lpFileSizeHigh);
1032 if (!DOSFS_GetFullName( lpFileName, TRUE, &full_name )) return INVALID_FILE_SIZE;
1033 if (stat(full_name.long_name, &st) != 0)
1035 FILE_SetDosError();
1036 return INVALID_FILE_SIZE;
1038 #if HAVE_STRUCT_STAT_ST_BLOCKS
1039 /* blocks are 512 bytes long */
1040 if (lpFileSizeHigh) *lpFileSizeHigh = (st.st_blocks >> 23);
1041 low = (DWORD)(st.st_blocks << 9);
1042 #else
1043 if (lpFileSizeHigh) *lpFileSizeHigh = (st.st_size >> 32);
1044 low = (DWORD)st.st_size;
1045 #endif
1046 return low;
1050 /***********************************************************************
1051 * GetFileTime (KERNEL32.@)
1053 BOOL WINAPI GetFileTime( HANDLE hFile, FILETIME *lpCreationTime,
1054 FILETIME *lpLastAccessTime,
1055 FILETIME *lpLastWriteTime )
1057 BY_HANDLE_FILE_INFORMATION info;
1058 if (!GetFileInformationByHandle( hFile, &info )) return FALSE;
1059 if (lpCreationTime) *lpCreationTime = info.ftCreationTime;
1060 if (lpLastAccessTime) *lpLastAccessTime = info.ftLastAccessTime;
1061 if (lpLastWriteTime) *lpLastWriteTime = info.ftLastWriteTime;
1062 return TRUE;
1066 /***********************************************************************
1067 * FILE_GetTempFileName : utility for GetTempFileName
1069 static UINT FILE_GetTempFileName( LPCWSTR path, LPCWSTR prefix, UINT unique,
1070 LPWSTR buffer )
1072 static UINT unique_temp;
1073 DOS_FULL_NAME full_name;
1074 int i;
1075 LPWSTR p;
1076 UINT num;
1077 char buf[20];
1079 if ( !path || !prefix || !buffer )
1081 SetLastError( ERROR_INVALID_PARAMETER );
1082 return 0;
1085 if (!unique_temp) unique_temp = time(NULL) & 0xffff;
1086 num = unique ? (unique & 0xffff) : (unique_temp++ & 0xffff);
1088 strcpyW( buffer, path );
1089 p = buffer + strlenW(buffer);
1091 /* add a \, if there isn't one and path is more than just the drive letter ... */
1092 if ( !((strlenW(buffer) == 2) && (buffer[1] == ':'))
1093 && ((p == buffer) || (p[-1] != '\\'))) *p++ = '\\';
1095 for (i = 3; (i > 0) && (*prefix); i--) *p++ = *prefix++;
1097 sprintf( buf, "%04x.tmp", num );
1098 MultiByteToWideChar(CP_ACP, 0, buf, -1, p, 20);
1100 /* Now try to create it */
1102 if (!unique)
1106 HANDLE handle = CreateFileW( buffer, GENERIC_WRITE, 0, NULL,
1107 CREATE_NEW, FILE_ATTRIBUTE_NORMAL, 0 );
1108 if (handle != INVALID_HANDLE_VALUE)
1109 { /* We created it */
1110 TRACE("created %s\n", debugstr_w(buffer) );
1111 CloseHandle( handle );
1112 break;
1114 if (GetLastError() != ERROR_FILE_EXISTS &&
1115 GetLastError() != ERROR_SHARING_VIOLATION)
1116 break; /* No need to go on */
1117 num++;
1118 sprintf( buf, "%04x.tmp", num );
1119 MultiByteToWideChar(CP_ACP, 0, buf, -1, p, 20);
1120 } while (num != (unique & 0xffff));
1123 /* Get the full path name */
1125 if (DOSFS_GetFullName( buffer, FALSE, &full_name ))
1127 char *slash;
1128 /* Check if we have write access in the directory */
1129 if ((slash = strrchr( full_name.long_name, '/' ))) *slash = '\0';
1130 if (access( full_name.long_name, W_OK ) == -1)
1131 WARN("returns %s, which doesn't seem to be writeable.\n",
1132 debugstr_w(buffer) );
1134 TRACE("returning %s\n", debugstr_w(buffer) );
1135 return unique ? unique : num;
1139 /***********************************************************************
1140 * GetTempFileNameA (KERNEL32.@)
1142 UINT WINAPI GetTempFileNameA( LPCSTR path, LPCSTR prefix, UINT unique,
1143 LPSTR buffer)
1145 UNICODE_STRING pathW, prefixW;
1146 WCHAR bufferW[MAX_PATH];
1147 UINT ret;
1149 if ( !path || !prefix || !buffer )
1151 SetLastError( ERROR_INVALID_PARAMETER );
1152 return 0;
1155 RtlCreateUnicodeStringFromAsciiz(&pathW, path);
1156 RtlCreateUnicodeStringFromAsciiz(&prefixW, prefix);
1158 ret = GetTempFileNameW(pathW.Buffer, prefixW.Buffer, unique, bufferW);
1159 if (ret)
1160 WideCharToMultiByte(CP_ACP, 0, bufferW, -1, buffer, MAX_PATH, NULL, NULL);
1162 RtlFreeUnicodeString(&pathW);
1163 RtlFreeUnicodeString(&prefixW);
1164 return ret;
1167 /***********************************************************************
1168 * GetTempFileNameW (KERNEL32.@)
1170 UINT WINAPI GetTempFileNameW( LPCWSTR path, LPCWSTR prefix, UINT unique,
1171 LPWSTR buffer )
1173 return FILE_GetTempFileName( path, prefix, unique, buffer );
1177 /***********************************************************************
1178 * FILE_DoOpenFile
1180 * Implementation of OpenFile16() and OpenFile32().
1182 static HFILE FILE_DoOpenFile( LPCSTR name, OFSTRUCT *ofs, UINT mode, BOOL win32 )
1184 HFILE hFileRet;
1185 HANDLE handle;
1186 FILETIME filetime;
1187 WORD filedatetime[2];
1188 DOS_FULL_NAME full_name;
1189 DWORD access, sharing;
1190 WCHAR *p;
1191 WCHAR buffer[MAX_PATH];
1192 LPWSTR nameW;
1194 if (!ofs) return HFILE_ERROR;
1196 TRACE("%s %s %s %s%s%s%s%s%s%s%s%s\n",name,
1197 ((mode & 0x3 )==OF_READ)?"OF_READ":
1198 ((mode & 0x3 )==OF_WRITE)?"OF_WRITE":
1199 ((mode & 0x3 )==OF_READWRITE)?"OF_READWRITE":"unknown",
1200 ((mode & 0x70 )==OF_SHARE_COMPAT)?"OF_SHARE_COMPAT":
1201 ((mode & 0x70 )==OF_SHARE_DENY_NONE)?"OF_SHARE_DENY_NONE":
1202 ((mode & 0x70 )==OF_SHARE_DENY_READ)?"OF_SHARE_DENY_READ":
1203 ((mode & 0x70 )==OF_SHARE_DENY_WRITE)?"OF_SHARE_DENY_WRITE":
1204 ((mode & 0x70 )==OF_SHARE_EXCLUSIVE)?"OF_SHARE_EXCLUSIVE":"unknown",
1205 ((mode & OF_PARSE )==OF_PARSE)?"OF_PARSE ":"",
1206 ((mode & OF_DELETE )==OF_DELETE)?"OF_DELETE ":"",
1207 ((mode & OF_VERIFY )==OF_VERIFY)?"OF_VERIFY ":"",
1208 ((mode & OF_SEARCH )==OF_SEARCH)?"OF_SEARCH ":"",
1209 ((mode & OF_CANCEL )==OF_CANCEL)?"OF_CANCEL ":"",
1210 ((mode & OF_CREATE )==OF_CREATE)?"OF_CREATE ":"",
1211 ((mode & OF_PROMPT )==OF_PROMPT)?"OF_PROMPT ":"",
1212 ((mode & OF_EXIST )==OF_EXIST)?"OF_EXIST ":"",
1213 ((mode & OF_REOPEN )==OF_REOPEN)?"OF_REOPEN ":""
1217 ofs->cBytes = sizeof(OFSTRUCT);
1218 ofs->nErrCode = 0;
1219 if (mode & OF_REOPEN) name = ofs->szPathName;
1221 if (!name) {
1222 ERR("called with `name' set to NULL ! Please debug.\n");
1223 return HFILE_ERROR;
1226 TRACE("%s %04x\n", name, mode );
1228 /* the watcom 10.6 IDE relies on a valid path returned in ofs->szPathName
1229 Are there any cases where getting the path here is wrong?
1230 Uwe Bonnes 1997 Apr 2 */
1231 if (!GetFullPathNameA( name, sizeof(ofs->szPathName),
1232 ofs->szPathName, NULL )) goto error;
1233 FILE_ConvertOFMode( mode, &access, &sharing );
1235 /* OF_PARSE simply fills the structure */
1237 if (mode & OF_PARSE)
1239 ofs->fFixedDisk = (GetDriveType16( ofs->szPathName[0]-'A' )
1240 != DRIVE_REMOVABLE);
1241 TRACE("(%s): OF_PARSE, res = '%s'\n",
1242 name, ofs->szPathName );
1243 return 0;
1246 /* OF_CREATE is completely different from all other options, so
1247 handle it first */
1249 if (mode & OF_CREATE)
1251 if ((handle = CreateFileA( name, GENERIC_READ | GENERIC_WRITE,
1252 sharing, NULL, CREATE_ALWAYS,
1253 FILE_ATTRIBUTE_NORMAL, 0 ))== INVALID_HANDLE_VALUE)
1254 goto error;
1255 goto success;
1258 MultiByteToWideChar(CP_ACP, 0, name, -1, buffer, MAX_PATH);
1259 nameW = buffer;
1261 /* If OF_SEARCH is set, ignore the given path */
1263 if ((mode & OF_SEARCH) && !(mode & OF_REOPEN))
1265 /* First try the file name as is */
1266 if (DOSFS_GetFullName( nameW, TRUE, &full_name )) goto found;
1267 /* Now remove the path */
1268 if (nameW[0] && (nameW[1] == ':')) nameW += 2;
1269 if ((p = strrchrW( nameW, '\\' ))) nameW = p + 1;
1270 if ((p = strrchrW( nameW, '/' ))) nameW = p + 1;
1271 if (!nameW[0]) goto not_found;
1274 /* Now look for the file */
1276 if (!DIR_SearchPath( NULL, nameW, NULL, &full_name, win32 )) goto not_found;
1278 found:
1279 TRACE("found %s = %s\n",
1280 full_name.long_name, debugstr_w(full_name.short_name) );
1281 WideCharToMultiByte(CP_ACP, 0, full_name.short_name, -1,
1282 ofs->szPathName, sizeof(ofs->szPathName), NULL, NULL);
1284 if (mode & OF_DELETE)
1286 handle = FILE_CreateFile( full_name.long_name, GENERIC_READ|GENERIC_WRITE, 0,
1287 NULL, OPEN_EXISTING, 0, 0, TRUE,
1288 GetDriveTypeW( full_name.short_name ) );
1289 if (!handle) goto error;
1290 CloseHandle( handle );
1291 if (unlink( full_name.long_name ) == -1) goto not_found;
1292 TRACE("(%s): OF_DELETE return = OK\n", name);
1293 return 1;
1296 handle = FILE_CreateFile( full_name.long_name, access, sharing,
1297 NULL, OPEN_EXISTING, 0, 0,
1298 DRIVE_GetFlags(full_name.drive) & DRIVE_FAIL_READ_ONLY,
1299 GetDriveTypeW( full_name.short_name ) );
1300 if (!handle) goto not_found;
1302 GetFileTime( handle, NULL, NULL, &filetime );
1303 FileTimeToDosDateTime( &filetime, &filedatetime[0], &filedatetime[1] );
1304 if ((mode & OF_VERIFY) && (mode & OF_REOPEN))
1306 if (ofs->Reserved1 != filedatetime[0] || ofs->Reserved2 != filedatetime[1] )
1308 CloseHandle( handle );
1309 WARN("(%s): OF_VERIFY failed\n", name );
1310 /* FIXME: what error here? */
1311 SetLastError( ERROR_FILE_NOT_FOUND );
1312 goto error;
1315 ofs->Reserved1 = filedatetime[0];
1316 ofs->Reserved2 = filedatetime[1];
1318 success: /* We get here if the open was successful */
1319 TRACE("(%s): OK, return = %p\n", name, handle );
1320 if (win32)
1322 hFileRet = (HFILE)handle;
1323 if (mode & OF_EXIST) /* Return the handle, but close it first */
1324 CloseHandle( handle );
1326 else
1328 hFileRet = Win32HandleToDosFileHandle( handle );
1329 if (hFileRet == HFILE_ERROR16) goto error;
1330 if (mode & OF_EXIST) /* Return the handle, but close it first */
1331 _lclose16( hFileRet );
1333 return hFileRet;
1335 not_found: /* We get here if the file does not exist */
1336 WARN("'%s' not found or sharing violation\n", name );
1337 SetLastError( ERROR_FILE_NOT_FOUND );
1338 /* fall through */
1340 error: /* We get here if there was an error opening the file */
1341 ofs->nErrCode = GetLastError();
1342 WARN("(%s): return = HFILE_ERROR error= %d\n",
1343 name,ofs->nErrCode );
1344 return HFILE_ERROR;
1348 /***********************************************************************
1349 * OpenFile (KERNEL.74)
1350 * OpenFileEx (KERNEL.360)
1352 HFILE16 WINAPI OpenFile16( LPCSTR name, OFSTRUCT *ofs, UINT16 mode )
1354 return FILE_DoOpenFile( name, ofs, mode, FALSE );
1358 /***********************************************************************
1359 * OpenFile (KERNEL32.@)
1361 HFILE WINAPI OpenFile( LPCSTR name, OFSTRUCT *ofs, UINT mode )
1363 return FILE_DoOpenFile( name, ofs, mode, TRUE );
1367 /***********************************************************************
1368 * FILE_InitProcessDosHandles
1370 * Allocates the default DOS handles for a process. Called either by
1371 * Win32HandleToDosFileHandle below or by the DOSVM stuff.
1373 static void FILE_InitProcessDosHandles( void )
1375 HANDLE cp = GetCurrentProcess();
1376 DuplicateHandle(cp, GetStdHandle(STD_INPUT_HANDLE), cp, &dos_handles[0],
1377 0, TRUE, DUPLICATE_SAME_ACCESS);
1378 DuplicateHandle(cp, GetStdHandle(STD_OUTPUT_HANDLE), cp, &dos_handles[1],
1379 0, TRUE, DUPLICATE_SAME_ACCESS);
1380 DuplicateHandle(cp, GetStdHandle(STD_ERROR_HANDLE), cp, &dos_handles[2],
1381 0, TRUE, DUPLICATE_SAME_ACCESS);
1382 DuplicateHandle(cp, GetStdHandle(STD_ERROR_HANDLE), cp, &dos_handles[3],
1383 0, TRUE, DUPLICATE_SAME_ACCESS);
1384 DuplicateHandle(cp, GetStdHandle(STD_ERROR_HANDLE), cp, &dos_handles[4],
1385 0, TRUE, DUPLICATE_SAME_ACCESS);
1388 /***********************************************************************
1389 * Win32HandleToDosFileHandle (KERNEL32.21)
1391 * Allocate a DOS handle for a Win32 handle. The Win32 handle is no
1392 * longer valid after this function (even on failure).
1394 * Note: this is not exactly right, since on Win95 the Win32 handles
1395 * are on top of DOS handles and we do it the other way
1396 * around. Should be good enough though.
1398 HFILE WINAPI Win32HandleToDosFileHandle( HANDLE handle )
1400 int i;
1402 if (!handle || (handle == INVALID_HANDLE_VALUE))
1403 return HFILE_ERROR;
1405 for (i = 5; i < DOS_TABLE_SIZE; i++)
1406 if (!dos_handles[i])
1408 dos_handles[i] = handle;
1409 TRACE("Got %d for h32 %p\n", i, handle );
1410 return (HFILE)i;
1412 CloseHandle( handle );
1413 SetLastError( ERROR_TOO_MANY_OPEN_FILES );
1414 return HFILE_ERROR;
1418 /***********************************************************************
1419 * DosFileHandleToWin32Handle (KERNEL32.20)
1421 * Return the Win32 handle for a DOS handle.
1423 * Note: this is not exactly right, since on Win95 the Win32 handles
1424 * are on top of DOS handles and we do it the other way
1425 * around. Should be good enough though.
1427 HANDLE WINAPI DosFileHandleToWin32Handle( HFILE handle )
1429 HFILE16 hfile = (HFILE16)handle;
1430 if (hfile < 5 && !dos_handles[hfile]) FILE_InitProcessDosHandles();
1431 if ((hfile >= DOS_TABLE_SIZE) || !dos_handles[hfile])
1433 SetLastError( ERROR_INVALID_HANDLE );
1434 return INVALID_HANDLE_VALUE;
1436 return dos_handles[hfile];
1440 /***********************************************************************
1441 * DisposeLZ32Handle (KERNEL32.22)
1443 * Note: this is not entirely correct, we should only close the
1444 * 32-bit handle and not the 16-bit one, but we cannot do
1445 * this because of the way our DOS handles are implemented.
1446 * It shouldn't break anything though.
1448 void WINAPI DisposeLZ32Handle( HANDLE handle )
1450 int i;
1452 if (!handle || (handle == INVALID_HANDLE_VALUE)) return;
1454 for (i = 5; i < DOS_TABLE_SIZE; i++)
1455 if (dos_handles[i] == handle)
1457 dos_handles[i] = 0;
1458 CloseHandle( handle );
1459 break;
1464 /***********************************************************************
1465 * FILE_Dup2
1467 * dup2() function for DOS handles.
1469 HFILE16 FILE_Dup2( HFILE16 hFile1, HFILE16 hFile2 )
1471 HANDLE new_handle;
1473 if (hFile1 < 5 && !dos_handles[hFile1]) FILE_InitProcessDosHandles();
1475 if ((hFile1 >= DOS_TABLE_SIZE) || (hFile2 >= DOS_TABLE_SIZE) || !dos_handles[hFile1])
1477 SetLastError( ERROR_INVALID_HANDLE );
1478 return HFILE_ERROR16;
1480 if (!DuplicateHandle( GetCurrentProcess(), dos_handles[hFile1],
1481 GetCurrentProcess(), &new_handle,
1482 0, FALSE, DUPLICATE_SAME_ACCESS ))
1483 return HFILE_ERROR16;
1484 if (dos_handles[hFile2]) CloseHandle( dos_handles[hFile2] );
1485 dos_handles[hFile2] = new_handle;
1486 return hFile2;
1490 /***********************************************************************
1491 * _lclose (KERNEL.81)
1493 HFILE16 WINAPI _lclose16( HFILE16 hFile )
1495 if ((hFile >= DOS_TABLE_SIZE) || !dos_handles[hFile])
1497 SetLastError( ERROR_INVALID_HANDLE );
1498 return HFILE_ERROR16;
1500 TRACE("%d (handle32=%p)\n", hFile, dos_handles[hFile] );
1501 CloseHandle( dos_handles[hFile] );
1502 dos_handles[hFile] = 0;
1503 return 0;
1507 /******************************************************************
1508 * FILE_ReadWriteApc (internal)
1512 static void WINAPI FILE_ReadWriteApc(void* apc_user, PIO_STATUS_BLOCK io_status, ULONG len)
1514 LPOVERLAPPED_COMPLETION_ROUTINE cr = (LPOVERLAPPED_COMPLETION_ROUTINE)apc_user;
1516 cr(RtlNtStatusToDosError(io_status->u.Status), len, (LPOVERLAPPED)io_status);
1519 /***********************************************************************
1520 * ReadFileEx (KERNEL32.@)
1522 BOOL WINAPI ReadFileEx(HANDLE hFile, LPVOID buffer, DWORD bytesToRead,
1523 LPOVERLAPPED overlapped,
1524 LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine)
1526 LARGE_INTEGER offset;
1527 NTSTATUS status;
1528 PIO_STATUS_BLOCK io_status;
1530 if (!overlapped)
1532 SetLastError(ERROR_INVALID_PARAMETER);
1533 return FALSE;
1536 offset.s.LowPart = overlapped->Offset;
1537 offset.s.HighPart = overlapped->OffsetHigh;
1538 io_status = (PIO_STATUS_BLOCK)overlapped;
1539 io_status->u.Status = STATUS_PENDING;
1541 status = NtReadFile(hFile, NULL, FILE_ReadWriteApc, lpCompletionRoutine,
1542 io_status, buffer, bytesToRead, &offset, NULL);
1544 if (status)
1546 SetLastError( RtlNtStatusToDosError(status) );
1547 return FALSE;
1549 return TRUE;
1552 /***********************************************************************
1553 * ReadFile (KERNEL32.@)
1555 BOOL WINAPI ReadFile( HANDLE hFile, LPVOID buffer, DWORD bytesToRead,
1556 LPDWORD bytesRead, LPOVERLAPPED overlapped )
1558 LARGE_INTEGER offset;
1559 PLARGE_INTEGER poffset = NULL;
1560 IO_STATUS_BLOCK iosb;
1561 PIO_STATUS_BLOCK io_status = &iosb;
1562 HANDLE hEvent = 0;
1563 NTSTATUS status;
1565 TRACE("%p %p %ld %p %p\n", hFile, buffer, bytesToRead,
1566 bytesRead, overlapped );
1568 if (bytesRead) *bytesRead = 0; /* Do this before anything else */
1569 if (!bytesToRead) return TRUE;
1571 if (IsBadReadPtr(buffer, bytesToRead))
1573 SetLastError(ERROR_WRITE_FAULT); /* FIXME */
1574 return FALSE;
1576 if (is_console_handle(hFile))
1577 return FILE_ReadConsole(hFile, buffer, bytesToRead, bytesRead, NULL);
1579 if (overlapped != NULL)
1581 offset.s.LowPart = overlapped->Offset;
1582 offset.s.HighPart = overlapped->OffsetHigh;
1583 poffset = &offset;
1584 hEvent = overlapped->hEvent;
1585 io_status = (PIO_STATUS_BLOCK)overlapped;
1587 io_status->u.Status = STATUS_PENDING;
1588 io_status->Information = 0;
1590 status = NtReadFile(hFile, hEvent, NULL, NULL, io_status, buffer, bytesToRead, poffset, NULL);
1592 if (status != STATUS_PENDING && bytesRead)
1593 *bytesRead = io_status->Information;
1595 if (status && status != STATUS_END_OF_FILE)
1597 SetLastError( RtlNtStatusToDosError(status) );
1598 return FALSE;
1600 return TRUE;
1604 /***********************************************************************
1605 * WriteFileEx (KERNEL32.@)
1607 BOOL WINAPI WriteFileEx(HANDLE hFile, LPCVOID buffer, DWORD bytesToWrite,
1608 LPOVERLAPPED overlapped,
1609 LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine)
1611 LARGE_INTEGER offset;
1612 NTSTATUS status;
1613 PIO_STATUS_BLOCK io_status;
1615 TRACE("%p %p %ld %p %p\n",
1616 hFile, buffer, bytesToWrite, overlapped, lpCompletionRoutine);
1618 if (overlapped == NULL)
1620 SetLastError(ERROR_INVALID_PARAMETER);
1621 return FALSE;
1623 offset.s.LowPart = overlapped->Offset;
1624 offset.s.HighPart = overlapped->OffsetHigh;
1626 io_status = (PIO_STATUS_BLOCK)overlapped;
1627 io_status->u.Status = STATUS_PENDING;
1629 status = NtWriteFile(hFile, NULL, FILE_ReadWriteApc, lpCompletionRoutine,
1630 io_status, buffer, bytesToWrite, &offset, NULL);
1632 if (status) SetLastError( RtlNtStatusToDosError(status) );
1633 return !status;
1636 /***********************************************************************
1637 * WriteFile (KERNEL32.@)
1639 BOOL WINAPI WriteFile( HANDLE hFile, LPCVOID buffer, DWORD bytesToWrite,
1640 LPDWORD bytesWritten, LPOVERLAPPED overlapped )
1642 HANDLE hEvent = NULL;
1643 LARGE_INTEGER offset;
1644 PLARGE_INTEGER poffset = NULL;
1645 NTSTATUS status;
1646 IO_STATUS_BLOCK iosb;
1647 PIO_STATUS_BLOCK piosb = &iosb;
1649 TRACE("%p %p %ld %p %p\n",
1650 hFile, buffer, bytesToWrite, bytesWritten, overlapped );
1652 if (is_console_handle(hFile))
1653 return FILE_WriteConsole(hFile, buffer, bytesToWrite, bytesWritten, NULL);
1655 if (IsBadReadPtr(buffer, bytesToWrite))
1657 SetLastError(ERROR_READ_FAULT); /* FIXME */
1658 return FALSE;
1661 if (overlapped)
1663 offset.s.LowPart = overlapped->Offset;
1664 offset.s.HighPart = overlapped->OffsetHigh;
1665 poffset = &offset;
1666 hEvent = overlapped->hEvent;
1667 piosb = (PIO_STATUS_BLOCK)overlapped;
1669 piosb->u.Status = STATUS_PENDING;
1670 piosb->Information = 0;
1672 status = NtWriteFile(hFile, hEvent, NULL, NULL, piosb,
1673 buffer, bytesToWrite, poffset, NULL);
1674 if (status)
1676 SetLastError( RtlNtStatusToDosError(status) );
1677 return FALSE;
1679 if (bytesWritten) *bytesWritten = piosb->Information;
1681 return TRUE;
1685 /***********************************************************************
1686 * SetFilePointer (KERNEL32.@)
1688 DWORD WINAPI SetFilePointer( HANDLE hFile, LONG distance, LONG *highword,
1689 DWORD method )
1691 DWORD ret = INVALID_SET_FILE_POINTER;
1693 TRACE("handle %p offset %ld high %ld origin %ld\n",
1694 hFile, distance, highword?*highword:0, method );
1696 SERVER_START_REQ( set_file_pointer )
1698 req->handle = hFile;
1699 req->low = distance;
1700 req->high = highword ? *highword : (distance >= 0) ? 0 : -1;
1701 /* FIXME: assumes 1:1 mapping between Windows and Unix seek constants */
1702 req->whence = method;
1703 SetLastError( 0 );
1704 if (!wine_server_call_err( req ))
1706 ret = reply->new_low;
1707 if (highword) *highword = reply->new_high;
1710 SERVER_END_REQ;
1711 return ret;
1715 /*************************************************************************
1716 * SetHandleCount (KERNEL32.@)
1718 UINT WINAPI SetHandleCount( UINT count )
1720 return min( 256, count );
1724 /**************************************************************************
1725 * SetEndOfFile (KERNEL32.@)
1727 BOOL WINAPI SetEndOfFile( HANDLE hFile )
1729 BOOL ret;
1730 SERVER_START_REQ( truncate_file )
1732 req->handle = hFile;
1733 ret = !wine_server_call_err( req );
1735 SERVER_END_REQ;
1736 return ret;
1740 /***********************************************************************
1741 * DeleteFileW (KERNEL32.@)
1743 BOOL WINAPI DeleteFileW( LPCWSTR path )
1745 DOS_FULL_NAME full_name;
1746 HANDLE hFile;
1748 TRACE("%s\n", debugstr_w(path) );
1749 if (!path || !*path)
1751 SetLastError(ERROR_PATH_NOT_FOUND);
1752 return FALSE;
1754 if (DOSFS_GetDevice( path ))
1756 WARN("cannot remove DOS device %s!\n", debugstr_w(path));
1757 SetLastError( ERROR_FILE_NOT_FOUND );
1758 return FALSE;
1761 if (!DOSFS_GetFullName( path, TRUE, &full_name )) return FALSE;
1763 /* check if we are allowed to delete the source */
1764 hFile = FILE_CreateFile( full_name.long_name, GENERIC_READ|GENERIC_WRITE, 0,
1765 NULL, OPEN_EXISTING, 0, 0, TRUE,
1766 GetDriveTypeW( full_name.short_name ) );
1767 if (!hFile) return FALSE;
1769 if (unlink( full_name.long_name ) == -1)
1771 FILE_SetDosError();
1772 CloseHandle(hFile);
1773 return FALSE;
1775 CloseHandle(hFile);
1776 return TRUE;
1780 /***********************************************************************
1781 * DeleteFileA (KERNEL32.@)
1783 BOOL WINAPI DeleteFileA( LPCSTR path )
1785 UNICODE_STRING pathW;
1786 BOOL ret = FALSE;
1788 if (!path)
1790 SetLastError(ERROR_INVALID_PARAMETER);
1791 return FALSE;
1794 if (RtlCreateUnicodeStringFromAsciiz(&pathW, path))
1796 ret = DeleteFileW(pathW.Buffer);
1797 RtlFreeUnicodeString(&pathW);
1799 else
1800 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1801 return ret;
1805 /***********************************************************************
1806 * GetFileType (KERNEL32.@)
1808 DWORD WINAPI GetFileType( HANDLE hFile )
1810 DWORD ret = FILE_TYPE_UNKNOWN;
1812 if (is_console_handle( hFile ))
1813 return FILE_TYPE_CHAR;
1815 SERVER_START_REQ( get_file_info )
1817 req->handle = hFile;
1818 if (!wine_server_call_err( req )) ret = reply->type;
1820 SERVER_END_REQ;
1821 return ret;
1825 /* check if a file name is for an executable file (.exe or .com) */
1826 inline static BOOL is_executable( const char *name )
1828 int len = strlen(name);
1830 if (len < 4) return FALSE;
1831 return (!strcasecmp( name + len - 4, ".exe" ) ||
1832 !strcasecmp( name + len - 4, ".com" ));
1836 /***********************************************************************
1837 * FILE_AddBootRenameEntry
1839 * Adds an entry to the registry that is loaded when windows boots and
1840 * checks if there are some files to be removed or renamed/moved.
1841 * <fn1> has to be valid and <fn2> may be NULL. If both pointers are
1842 * non-NULL then the file is moved, otherwise it is deleted. The
1843 * entry of the registrykey is always appended with two zero
1844 * terminated strings. If <fn2> is NULL then the second entry is
1845 * simply a single 0-byte. Otherwise the second filename goes
1846 * there. The entries are prepended with \??\ before the path and the
1847 * second filename gets also a '!' as the first character if
1848 * MOVEFILE_REPLACE_EXISTING is set. After the final string another
1849 * 0-byte follows to indicate the end of the strings.
1850 * i.e.:
1851 * \??\D:\test\file1[0]
1852 * !\??\D:\test\file1_renamed[0]
1853 * \??\D:\Test|delete[0]
1854 * [0] <- file is to be deleted, second string empty
1855 * \??\D:\test\file2[0]
1856 * !\??\D:\test\file2_renamed[0]
1857 * [0] <- indicates end of strings
1859 * or:
1860 * \??\D:\test\file1[0]
1861 * !\??\D:\test\file1_renamed[0]
1862 * \??\D:\Test|delete[0]
1863 * [0] <- file is to be deleted, second string empty
1864 * [0] <- indicates end of strings
1867 static BOOL FILE_AddBootRenameEntry( LPCWSTR fn1, LPCWSTR fn2, DWORD flags )
1869 static const WCHAR PreString[] = {'\\','?','?','\\',0};
1870 static const WCHAR ValueName[] = {'P','e','n','d','i','n','g',
1871 'F','i','l','e','R','e','n','a','m','e',
1872 'O','p','e','r','a','t','i','o','n','s',0};
1873 static const WCHAR SessionW[] = {'M','a','c','h','i','n','e','\\',
1874 'S','y','s','t','e','m','\\',
1875 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
1876 'C','o','n','t','r','o','l','\\',
1877 'S','e','s','s','i','o','n',' ','M','a','n','a','g','e','r',0};
1878 static const int info_size = FIELD_OFFSET( KEY_VALUE_PARTIAL_INFORMATION, Data );
1880 OBJECT_ATTRIBUTES attr;
1881 UNICODE_STRING nameW;
1882 KEY_VALUE_PARTIAL_INFORMATION *info;
1883 BOOL rc = FALSE;
1884 HKEY Reboot = 0;
1885 DWORD len0, len1, len2;
1886 DWORD DataSize = 0;
1887 BYTE *Buffer = NULL;
1888 WCHAR *p;
1890 attr.Length = sizeof(attr);
1891 attr.RootDirectory = 0;
1892 attr.ObjectName = &nameW;
1893 attr.Attributes = 0;
1894 attr.SecurityDescriptor = NULL;
1895 attr.SecurityQualityOfService = NULL;
1896 RtlInitUnicodeString( &nameW, SessionW );
1898 if (NtCreateKey( &Reboot, KEY_ALL_ACCESS, &attr, 0, NULL, 0, NULL ) != STATUS_SUCCESS)
1900 WARN("Error creating key for reboot managment [%s]\n",
1901 "SYSTEM\\CurrentControlSet\\Control\\Session Manager");
1902 return FALSE;
1905 len0 = strlenW(PreString);
1906 len1 = strlenW(fn1) + len0 + 1;
1907 if (fn2)
1909 len2 = strlenW(fn2) + len0 + 1;
1910 if (flags & MOVEFILE_REPLACE_EXISTING) len2++; /* Plus 1 because of the leading '!' */
1912 else len2 = 1; /* minimum is the 0 characters for the empty second string */
1914 /* convert characters to bytes */
1915 len0 *= sizeof(WCHAR);
1916 len1 *= sizeof(WCHAR);
1917 len2 *= sizeof(WCHAR);
1919 RtlInitUnicodeString( &nameW, ValueName );
1921 /* First we check if the key exists and if so how many bytes it already contains. */
1922 if (NtQueryValueKey( Reboot, &nameW, KeyValuePartialInformation,
1923 NULL, 0, &DataSize ) == STATUS_BUFFER_OVERFLOW)
1925 if (!(Buffer = HeapAlloc( GetProcessHeap(), 0, DataSize + len1 + len2 + sizeof(WCHAR) )))
1926 goto Quit;
1927 if (NtQueryValueKey( Reboot, &nameW, KeyValuePartialInformation,
1928 Buffer, DataSize, &DataSize )) goto Quit;
1929 info = (KEY_VALUE_PARTIAL_INFORMATION *)Buffer;
1930 if (info->Type != REG_MULTI_SZ) goto Quit;
1931 if (DataSize > sizeof(info)) DataSize -= sizeof(WCHAR); /* remove terminating null (will be added back later) */
1933 else
1935 DataSize = info_size;
1936 if (!(Buffer = HeapAlloc( GetProcessHeap(), 0, DataSize + len1 + len2 + sizeof(WCHAR) )))
1937 goto Quit;
1940 p = (WCHAR *)(Buffer + DataSize);
1941 strcpyW( p, PreString );
1942 strcatW( p, fn1 );
1943 DataSize += len1;
1944 if (fn2)
1946 p = (WCHAR *)(Buffer + DataSize);
1947 if (flags & MOVEFILE_REPLACE_EXISTING)
1948 *p++ = '!';
1949 strcpyW( p, PreString );
1950 strcatW( p, fn2 );
1951 DataSize += len2;
1953 else
1955 p = (WCHAR *)(Buffer + DataSize);
1956 *p = 0;
1957 DataSize += sizeof(WCHAR);
1960 /* add final null */
1961 p = (WCHAR *)(Buffer + DataSize);
1962 *p = 0;
1963 DataSize += sizeof(WCHAR);
1965 rc = !NtSetValueKey(Reboot, &nameW, 0, REG_MULTI_SZ, Buffer + info_size, DataSize - info_size);
1967 Quit:
1968 if (Reboot) NtClose(Reboot);
1969 if (Buffer) HeapFree( GetProcessHeap(), 0, Buffer );
1970 return(rc);
1974 /**************************************************************************
1975 * MoveFileExW (KERNEL32.@)
1977 BOOL WINAPI MoveFileExW( LPCWSTR fn1, LPCWSTR fn2, DWORD flag )
1979 DOS_FULL_NAME full_name1, full_name2;
1980 HANDLE hFile;
1981 DWORD attr = INVALID_FILE_ATTRIBUTES;
1983 TRACE("(%s,%s,%04lx)\n", debugstr_w(fn1), debugstr_w(fn2), flag);
1985 /* FIXME: <Gerhard W. Gruber>sparhawk@gmx.at
1986 In case of W9x and lesser this function should return 120 (ERROR_CALL_NOT_IMPLEMENTED)
1987 to be really compatible. Most programs wont have any problems though. In case
1988 you encounter one, this is what you should return here. I don't know what's up
1989 with NT 3.5. Is this function available there or not?
1990 Does anybody really care about 3.5? :)
1993 /* Filename1 has to be always set to a valid path. Filename2 may be NULL
1994 if the source file has to be deleted.
1996 if (!fn1) {
1997 SetLastError(ERROR_INVALID_PARAMETER);
1998 return FALSE;
2001 /* This function has to be run through in order to process the name properly.
2002 If the BOOTDELAY flag is set, the file doesn't need to exist though. At least
2003 that is the behaviour on NT 4.0. The operation accepts the filenames as
2004 they are given but it can't reply with a reasonable returncode. Success
2005 means in that case success for entering the values into the registry.
2007 if(!DOSFS_GetFullName( fn1, TRUE, &full_name1 ))
2009 if(!(flag & MOVEFILE_DELAY_UNTIL_REBOOT))
2010 return FALSE;
2013 if (fn2) /* !fn2 means delete fn1 */
2015 if (DOSFS_GetFullName( fn2, TRUE, &full_name2 ))
2017 if(!(flag & MOVEFILE_DELAY_UNTIL_REBOOT))
2019 /* target exists, check if we may overwrite */
2020 if (!(flag & MOVEFILE_REPLACE_EXISTING))
2022 SetLastError( ERROR_FILE_EXISTS );
2023 return FALSE;
2027 else
2029 if (!DOSFS_GetFullName( fn2, FALSE, &full_name2 ))
2031 if(!(flag & MOVEFILE_DELAY_UNTIL_REBOOT))
2032 return FALSE;
2036 /* Source name and target path are valid */
2038 if (flag & MOVEFILE_DELAY_UNTIL_REBOOT)
2040 return FILE_AddBootRenameEntry( fn1, fn2, flag );
2043 attr = GetFileAttributesW( fn1 );
2044 if ( attr == INVALID_FILE_ATTRIBUTES ) return FALSE;
2046 /* check if we are allowed to rename the source */
2047 hFile = FILE_CreateFile( full_name1.long_name, 0, 0,
2048 NULL, OPEN_EXISTING, 0, 0, TRUE,
2049 GetDriveTypeW( full_name1.short_name ) );
2050 if (!hFile)
2052 if (GetLastError() != ERROR_ACCESS_DENIED) return FALSE;
2053 if ( !(attr & FILE_ATTRIBUTE_DIRECTORY) ) return FALSE;
2054 /* if it's a directory we can continue */
2056 else CloseHandle(hFile);
2058 /* check, if we are allowed to delete the destination,
2059 ** (but the file not being there is fine) */
2060 hFile = FILE_CreateFile( full_name2.long_name, GENERIC_READ|GENERIC_WRITE, 0,
2061 NULL, OPEN_EXISTING, 0, 0, TRUE,
2062 GetDriveTypeW( full_name2.short_name ) );
2063 if(!hFile && GetLastError() != ERROR_FILE_NOT_FOUND) return FALSE;
2064 CloseHandle(hFile);
2066 if (full_name1.drive != full_name2.drive)
2068 if (!(flag & MOVEFILE_COPY_ALLOWED))
2070 SetLastError( ERROR_NOT_SAME_DEVICE );
2071 return FALSE;
2073 else if ( attr & FILE_ATTRIBUTE_DIRECTORY )
2075 /* Strange, but that's what Windows returns */
2076 SetLastError ( ERROR_ACCESS_DENIED );
2077 return FALSE;
2080 if (rename( full_name1.long_name, full_name2.long_name ) == -1)
2081 /* Try copy/delete unless it's a directory. */
2082 /* FIXME: This does not handle the (unlikely) case that the two locations
2083 are on the same Wine drive, but on different Unix file systems. */
2085 if ( attr & FILE_ATTRIBUTE_DIRECTORY )
2087 FILE_SetDosError();
2088 return FALSE;
2090 else
2092 if ( ! CopyFileW( fn1, fn2, !(flag & MOVEFILE_REPLACE_EXISTING) ))
2093 return FALSE;
2094 if ( ! DeleteFileW ( fn1 ) )
2095 return FALSE;
2098 if (is_executable( full_name1.long_name ) != is_executable( full_name2.long_name ))
2100 struct stat fstat;
2101 if (stat( full_name2.long_name, &fstat ) != -1)
2103 if (is_executable( full_name2.long_name ))
2104 /* set executable bit where read bit is set */
2105 fstat.st_mode |= (fstat.st_mode & 0444) >> 2;
2106 else
2107 fstat.st_mode &= ~0111;
2108 chmod( full_name2.long_name, fstat.st_mode );
2111 return TRUE;
2113 else /* fn2 == NULL means delete source */
2115 if (flag & MOVEFILE_DELAY_UNTIL_REBOOT)
2117 if (flag & MOVEFILE_COPY_ALLOWED) {
2118 WARN("Illegal flag\n");
2119 SetLastError( ERROR_GEN_FAILURE );
2120 return FALSE;
2123 return FILE_AddBootRenameEntry( fn1, NULL, flag );
2126 if (unlink( full_name1.long_name ) == -1)
2128 FILE_SetDosError();
2129 return FALSE;
2131 return TRUE; /* successfully deleted */
2135 /**************************************************************************
2136 * MoveFileExA (KERNEL32.@)
2138 BOOL WINAPI MoveFileExA( LPCSTR fn1, LPCSTR fn2, DWORD flag )
2140 UNICODE_STRING fn1W, fn2W;
2141 BOOL ret;
2143 if (!fn1)
2145 SetLastError(ERROR_INVALID_PARAMETER);
2146 return FALSE;
2149 RtlCreateUnicodeStringFromAsciiz(&fn1W, fn1);
2150 if (fn2) RtlCreateUnicodeStringFromAsciiz(&fn2W, fn2);
2151 else fn2W.Buffer = NULL;
2153 ret = MoveFileExW( fn1W.Buffer, fn2W.Buffer, flag );
2155 RtlFreeUnicodeString(&fn1W);
2156 RtlFreeUnicodeString(&fn2W);
2157 return ret;
2161 /**************************************************************************
2162 * MoveFileW (KERNEL32.@)
2164 * Move file or directory
2166 BOOL WINAPI MoveFileW( LPCWSTR fn1, LPCWSTR fn2 )
2168 return MoveFileExW( fn1, fn2, MOVEFILE_COPY_ALLOWED );
2172 /**************************************************************************
2173 * MoveFileA (KERNEL32.@)
2175 BOOL WINAPI MoveFileA( LPCSTR fn1, LPCSTR fn2 )
2177 return MoveFileExA( fn1, fn2, MOVEFILE_COPY_ALLOWED );
2181 /**************************************************************************
2182 * CopyFileW (KERNEL32.@)
2184 BOOL WINAPI CopyFileW( LPCWSTR source, LPCWSTR dest, BOOL fail_if_exists )
2186 HANDLE h1, h2;
2187 BY_HANDLE_FILE_INFORMATION info;
2188 DWORD count;
2189 BOOL ret = FALSE;
2190 char buffer[2048];
2192 if (!source || !dest)
2194 SetLastError(ERROR_INVALID_PARAMETER);
2195 return FALSE;
2198 TRACE("%s -> %s\n", debugstr_w(source), debugstr_w(dest));
2200 if ((h1 = CreateFileW(source, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE,
2201 NULL, OPEN_EXISTING, 0, 0)) == INVALID_HANDLE_VALUE)
2203 WARN("Unable to open source %s\n", debugstr_w(source));
2204 return FALSE;
2207 if (!GetFileInformationByHandle( h1, &info ))
2209 WARN("GetFileInformationByHandle returned error for %s\n", debugstr_w(source));
2210 CloseHandle( h1 );
2211 return FALSE;
2214 if ((h2 = CreateFileW( dest, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
2215 fail_if_exists ? CREATE_NEW : CREATE_ALWAYS,
2216 info.dwFileAttributes, h1 )) == INVALID_HANDLE_VALUE)
2218 WARN("Unable to open dest %s\n", debugstr_w(dest));
2219 CloseHandle( h1 );
2220 return FALSE;
2223 while (ReadFile( h1, buffer, sizeof(buffer), &count, NULL ) && count)
2225 char *p = buffer;
2226 while (count != 0)
2228 DWORD res;
2229 if (!WriteFile( h2, p, count, &res, NULL ) || !res) goto done;
2230 p += res;
2231 count -= res;
2234 ret = TRUE;
2235 done:
2236 CloseHandle( h1 );
2237 CloseHandle( h2 );
2238 return ret;
2242 /**************************************************************************
2243 * CopyFileA (KERNEL32.@)
2245 BOOL WINAPI CopyFileA( LPCSTR source, LPCSTR dest, BOOL fail_if_exists)
2247 UNICODE_STRING sourceW, destW;
2248 BOOL ret;
2250 if (!source || !dest)
2252 SetLastError(ERROR_INVALID_PARAMETER);
2253 return FALSE;
2256 RtlCreateUnicodeStringFromAsciiz(&sourceW, source);
2257 RtlCreateUnicodeStringFromAsciiz(&destW, dest);
2259 ret = CopyFileW(sourceW.Buffer, destW.Buffer, fail_if_exists);
2261 RtlFreeUnicodeString(&sourceW);
2262 RtlFreeUnicodeString(&destW);
2263 return ret;
2267 /**************************************************************************
2268 * CopyFileExW (KERNEL32.@)
2270 * This implementation ignores most of the extra parameters passed-in into
2271 * the "ex" version of the method and calls the CopyFile method.
2272 * It will have to be fixed eventually.
2274 BOOL WINAPI CopyFileExW(LPCWSTR sourceFilename, LPCWSTR destFilename,
2275 LPPROGRESS_ROUTINE progressRoutine, LPVOID appData,
2276 LPBOOL cancelFlagPointer, DWORD copyFlags)
2279 * Interpret the only flag that CopyFile can interpret.
2281 return CopyFileW(sourceFilename, destFilename, (copyFlags & COPY_FILE_FAIL_IF_EXISTS) != 0);
2285 /**************************************************************************
2286 * CopyFileExA (KERNEL32.@)
2288 BOOL WINAPI CopyFileExA(LPCSTR sourceFilename, LPCSTR destFilename,
2289 LPPROGRESS_ROUTINE progressRoutine, LPVOID appData,
2290 LPBOOL cancelFlagPointer, DWORD copyFlags)
2292 UNICODE_STRING sourceW, destW;
2293 BOOL ret;
2295 if (!sourceFilename || !destFilename)
2297 SetLastError(ERROR_INVALID_PARAMETER);
2298 return FALSE;
2301 RtlCreateUnicodeStringFromAsciiz(&sourceW, sourceFilename);
2302 RtlCreateUnicodeStringFromAsciiz(&destW, destFilename);
2304 ret = CopyFileExW(sourceW.Buffer, destW.Buffer, progressRoutine, appData,
2305 cancelFlagPointer, copyFlags);
2307 RtlFreeUnicodeString(&sourceW);
2308 RtlFreeUnicodeString(&destW);
2309 return ret;
2313 /***********************************************************************
2314 * SetFileTime (KERNEL32.@)
2316 BOOL WINAPI SetFileTime( HANDLE hFile,
2317 const FILETIME *lpCreationTime,
2318 const FILETIME *lpLastAccessTime,
2319 const FILETIME *lpLastWriteTime )
2321 BOOL ret;
2322 SERVER_START_REQ( set_file_time )
2324 req->handle = hFile;
2325 if (lpLastAccessTime)
2326 RtlTimeToSecondsSince1970( (PLARGE_INTEGER) lpLastAccessTime, (DWORD *)&req->access_time );
2327 else
2328 req->access_time = 0; /* FIXME */
2329 if (lpLastWriteTime)
2330 RtlTimeToSecondsSince1970( (PLARGE_INTEGER) lpLastWriteTime, (DWORD *)&req->write_time );
2331 else
2332 req->write_time = 0; /* FIXME */
2333 ret = !wine_server_call_err( req );
2335 SERVER_END_REQ;
2336 return ret;
2340 /**************************************************************************
2341 * GetFileAttributesExW (KERNEL32.@)
2343 BOOL WINAPI GetFileAttributesExW(
2344 LPCWSTR lpFileName, GET_FILEEX_INFO_LEVELS fInfoLevelId,
2345 LPVOID lpFileInformation)
2347 DOS_FULL_NAME full_name;
2348 BY_HANDLE_FILE_INFORMATION info;
2350 if (!lpFileName || !lpFileInformation)
2352 SetLastError(ERROR_INVALID_PARAMETER);
2353 return FALSE;
2356 if (fInfoLevelId == GetFileExInfoStandard) {
2357 LPWIN32_FILE_ATTRIBUTE_DATA lpFad =
2358 (LPWIN32_FILE_ATTRIBUTE_DATA) lpFileInformation;
2359 if (!DOSFS_GetFullName( lpFileName, TRUE, &full_name )) return FALSE;
2360 if (!FILE_Stat( full_name.long_name, &info, NULL )) return FALSE;
2362 lpFad->dwFileAttributes = info.dwFileAttributes;
2363 lpFad->ftCreationTime = info.ftCreationTime;
2364 lpFad->ftLastAccessTime = info.ftLastAccessTime;
2365 lpFad->ftLastWriteTime = info.ftLastWriteTime;
2366 lpFad->nFileSizeHigh = info.nFileSizeHigh;
2367 lpFad->nFileSizeLow = info.nFileSizeLow;
2369 else {
2370 FIXME("invalid info level %d!\n", fInfoLevelId);
2371 return FALSE;
2374 return TRUE;
2378 /**************************************************************************
2379 * GetFileAttributesExA (KERNEL32.@)
2381 BOOL WINAPI GetFileAttributesExA(
2382 LPCSTR filename, GET_FILEEX_INFO_LEVELS fInfoLevelId,
2383 LPVOID lpFileInformation)
2385 UNICODE_STRING filenameW;
2386 BOOL ret = FALSE;
2388 if (!filename || !lpFileInformation)
2390 SetLastError(ERROR_INVALID_PARAMETER);
2391 return FALSE;
2394 if (RtlCreateUnicodeStringFromAsciiz(&filenameW, filename))
2396 ret = GetFileAttributesExW(filenameW.Buffer, fInfoLevelId, lpFileInformation);
2397 RtlFreeUnicodeString(&filenameW);
2399 else
2400 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
2401 return ret;