int33 21h is identical to int33 00h.
[wine.git] / files / file.c
blob3d2ad8b0b8c7a372feb9f5c6310c4ec8d817a17b
1 /*
2 * File handling functions
4 * Copyright 1993 John Burton
5 * Copyright 1996 Alexandre Julliard
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 * TODO:
22 * Fix the CopyFileEx methods to implement the "extended" functionality.
23 * Right now, they simply call the CopyFile method.
26 #include "config.h"
27 #include "wine/port.h"
29 #include <assert.h>
30 #include <ctype.h>
31 #include <errno.h>
32 #include <fcntl.h>
33 #include <stdlib.h>
34 #include <stdio.h>
35 #include <string.h>
36 #ifdef HAVE_SYS_ERRNO_H
37 #include <sys/errno.h>
38 #endif
39 #include <sys/types.h>
40 #include <sys/stat.h>
41 #ifdef HAVE_SYS_MMAN_H
42 #include <sys/mman.h>
43 #endif
44 #ifdef HAVE_SYS_TIME_H
45 # include <sys/time.h>
46 #endif
47 #ifdef HAVE_SYS_POLL_H
48 # include <sys/poll.h>
49 #endif
50 #include <time.h>
51 #ifdef HAVE_UNISTD_H
52 # include <unistd.h>
53 #endif
54 #ifdef HAVE_UTIME_H
55 # include <utime.h>
56 #endif
58 #define NONAMELESSUNION
59 #define NONAMELESSSTRUCT
60 #include "winerror.h"
61 #include "windef.h"
62 #include "winbase.h"
63 #include "winternl.h"
64 #include "wine/winbase16.h"
65 #include "wine/server.h"
67 #include "drive.h"
68 #include "file.h"
69 #include "heap.h"
70 #include "msdos.h"
71 #include "wincon.h"
72 #include "../kernel/kernel_private.h"
74 #include "smb.h"
75 #include "wine/unicode.h"
76 #include "wine/debug.h"
78 WINE_DEFAULT_DEBUG_CHANNEL(file);
80 #if defined(MAP_ANONYMOUS) && !defined(MAP_ANON)
81 #define MAP_ANON MAP_ANONYMOUS
82 #endif
84 #define IS_OPTION_TRUE(ch) ((ch) == 'y' || (ch) == 'Y' || (ch) == 't' || (ch) == 'T' || (ch) == '1')
86 HANDLE dos_handles[DOS_TABLE_SIZE];
87 mode_t FILE_umask;
89 /***********************************************************************
90 * FILE_ConvertOFMode
92 * Convert OF_* mode into flags for CreateFile.
94 void FILE_ConvertOFMode( INT mode, DWORD *access, DWORD *sharing )
96 switch(mode & 0x03)
98 case OF_READ: *access = GENERIC_READ; break;
99 case OF_WRITE: *access = GENERIC_WRITE; break;
100 case OF_READWRITE: *access = GENERIC_READ | GENERIC_WRITE; break;
101 default: *access = 0; break;
103 switch(mode & 0x70)
105 case OF_SHARE_EXCLUSIVE: *sharing = 0; break;
106 case OF_SHARE_DENY_WRITE: *sharing = FILE_SHARE_READ; break;
107 case OF_SHARE_DENY_READ: *sharing = FILE_SHARE_WRITE; break;
108 case OF_SHARE_DENY_NONE:
109 case OF_SHARE_COMPAT:
110 default: *sharing = FILE_SHARE_READ | FILE_SHARE_WRITE; break;
115 /***********************************************************************
116 * FILE_strcasecmp
118 * locale-independent case conversion for file I/O
120 int FILE_strcasecmp( const char *str1, const char *str2 )
122 int ret = 0;
123 for ( ; ; str1++, str2++)
124 if ((ret = FILE_toupper(*str1) - FILE_toupper(*str2)) || !*str1) break;
125 return ret;
129 /***********************************************************************
130 * FILE_strncasecmp
132 * locale-independent case conversion for file I/O
134 int FILE_strncasecmp( const char *str1, const char *str2, int len )
136 int ret = 0;
137 for ( ; len > 0; len--, str1++, str2++)
138 if ((ret = FILE_toupper(*str1) - FILE_toupper(*str2)) || !*str1) break;
139 return ret;
143 /***********************************************************************
144 * FILE_SetDosError
146 * Set the DOS error code from errno.
148 void FILE_SetDosError(void)
150 int save_errno = errno; /* errno gets overwritten by printf */
152 TRACE("errno = %d %s\n", errno, strerror(errno));
153 switch (save_errno)
155 case EAGAIN:
156 SetLastError( ERROR_SHARING_VIOLATION );
157 break;
158 case EBADF:
159 SetLastError( ERROR_INVALID_HANDLE );
160 break;
161 case ENOSPC:
162 SetLastError( ERROR_HANDLE_DISK_FULL );
163 break;
164 case EACCES:
165 case EPERM:
166 case EROFS:
167 SetLastError( ERROR_ACCESS_DENIED );
168 break;
169 case EBUSY:
170 SetLastError( ERROR_LOCK_VIOLATION );
171 break;
172 case ENOENT:
173 SetLastError( ERROR_FILE_NOT_FOUND );
174 break;
175 case EISDIR:
176 SetLastError( ERROR_CANNOT_MAKE );
177 break;
178 case ENFILE:
179 case EMFILE:
180 SetLastError( ERROR_NO_MORE_FILES );
181 break;
182 case EEXIST:
183 SetLastError( ERROR_FILE_EXISTS );
184 break;
185 case EINVAL:
186 case ESPIPE:
187 SetLastError( ERROR_SEEK );
188 break;
189 case ENOTEMPTY:
190 SetLastError( ERROR_DIR_NOT_EMPTY );
191 break;
192 case ENOEXEC:
193 SetLastError( ERROR_BAD_FORMAT );
194 break;
195 default:
196 WARN("unknown file error: %s\n", strerror(save_errno) );
197 SetLastError( ERROR_GEN_FAILURE );
198 break;
200 errno = save_errno;
204 /***********************************************************************
205 * FILE_GetUnixHandleType
207 * Retrieve the Unix handle corresponding to a file handle.
208 * Returns -1 on failure.
210 static int FILE_GetUnixHandleType( HANDLE handle, DWORD access, enum fd_type *type, int *flags_ptr )
212 int ret, flags, fd = -1;
214 ret = wine_server_handle_to_fd( handle, access, &fd, type, &flags );
215 if (flags_ptr) *flags_ptr = flags;
216 if (ret) SetLastError( RtlNtStatusToDosError(ret) );
217 else if (((access & GENERIC_READ) && (flags & FD_FLAG_RECV_SHUTDOWN)) ||
218 ((access & GENERIC_WRITE) && (flags & FD_FLAG_SEND_SHUTDOWN)))
220 close (fd);
221 SetLastError ( ERROR_PIPE_NOT_CONNECTED );
222 return -1;
224 return fd;
227 /***********************************************************************
228 * FILE_GetUnixHandle
230 * Retrieve the Unix handle corresponding to a file handle.
231 * Returns -1 on failure.
233 int FILE_GetUnixHandle( HANDLE handle, DWORD access )
235 return FILE_GetUnixHandleType( handle, access, NULL, NULL );
238 /******************************************************************
239 * OpenConsoleW (KERNEL32.@)
241 * Undocumented
242 * Open a handle to the current process console.
243 * Returns INVALID_HANDLE_VALUE on failure.
245 HANDLE WINAPI OpenConsoleW(LPCWSTR name, DWORD access, LPSECURITY_ATTRIBUTES sa,
246 DWORD creation)
248 static const WCHAR coninW[] = {'C','O','N','I','N','$',0};
249 static const WCHAR conoutW[] = {'C','O','N','O','U','T','$',0};
250 BOOL output;
251 HANDLE ret;
253 if (strcmpW(coninW, name) == 0)
254 output = FALSE;
255 else if (strcmpW(conoutW, name) == 0)
256 output = TRUE;
257 else
259 SetLastError(ERROR_INVALID_NAME);
260 return INVALID_HANDLE_VALUE;
262 if (creation != OPEN_EXISTING)
264 SetLastError(ERROR_INVALID_PARAMETER);
265 return INVALID_HANDLE_VALUE;
268 SERVER_START_REQ( open_console )
270 req->from = output;
271 req->access = access;
272 req->share = FILE_SHARE_READ | FILE_SHARE_WRITE;
273 req->inherit = (sa && (sa->nLength>=sizeof(*sa)) && sa->bInheritHandle);
274 SetLastError(0);
275 wine_server_call_err( req );
276 ret = reply->handle;
278 SERVER_END_REQ;
279 return ret ? console_handle_map(ret) : INVALID_HANDLE_VALUE;
282 /******************************************************************
283 * VerifyConsoleIoHandle (KERNEL32.@)
285 * Undocumented
287 BOOL WINAPI VerifyConsoleIoHandle(HANDLE handle)
289 BOOL ret;
291 if (!is_console_handle(handle)) return FALSE;
292 SERVER_START_REQ(get_console_mode)
294 req->handle = console_handle_unmap(handle);
295 ret = !wine_server_call_err( req );
297 SERVER_END_REQ;
298 return ret;
301 /******************************************************************
302 * DuplicateConsoleHandle (KERNEL32.@)
304 * Undocumented
306 HANDLE WINAPI DuplicateConsoleHandle(HANDLE handle, DWORD access, BOOL inherit,
307 DWORD options)
309 HANDLE ret;
311 if (!is_console_handle(handle) ||
312 !DuplicateHandle(GetCurrentProcess(), console_handle_unmap(handle),
313 GetCurrentProcess(), &ret, access, inherit, options))
314 return INVALID_HANDLE_VALUE;
315 return console_handle_map(ret);
318 /******************************************************************
319 * CloseConsoleHandle (KERNEL32.@)
321 * Undocumented
323 BOOL WINAPI CloseConsoleHandle(HANDLE handle)
325 if (!is_console_handle(handle))
327 SetLastError(ERROR_INVALID_PARAMETER);
328 return FALSE;
330 return CloseHandle(console_handle_unmap(handle));
333 /******************************************************************
334 * GetConsoleInputWaitHandle (KERNEL32.@)
336 * Undocumented
338 HANDLE WINAPI GetConsoleInputWaitHandle(void)
340 static HANDLE console_wait_event;
342 /* FIXME: this is not thread safe */
343 if (!console_wait_event)
345 SERVER_START_REQ(get_console_wait_event)
347 if (!wine_server_call_err( req )) console_wait_event = reply->handle;
349 SERVER_END_REQ;
351 return console_wait_event;
353 /* end of FIXME */
356 /* FIXME: those routines defined as pointers are needed, because this file is
357 * currently compiled into NTDLL whereas it belongs to kernel32.
358 * this shall go away once all the DLL separation process is done
360 typedef BOOL (WINAPI* pRW)(HANDLE, const void*, DWORD, DWORD*, void*);
362 static BOOL FILE_ReadConsole(HANDLE hCon, void* buf, DWORD nb, DWORD* nr, void* p)
364 static HANDLE hKernel /* = 0 */;
365 static pRW pReadConsole /* = 0 */;
367 if ((!hKernel && !(hKernel = LoadLibraryA("kernel32"))) ||
368 (!pReadConsole &&
369 !(pReadConsole = GetProcAddress(hKernel, "ReadConsoleA"))))
371 *nr = 0;
372 return 0;
374 return (pReadConsole)(hCon, buf, nb, nr, p);
377 static BOOL FILE_WriteConsole(HANDLE hCon, const void* buf, DWORD nb, DWORD* nr, void* p)
379 static HANDLE hKernel /* = 0 */;
380 static pRW pWriteConsole /* = 0 */;
382 if ((!hKernel && !(hKernel = LoadLibraryA("kernel32"))) ||
383 (!pWriteConsole &&
384 !(pWriteConsole = GetProcAddress(hKernel, "WriteConsoleA"))))
386 *nr = 0;
387 return 0;
389 return (pWriteConsole)(hCon, buf, nb, nr, p);
391 /* end of FIXME */
393 /***********************************************************************
394 * FILE_CreateFile
396 * Implementation of CreateFile. Takes a Unix path name.
397 * Returns 0 on failure.
399 HANDLE FILE_CreateFile( LPCSTR filename, DWORD access, DWORD sharing,
400 LPSECURITY_ATTRIBUTES sa, DWORD creation,
401 DWORD attributes, HANDLE template, BOOL fail_read_only,
402 UINT drive_type )
404 unsigned int err;
405 HANDLE ret;
407 for (;;)
409 SERVER_START_REQ( create_file )
411 req->access = access;
412 req->inherit = (sa && (sa->nLength>=sizeof(*sa)) && sa->bInheritHandle);
413 req->sharing = sharing;
414 req->create = creation;
415 req->attrs = attributes;
416 req->drive_type = drive_type;
417 wine_server_add_data( req, filename, strlen(filename) );
418 SetLastError(0);
419 err = wine_server_call( req );
420 ret = reply->handle;
422 SERVER_END_REQ;
424 /* If write access failed, retry without GENERIC_WRITE */
426 if (!ret && !fail_read_only && (access & GENERIC_WRITE))
428 if ((err == STATUS_MEDIA_WRITE_PROTECTED) || (err == STATUS_ACCESS_DENIED))
430 TRACE("Write access failed for file '%s', trying without "
431 "write access\n", filename);
432 access &= ~GENERIC_WRITE;
433 continue;
437 if (err)
439 /* In the case file creation was rejected due to CREATE_NEW flag
440 * was specified and file with that name already exists, correct
441 * last error is ERROR_FILE_EXISTS and not ERROR_ALREADY_EXISTS.
442 * Note: RtlNtStatusToDosError is not the subject to blame here.
444 if (err == STATUS_OBJECT_NAME_COLLISION)
445 SetLastError( ERROR_FILE_EXISTS );
446 else
447 SetLastError( RtlNtStatusToDosError(err) );
450 if (!ret) WARN("Unable to create file '%s' (GLE %ld)\n", filename, GetLastError());
451 return ret;
456 /***********************************************************************
457 * FILE_CreateDevice
459 * Same as FILE_CreateFile but for a device
460 * Returns 0 on failure.
462 HANDLE FILE_CreateDevice( int client_id, DWORD access, LPSECURITY_ATTRIBUTES sa )
464 HANDLE ret;
465 SERVER_START_REQ( create_device )
467 req->access = access;
468 req->inherit = (sa && (sa->nLength>=sizeof(*sa)) && sa->bInheritHandle);
469 req->id = client_id;
470 SetLastError(0);
471 wine_server_call_err( req );
472 ret = reply->handle;
474 SERVER_END_REQ;
475 return ret;
478 static HANDLE FILE_OpenPipe(LPCWSTR name, DWORD access, LPSECURITY_ATTRIBUTES sa )
480 HANDLE ret;
481 DWORD len = 0;
483 if (name && (len = strlenW(name)) > MAX_PATH)
485 SetLastError( ERROR_FILENAME_EXCED_RANGE );
486 return 0;
488 SERVER_START_REQ( open_named_pipe )
490 req->access = access;
491 req->inherit = (sa && (sa->nLength>=sizeof(*sa)) && sa->bInheritHandle);
492 SetLastError(0);
493 wine_server_add_data( req, name, len * sizeof(WCHAR) );
494 wine_server_call_err( req );
495 ret = reply->handle;
497 SERVER_END_REQ;
498 TRACE("Returned %p\n",ret);
499 return ret;
502 /*************************************************************************
503 * CreateFileW [KERNEL32.@] Creates or opens a file or other object
505 * Creates or opens an object, and returns a handle that can be used to
506 * access that object.
508 * PARAMS
510 * filename [in] pointer to filename to be accessed
511 * access [in] access mode requested
512 * sharing [in] share mode
513 * sa [in] pointer to security attributes
514 * creation [in] how to create the file
515 * attributes [in] attributes for newly created file
516 * template [in] handle to file with extended attributes to copy
518 * RETURNS
519 * Success: Open handle to specified file
520 * Failure: INVALID_HANDLE_VALUE
522 * NOTES
523 * Should call SetLastError() on failure.
525 * BUGS
527 * Doesn't support character devices, template files, or a
528 * lot of the 'attributes' flags yet.
530 HANDLE WINAPI CreateFileW( LPCWSTR filename, DWORD access, DWORD sharing,
531 LPSECURITY_ATTRIBUTES sa, DWORD creation,
532 DWORD attributes, HANDLE template )
534 DOS_FULL_NAME full_name;
535 HANDLE ret;
536 static const WCHAR bkslashes_with_question_markW[] = {'\\','\\','?','\\',0};
537 static const WCHAR bkslashes_with_dotW[] = {'\\','\\','.','\\',0};
538 static const WCHAR bkslashesW[] = {'\\','\\',0};
539 static const WCHAR coninW[] = {'C','O','N','I','N','$',0};
540 static const WCHAR conoutW[] = {'C','O','N','O','U','T','$',0};
542 if (!filename)
544 SetLastError( ERROR_INVALID_PARAMETER );
545 return INVALID_HANDLE_VALUE;
547 TRACE("%s %s%s%s%s%s%s%s attributes 0x%lx\n", debugstr_w(filename),
548 ((access & GENERIC_READ)==GENERIC_READ)?"GENERIC_READ ":"",
549 ((access & GENERIC_WRITE)==GENERIC_WRITE)?"GENERIC_WRITE ":"",
550 (!access)?"QUERY_ACCESS ":"",
551 ((sharing & FILE_SHARE_READ)==FILE_SHARE_READ)?"FILE_SHARE_READ ":"",
552 ((sharing & FILE_SHARE_WRITE)==FILE_SHARE_WRITE)?"FILE_SHARE_WRITE ":"",
553 ((sharing & FILE_SHARE_DELETE)==FILE_SHARE_DELETE)?"FILE_SHARE_DELETE ":"",
554 (creation ==CREATE_NEW)?"CREATE_NEW":
555 (creation ==CREATE_ALWAYS)?"CREATE_ALWAYS ":
556 (creation ==OPEN_EXISTING)?"OPEN_EXISTING ":
557 (creation ==OPEN_ALWAYS)?"OPEN_ALWAYS ":
558 (creation ==TRUNCATE_EXISTING)?"TRUNCATE_EXISTING ":"", attributes);
560 /* If the name starts with '\\?\', ignore the first 4 chars. */
561 if (!strncmpW(filename, bkslashes_with_question_markW, 4))
563 static const WCHAR uncW[] = {'U','N','C','\\',0};
564 filename += 4;
565 if (!strncmpiW(filename, uncW, 4))
567 FIXME("UNC name (%s) not supported.\n", debugstr_w(filename) );
568 SetLastError( ERROR_PATH_NOT_FOUND );
569 return INVALID_HANDLE_VALUE;
573 if (!strncmpW(filename, bkslashes_with_dotW, 4))
575 static const WCHAR pipeW[] = {'P','I','P','E','\\',0};
576 if(!strncmpiW(filename + 4, pipeW, 5))
578 TRACE("Opening a pipe: %s\n", debugstr_w(filename));
579 ret = FILE_OpenPipe( filename, access, sa );
580 goto done;
582 else if (isalphaW(filename[4]) && filename[5] == ':' && filename[6] == '\0')
584 ret = FILE_CreateDevice( (toupperW(filename[4]) - 'A') | 0x20000, access, sa );
585 goto done;
587 else if (!DOSFS_GetDevice( filename ))
589 ret = DEVICE_Open( filename+4, access, sa );
590 goto done;
592 else
593 filename+=4; /* fall into DOSFS_Device case below */
596 /* If the name still starts with '\\', it's a UNC name. */
597 if (!strncmpW(filename, bkslashesW, 2))
599 ret = SMB_CreateFileW(filename, access, sharing, sa, creation, attributes, template );
600 goto done;
603 /* If the name contains a DOS wild card (* or ?), do no create a file */
604 if(strchrW(filename, '*') || strchrW(filename, '?'))
606 SetLastError(ERROR_BAD_PATHNAME);
607 return INVALID_HANDLE_VALUE;
610 /* Open a console for CONIN$ or CONOUT$ */
611 if (!strcmpiW(filename, coninW) || !strcmpiW(filename, conoutW))
613 ret = OpenConsoleW(filename, access, sa, creation);
614 goto done;
617 if (DOSFS_GetDevice( filename ))
619 TRACE("opening device %s\n", debugstr_w(filename) );
621 if (!(ret = DOSFS_OpenDevice( filename, access, attributes, sa )))
623 /* Do not silence this please. It is a critical error. -MM */
624 ERR("Couldn't open device %s!\n", debugstr_w(filename));
625 SetLastError( ERROR_FILE_NOT_FOUND );
627 goto done;
630 /* check for filename, don't check for last entry if creating */
631 if (!DOSFS_GetFullName( filename,
632 (creation == OPEN_EXISTING) ||
633 (creation == TRUNCATE_EXISTING),
634 &full_name )) {
635 WARN("Unable to get full filename from %s (GLE %ld)\n",
636 debugstr_w(filename), GetLastError());
637 return INVALID_HANDLE_VALUE;
640 ret = FILE_CreateFile( full_name.long_name, access, sharing,
641 sa, creation, attributes, template,
642 DRIVE_GetFlags(full_name.drive) & DRIVE_FAIL_READ_ONLY,
643 GetDriveTypeW( full_name.short_name ) );
644 done:
645 if (!ret) ret = INVALID_HANDLE_VALUE;
646 TRACE("returning %p\n", ret);
647 return ret;
652 /*************************************************************************
653 * CreateFileA (KERNEL32.@)
655 HANDLE WINAPI CreateFileA( LPCSTR filename, DWORD access, DWORD sharing,
656 LPSECURITY_ATTRIBUTES sa, DWORD creation,
657 DWORD attributes, HANDLE template)
659 UNICODE_STRING filenameW;
660 HANDLE ret = INVALID_HANDLE_VALUE;
662 if (!filename)
664 SetLastError( ERROR_INVALID_PARAMETER );
665 return INVALID_HANDLE_VALUE;
668 if (RtlCreateUnicodeStringFromAsciiz(&filenameW, filename))
670 ret = CreateFileW(filenameW.Buffer, access, sharing, sa, creation,
671 attributes, template);
672 RtlFreeUnicodeString(&filenameW);
674 else
675 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
676 return ret;
680 /***********************************************************************
681 * FILE_FillInfo
683 * Fill a file information from a struct stat.
685 static void FILE_FillInfo( struct stat *st, BY_HANDLE_FILE_INFORMATION *info )
687 if (S_ISDIR(st->st_mode))
688 info->dwFileAttributes = FILE_ATTRIBUTE_DIRECTORY;
689 else
690 info->dwFileAttributes = FILE_ATTRIBUTE_ARCHIVE;
691 if (!(st->st_mode & S_IWUSR))
692 info->dwFileAttributes |= FILE_ATTRIBUTE_READONLY;
694 RtlSecondsSince1970ToTime( st->st_mtime, (LARGE_INTEGER *)&info->ftCreationTime );
695 RtlSecondsSince1970ToTime( st->st_mtime, (LARGE_INTEGER *)&info->ftLastWriteTime );
696 RtlSecondsSince1970ToTime( st->st_atime, (LARGE_INTEGER *)&info->ftLastAccessTime );
698 info->dwVolumeSerialNumber = 0; /* FIXME */
699 info->nFileSizeHigh = 0;
700 info->nFileSizeLow = 0;
701 if (!S_ISDIR(st->st_mode)) {
702 info->nFileSizeHigh = st->st_size >> 32;
703 info->nFileSizeLow = st->st_size & 0xffffffff;
705 info->nNumberOfLinks = st->st_nlink;
706 info->nFileIndexHigh = 0;
707 info->nFileIndexLow = st->st_ino;
711 /***********************************************************************
712 * get_show_dot_files_option
714 static BOOL get_show_dot_files_option(void)
716 static const WCHAR WineW[] = {'M','a','c','h','i','n','e','\\',
717 'S','o','f','t','w','a','r','e','\\',
718 'W','i','n','e','\\','W','i','n','e','\\',
719 'C','o','n','f','i','g','\\','W','i','n','e',0};
720 static const WCHAR ShowDotFilesW[] = {'S','h','o','w','D','o','t','F','i','l','e','s',0};
722 char tmp[80];
723 HKEY hkey;
724 DWORD dummy;
725 OBJECT_ATTRIBUTES attr;
726 UNICODE_STRING nameW;
727 BOOL ret = FALSE;
729 attr.Length = sizeof(attr);
730 attr.RootDirectory = 0;
731 attr.ObjectName = &nameW;
732 attr.Attributes = 0;
733 attr.SecurityDescriptor = NULL;
734 attr.SecurityQualityOfService = NULL;
735 RtlInitUnicodeString( &nameW, WineW );
737 if (!NtOpenKey( &hkey, KEY_ALL_ACCESS, &attr ))
739 RtlInitUnicodeString( &nameW, ShowDotFilesW );
740 if (!NtQueryValueKey( hkey, &nameW, KeyValuePartialInformation, tmp, sizeof(tmp), &dummy ))
742 WCHAR *str = (WCHAR *)((KEY_VALUE_PARTIAL_INFORMATION *)tmp)->Data;
743 ret = IS_OPTION_TRUE( str[0] );
745 NtClose( hkey );
747 return ret;
751 /***********************************************************************
752 * FILE_Stat
754 * Stat a Unix path name. Return TRUE if OK.
756 BOOL FILE_Stat( LPCSTR unixName, BY_HANDLE_FILE_INFORMATION *info, BOOL *is_symlink_ptr )
758 struct stat st;
759 int is_symlink;
760 LPCSTR p;
762 if (lstat( unixName, &st ) == -1)
764 FILE_SetDosError();
765 return FALSE;
767 is_symlink = S_ISLNK(st.st_mode);
768 if (is_symlink)
770 /* do a "real" stat to find out
771 about the type of the symlink destination */
772 if (stat( unixName, &st ) == -1)
774 FILE_SetDosError();
775 return FALSE;
779 /* fill in the information we gathered so far */
780 FILE_FillInfo( &st, info );
782 /* and now see if this is a hidden file, based on the name */
783 p = strrchr( unixName, '/');
784 p = p ? p + 1 : unixName;
785 if (*p == '.' && *(p+1) && (*(p+1) != '.' || *(p+2)))
787 static int show_dot_files = -1;
788 if (show_dot_files == -1)
789 show_dot_files = get_show_dot_files_option();
790 if (!show_dot_files)
791 info->dwFileAttributes |= FILE_ATTRIBUTE_HIDDEN;
793 if (is_symlink_ptr) *is_symlink_ptr = is_symlink;
794 return TRUE;
798 /***********************************************************************
799 * GetFileInformationByHandle (KERNEL32.@)
801 DWORD WINAPI GetFileInformationByHandle( HANDLE hFile,
802 BY_HANDLE_FILE_INFORMATION *info )
804 DWORD ret;
805 if (!info) return 0;
807 TRACE("%p\n", hFile);
809 SERVER_START_REQ( get_file_info )
811 req->handle = hFile;
812 if ((ret = !wine_server_call_err( req )))
814 /* FIXME: which file types are supported ?
815 * Serial ports (FILE_TYPE_CHAR) are not,
816 * and MSDN also says that pipes are not supported.
817 * FILE_TYPE_REMOTE seems to be supported according to
818 * MSDN q234741.txt */
819 if ((reply->type == FILE_TYPE_DISK) || (reply->type == FILE_TYPE_REMOTE))
821 RtlSecondsSince1970ToTime( reply->write_time, (LARGE_INTEGER *)&info->ftCreationTime );
822 RtlSecondsSince1970ToTime( reply->write_time, (LARGE_INTEGER *)&info->ftLastWriteTime );
823 RtlSecondsSince1970ToTime( reply->access_time, (LARGE_INTEGER *)&info->ftLastAccessTime );
824 info->dwFileAttributes = reply->attr;
825 info->dwVolumeSerialNumber = reply->serial;
826 info->nFileSizeHigh = reply->size_high;
827 info->nFileSizeLow = reply->size_low;
828 info->nNumberOfLinks = reply->links;
829 info->nFileIndexHigh = reply->index_high;
830 info->nFileIndexLow = reply->index_low;
832 else
834 SetLastError(ERROR_NOT_SUPPORTED);
835 ret = 0;
839 SERVER_END_REQ;
840 return ret;
844 /**************************************************************************
845 * GetFileAttributesW (KERNEL32.@)
847 DWORD WINAPI GetFileAttributesW( LPCWSTR name )
849 DOS_FULL_NAME full_name;
850 BY_HANDLE_FILE_INFORMATION info;
852 if (name == NULL)
854 SetLastError( ERROR_INVALID_PARAMETER );
855 return -1;
857 if (!DOSFS_GetFullName( name, TRUE, &full_name) )
858 return -1;
859 if (!FILE_Stat( full_name.long_name, &info, NULL )) return -1;
860 return info.dwFileAttributes;
864 /**************************************************************************
865 * GetFileAttributesA (KERNEL32.@)
867 DWORD WINAPI GetFileAttributesA( LPCSTR name )
869 UNICODE_STRING nameW;
870 DWORD ret = (DWORD)-1;
872 if (!name)
874 SetLastError( ERROR_INVALID_PARAMETER );
875 return (DWORD)-1;
878 if (RtlCreateUnicodeStringFromAsciiz(&nameW, name))
880 ret = GetFileAttributesW(nameW.Buffer);
881 RtlFreeUnicodeString(&nameW);
883 else
884 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
885 return ret;
889 /**************************************************************************
890 * SetFileAttributesW (KERNEL32.@)
892 BOOL WINAPI SetFileAttributesW(LPCWSTR lpFileName, DWORD attributes)
894 struct stat buf;
895 DOS_FULL_NAME full_name;
897 if (!lpFileName)
899 SetLastError( ERROR_INVALID_PARAMETER );
900 return FALSE;
903 TRACE("(%s,%lx)\n", debugstr_w(lpFileName), attributes);
905 if (!DOSFS_GetFullName( lpFileName, TRUE, &full_name ))
906 return FALSE;
908 if(stat(full_name.long_name,&buf)==-1)
910 FILE_SetDosError();
911 return FALSE;
913 if (attributes & FILE_ATTRIBUTE_READONLY)
915 if(S_ISDIR(buf.st_mode))
916 /* FIXME */
917 WARN("FILE_ATTRIBUTE_READONLY ignored for directory.\n");
918 else
919 buf.st_mode &= ~0222; /* octal!, clear write permission bits */
920 attributes &= ~FILE_ATTRIBUTE_READONLY;
922 else
924 /* add write permission */
925 buf.st_mode |= (0600 | ((buf.st_mode & 044) >> 1)) & (~FILE_umask);
927 if (attributes & FILE_ATTRIBUTE_DIRECTORY)
929 if (!S_ISDIR(buf.st_mode))
930 FIXME("SetFileAttributes expected the file %s to be a directory\n",
931 debugstr_w(lpFileName));
932 attributes &= ~FILE_ATTRIBUTE_DIRECTORY;
934 attributes &= ~(FILE_ATTRIBUTE_NORMAL|FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_HIDDEN|FILE_ATTRIBUTE_SYSTEM);
935 if (attributes)
936 FIXME("(%s):%lx attribute(s) not implemented.\n", debugstr_w(lpFileName), attributes);
937 if (-1==chmod(full_name.long_name,buf.st_mode))
939 if (GetDriveTypeW(lpFileName) == DRIVE_CDROM)
941 SetLastError( ERROR_ACCESS_DENIED );
942 return FALSE;
946 * FIXME: We don't return FALSE here because of differences between
947 * Linux and Windows privileges. Under Linux only the owner of
948 * the file is allowed to change file attributes. Under Windows,
949 * applications expect that if you can write to a file, you can also
950 * change its attributes (see GENERIC_WRITE). We could try to be
951 * clever here but that would break multi-user installations where
952 * users share read-only DLLs. This is because some installers like
953 * to change attributes of already installed DLLs.
955 FIXME("Couldn't set file attributes for existing file \"%s\".\n"
956 "Check permissions or set VFAT \"quiet\" mount flag\n", full_name.long_name);
958 return TRUE;
962 /**************************************************************************
963 * SetFileAttributesA (KERNEL32.@)
965 BOOL WINAPI SetFileAttributesA(LPCSTR lpFileName, DWORD attributes)
967 UNICODE_STRING filenameW;
968 BOOL ret = FALSE;
970 if (!lpFileName)
972 SetLastError( ERROR_INVALID_PARAMETER );
973 return FALSE;
976 if (RtlCreateUnicodeStringFromAsciiz(&filenameW, lpFileName))
978 ret = SetFileAttributesW(filenameW.Buffer, attributes);
979 RtlFreeUnicodeString(&filenameW);
981 else
982 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
983 return ret;
987 /***********************************************************************
988 * GetFileTime (KERNEL32.@)
990 BOOL WINAPI GetFileTime( HANDLE hFile, FILETIME *lpCreationTime,
991 FILETIME *lpLastAccessTime,
992 FILETIME *lpLastWriteTime )
994 BY_HANDLE_FILE_INFORMATION info;
995 if (!GetFileInformationByHandle( hFile, &info )) return FALSE;
996 if (lpCreationTime) *lpCreationTime = info.ftCreationTime;
997 if (lpLastAccessTime) *lpLastAccessTime = info.ftLastAccessTime;
998 if (lpLastWriteTime) *lpLastWriteTime = info.ftLastWriteTime;
999 return TRUE;
1003 /***********************************************************************
1004 * FILE_GetTempFileName : utility for GetTempFileName
1006 static UINT FILE_GetTempFileName( LPCWSTR path, LPCWSTR prefix, UINT unique,
1007 LPWSTR buffer )
1009 static UINT unique_temp;
1010 DOS_FULL_NAME full_name;
1011 int i;
1012 LPWSTR p;
1013 UINT num;
1014 char buf[20];
1016 if ( !path || !prefix || !buffer )
1018 SetLastError( ERROR_INVALID_PARAMETER );
1019 return 0;
1022 if (!unique_temp) unique_temp = time(NULL) & 0xffff;
1023 num = unique ? (unique & 0xffff) : (unique_temp++ & 0xffff);
1025 strcpyW( buffer, path );
1026 p = buffer + strlenW(buffer);
1028 /* add a \, if there isn't one and path is more than just the drive letter ... */
1029 if ( !((strlenW(buffer) == 2) && (buffer[1] == ':'))
1030 && ((p == buffer) || (p[-1] != '\\'))) *p++ = '\\';
1032 for (i = 3; (i > 0) && (*prefix); i--) *p++ = *prefix++;
1034 sprintf( buf, "%04x.tmp", num );
1035 MultiByteToWideChar(CP_ACP, 0, buf, -1, p, 20);
1037 /* Now try to create it */
1039 if (!unique)
1043 HANDLE handle = CreateFileW( buffer, GENERIC_WRITE, 0, NULL,
1044 CREATE_NEW, FILE_ATTRIBUTE_NORMAL, 0 );
1045 if (handle != INVALID_HANDLE_VALUE)
1046 { /* We created it */
1047 TRACE("created %s\n", debugstr_w(buffer) );
1048 CloseHandle( handle );
1049 break;
1051 if (GetLastError() != ERROR_FILE_EXISTS &&
1052 GetLastError() != ERROR_SHARING_VIOLATION)
1053 break; /* No need to go on */
1054 num++;
1055 sprintf( buf, "%04x.tmp", num );
1056 MultiByteToWideChar(CP_ACP, 0, buf, -1, p, 20);
1057 } while (num != (unique & 0xffff));
1060 /* Get the full path name */
1062 if (DOSFS_GetFullName( buffer, FALSE, &full_name ))
1064 char *slash;
1065 /* Check if we have write access in the directory */
1066 if ((slash = strrchr( full_name.long_name, '/' ))) *slash = '\0';
1067 if (access( full_name.long_name, W_OK ) == -1)
1068 WARN("returns %s, which doesn't seem to be writeable.\n",
1069 debugstr_w(buffer) );
1071 TRACE("returning %s\n", debugstr_w(buffer) );
1072 return unique ? unique : num;
1076 /***********************************************************************
1077 * GetTempFileNameA (KERNEL32.@)
1079 UINT WINAPI GetTempFileNameA( LPCSTR path, LPCSTR prefix, UINT unique,
1080 LPSTR buffer)
1082 UNICODE_STRING pathW, prefixW;
1083 WCHAR bufferW[MAX_PATH];
1084 UINT ret;
1086 if ( !path || !prefix || !buffer )
1088 SetLastError( ERROR_INVALID_PARAMETER );
1089 return 0;
1092 RtlCreateUnicodeStringFromAsciiz(&pathW, path);
1093 RtlCreateUnicodeStringFromAsciiz(&prefixW, prefix);
1095 ret = GetTempFileNameW(pathW.Buffer, prefixW.Buffer, unique, bufferW);
1096 if (ret)
1097 WideCharToMultiByte(CP_ACP, 0, bufferW, -1, buffer, MAX_PATH, NULL, NULL);
1099 RtlFreeUnicodeString(&pathW);
1100 RtlFreeUnicodeString(&prefixW);
1101 return ret;
1104 /***********************************************************************
1105 * GetTempFileNameW (KERNEL32.@)
1107 UINT WINAPI GetTempFileNameW( LPCWSTR path, LPCWSTR prefix, UINT unique,
1108 LPWSTR buffer )
1110 return FILE_GetTempFileName( path, prefix, unique, buffer );
1114 /***********************************************************************
1115 * FILE_DoOpenFile
1117 * Implementation of OpenFile16() and OpenFile32().
1119 static HFILE FILE_DoOpenFile( LPCSTR name, OFSTRUCT *ofs, UINT mode, BOOL win32 )
1121 HFILE hFileRet;
1122 HANDLE handle;
1123 FILETIME filetime;
1124 WORD filedatetime[2];
1125 DOS_FULL_NAME full_name;
1126 DWORD access, sharing;
1127 WCHAR *p;
1128 WCHAR buffer[MAX_PATH];
1129 LPWSTR nameW;
1131 if (!ofs) return HFILE_ERROR;
1133 TRACE("%s %s %s %s%s%s%s%s%s%s%s%s\n",name,
1134 ((mode & 0x3 )==OF_READ)?"OF_READ":
1135 ((mode & 0x3 )==OF_WRITE)?"OF_WRITE":
1136 ((mode & 0x3 )==OF_READWRITE)?"OF_READWRITE":"unknown",
1137 ((mode & 0x70 )==OF_SHARE_COMPAT)?"OF_SHARE_COMPAT":
1138 ((mode & 0x70 )==OF_SHARE_DENY_NONE)?"OF_SHARE_DENY_NONE":
1139 ((mode & 0x70 )==OF_SHARE_DENY_READ)?"OF_SHARE_DENY_READ":
1140 ((mode & 0x70 )==OF_SHARE_DENY_WRITE)?"OF_SHARE_DENY_WRITE":
1141 ((mode & 0x70 )==OF_SHARE_EXCLUSIVE)?"OF_SHARE_EXCLUSIVE":"unknown",
1142 ((mode & OF_PARSE )==OF_PARSE)?"OF_PARSE ":"",
1143 ((mode & OF_DELETE )==OF_DELETE)?"OF_DELETE ":"",
1144 ((mode & OF_VERIFY )==OF_VERIFY)?"OF_VERIFY ":"",
1145 ((mode & OF_SEARCH )==OF_SEARCH)?"OF_SEARCH ":"",
1146 ((mode & OF_CANCEL )==OF_CANCEL)?"OF_CANCEL ":"",
1147 ((mode & OF_CREATE )==OF_CREATE)?"OF_CREATE ":"",
1148 ((mode & OF_PROMPT )==OF_PROMPT)?"OF_PROMPT ":"",
1149 ((mode & OF_EXIST )==OF_EXIST)?"OF_EXIST ":"",
1150 ((mode & OF_REOPEN )==OF_REOPEN)?"OF_REOPEN ":""
1154 ofs->cBytes = sizeof(OFSTRUCT);
1155 ofs->nErrCode = 0;
1156 if (mode & OF_REOPEN) name = ofs->szPathName;
1158 if (!name) {
1159 ERR("called with `name' set to NULL ! Please debug.\n");
1160 return HFILE_ERROR;
1163 TRACE("%s %04x\n", name, mode );
1165 /* the watcom 10.6 IDE relies on a valid path returned in ofs->szPathName
1166 Are there any cases where getting the path here is wrong?
1167 Uwe Bonnes 1997 Apr 2 */
1168 if (!GetFullPathNameA( name, sizeof(ofs->szPathName),
1169 ofs->szPathName, NULL )) goto error;
1170 FILE_ConvertOFMode( mode, &access, &sharing );
1172 /* OF_PARSE simply fills the structure */
1174 if (mode & OF_PARSE)
1176 ofs->fFixedDisk = (GetDriveType16( ofs->szPathName[0]-'A' )
1177 != DRIVE_REMOVABLE);
1178 TRACE("(%s): OF_PARSE, res = '%s'\n",
1179 name, ofs->szPathName );
1180 return 0;
1183 /* OF_CREATE is completely different from all other options, so
1184 handle it first */
1186 if (mode & OF_CREATE)
1188 if ((handle = CreateFileA( name, GENERIC_READ | GENERIC_WRITE,
1189 sharing, NULL, CREATE_ALWAYS,
1190 FILE_ATTRIBUTE_NORMAL, 0 ))== INVALID_HANDLE_VALUE)
1191 goto error;
1192 goto success;
1195 MultiByteToWideChar(CP_ACP, 0, name, -1, buffer, MAX_PATH);
1196 nameW = buffer;
1198 /* If OF_SEARCH is set, ignore the given path */
1200 if ((mode & OF_SEARCH) && !(mode & OF_REOPEN))
1202 /* First try the file name as is */
1203 if (DOSFS_GetFullName( nameW, TRUE, &full_name )) goto found;
1204 /* Now remove the path */
1205 if (nameW[0] && (nameW[1] == ':')) nameW += 2;
1206 if ((p = strrchrW( nameW, '\\' ))) nameW = p + 1;
1207 if ((p = strrchrW( nameW, '/' ))) nameW = p + 1;
1208 if (!nameW[0]) goto not_found;
1211 /* Now look for the file */
1213 if (!DIR_SearchPath( NULL, nameW, NULL, &full_name, win32 )) goto not_found;
1215 found:
1216 TRACE("found %s = %s\n",
1217 full_name.long_name, debugstr_w(full_name.short_name) );
1218 WideCharToMultiByte(CP_ACP, 0, full_name.short_name, -1,
1219 ofs->szPathName, sizeof(ofs->szPathName), NULL, NULL);
1221 if (mode & OF_SHARE_EXCLUSIVE)
1222 /* Some InstallShield version uses OF_SHARE_EXCLUSIVE
1223 on the file <tempdir>/_ins0432._mp to determine how
1224 far installation has proceeded.
1225 _ins0432._mp is an executable and while running the
1226 application expects the open with OF_SHARE_ to fail*/
1227 /* Probable FIXME:
1228 As our loader closes the files after loading the executable,
1229 we can't find the running executable with FILE_InUse.
1230 The loader should keep the file open, as Windows does that, too.
1233 char *last = strrchr(full_name.long_name,'/');
1234 if (!last)
1235 last = full_name.long_name - 1;
1236 if (GetModuleHandle16(last+1))
1238 TRACE("Denying shared open for %s\n",full_name.long_name);
1239 return HFILE_ERROR;
1243 if (mode & OF_DELETE)
1245 if (unlink( full_name.long_name ) == -1) goto not_found;
1246 TRACE("(%s): OF_DELETE return = OK\n", name);
1247 return 1;
1250 handle = FILE_CreateFile( full_name.long_name, access, sharing,
1251 NULL, OPEN_EXISTING, 0, 0,
1252 DRIVE_GetFlags(full_name.drive) & DRIVE_FAIL_READ_ONLY,
1253 GetDriveTypeW( full_name.short_name ) );
1254 if (!handle) goto not_found;
1256 GetFileTime( handle, NULL, NULL, &filetime );
1257 FileTimeToDosDateTime( &filetime, &filedatetime[0], &filedatetime[1] );
1258 if ((mode & OF_VERIFY) && (mode & OF_REOPEN))
1260 if (ofs->Reserved1 != filedatetime[0] || ofs->Reserved2 != filedatetime[1] )
1262 CloseHandle( handle );
1263 WARN("(%s): OF_VERIFY failed\n", name );
1264 /* FIXME: what error here? */
1265 SetLastError( ERROR_FILE_NOT_FOUND );
1266 goto error;
1269 ofs->Reserved1 = filedatetime[0];
1270 ofs->Reserved2 = filedatetime[1];
1272 success: /* We get here if the open was successful */
1273 TRACE("(%s): OK, return = %p\n", name, handle );
1274 if (win32)
1276 hFileRet = (HFILE)handle;
1277 if (mode & OF_EXIST) /* Return the handle, but close it first */
1278 CloseHandle( handle );
1280 else
1282 hFileRet = Win32HandleToDosFileHandle( handle );
1283 if (hFileRet == HFILE_ERROR16) goto error;
1284 if (mode & OF_EXIST) /* Return the handle, but close it first */
1285 _lclose16( hFileRet );
1287 return hFileRet;
1289 not_found: /* We get here if the file does not exist */
1290 WARN("'%s' not found or sharing violation\n", name );
1291 SetLastError( ERROR_FILE_NOT_FOUND );
1292 /* fall through */
1294 error: /* We get here if there was an error opening the file */
1295 ofs->nErrCode = GetLastError();
1296 WARN("(%s): return = HFILE_ERROR error= %d\n",
1297 name,ofs->nErrCode );
1298 return HFILE_ERROR;
1302 /***********************************************************************
1303 * OpenFile (KERNEL.74)
1304 * OpenFileEx (KERNEL.360)
1306 HFILE16 WINAPI OpenFile16( LPCSTR name, OFSTRUCT *ofs, UINT16 mode )
1308 return FILE_DoOpenFile( name, ofs, mode, FALSE );
1312 /***********************************************************************
1313 * OpenFile (KERNEL32.@)
1315 HFILE WINAPI OpenFile( LPCSTR name, OFSTRUCT *ofs, UINT mode )
1317 return FILE_DoOpenFile( name, ofs, mode, TRUE );
1321 /***********************************************************************
1322 * FILE_InitProcessDosHandles
1324 * Allocates the default DOS handles for a process. Called either by
1325 * Win32HandleToDosFileHandle below or by the DOSVM stuff.
1327 static void FILE_InitProcessDosHandles( void )
1329 HANDLE cp = GetCurrentProcess();
1330 DuplicateHandle(cp, GetStdHandle(STD_INPUT_HANDLE), cp, &dos_handles[0],
1331 0, TRUE, DUPLICATE_SAME_ACCESS);
1332 DuplicateHandle(cp, GetStdHandle(STD_OUTPUT_HANDLE), cp, &dos_handles[1],
1333 0, TRUE, DUPLICATE_SAME_ACCESS);
1334 DuplicateHandle(cp, GetStdHandle(STD_ERROR_HANDLE), cp, &dos_handles[2],
1335 0, TRUE, DUPLICATE_SAME_ACCESS);
1336 DuplicateHandle(cp, GetStdHandle(STD_ERROR_HANDLE), cp, &dos_handles[3],
1337 0, TRUE, DUPLICATE_SAME_ACCESS);
1338 DuplicateHandle(cp, GetStdHandle(STD_ERROR_HANDLE), cp, &dos_handles[4],
1339 0, TRUE, DUPLICATE_SAME_ACCESS);
1342 /***********************************************************************
1343 * Win32HandleToDosFileHandle (KERNEL32.21)
1345 * Allocate a DOS handle for a Win32 handle. The Win32 handle is no
1346 * longer valid after this function (even on failure).
1348 * Note: this is not exactly right, since on Win95 the Win32 handles
1349 * are on top of DOS handles and we do it the other way
1350 * around. Should be good enough though.
1352 HFILE WINAPI Win32HandleToDosFileHandle( HANDLE handle )
1354 int i;
1356 if (!handle || (handle == INVALID_HANDLE_VALUE))
1357 return HFILE_ERROR;
1359 for (i = 5; i < DOS_TABLE_SIZE; i++)
1360 if (!dos_handles[i])
1362 dos_handles[i] = handle;
1363 TRACE("Got %d for h32 %p\n", i, handle );
1364 return (HFILE)i;
1366 CloseHandle( handle );
1367 SetLastError( ERROR_TOO_MANY_OPEN_FILES );
1368 return HFILE_ERROR;
1372 /***********************************************************************
1373 * DosFileHandleToWin32Handle (KERNEL32.20)
1375 * Return the Win32 handle for a DOS handle.
1377 * Note: this is not exactly right, since on Win95 the Win32 handles
1378 * are on top of DOS handles and we do it the other way
1379 * around. Should be good enough though.
1381 HANDLE WINAPI DosFileHandleToWin32Handle( HFILE handle )
1383 HFILE16 hfile = (HFILE16)handle;
1384 if (hfile < 5 && !dos_handles[hfile]) FILE_InitProcessDosHandles();
1385 if ((hfile >= DOS_TABLE_SIZE) || !dos_handles[hfile])
1387 SetLastError( ERROR_INVALID_HANDLE );
1388 return INVALID_HANDLE_VALUE;
1390 return dos_handles[hfile];
1394 /***********************************************************************
1395 * DisposeLZ32Handle (KERNEL32.22)
1397 * Note: this is not entirely correct, we should only close the
1398 * 32-bit handle and not the 16-bit one, but we cannot do
1399 * this because of the way our DOS handles are implemented.
1400 * It shouldn't break anything though.
1402 void WINAPI DisposeLZ32Handle( HANDLE handle )
1404 int i;
1406 if (!handle || (handle == INVALID_HANDLE_VALUE)) return;
1408 for (i = 5; i < DOS_TABLE_SIZE; i++)
1409 if (dos_handles[i] == handle)
1411 dos_handles[i] = 0;
1412 CloseHandle( handle );
1413 break;
1418 /***********************************************************************
1419 * FILE_Dup2
1421 * dup2() function for DOS handles.
1423 HFILE16 FILE_Dup2( HFILE16 hFile1, HFILE16 hFile2 )
1425 HANDLE new_handle;
1427 if (hFile1 < 5 && !dos_handles[hFile1]) FILE_InitProcessDosHandles();
1429 if ((hFile1 >= DOS_TABLE_SIZE) || (hFile2 >= DOS_TABLE_SIZE) || !dos_handles[hFile1])
1431 SetLastError( ERROR_INVALID_HANDLE );
1432 return HFILE_ERROR16;
1434 if (!DuplicateHandle( GetCurrentProcess(), dos_handles[hFile1],
1435 GetCurrentProcess(), &new_handle,
1436 0, FALSE, DUPLICATE_SAME_ACCESS ))
1437 return HFILE_ERROR16;
1438 if (dos_handles[hFile2]) CloseHandle( dos_handles[hFile2] );
1439 dos_handles[hFile2] = new_handle;
1440 return hFile2;
1444 /***********************************************************************
1445 * _lclose (KERNEL.81)
1447 HFILE16 WINAPI _lclose16( HFILE16 hFile )
1449 if ((hFile >= DOS_TABLE_SIZE) || !dos_handles[hFile])
1451 SetLastError( ERROR_INVALID_HANDLE );
1452 return HFILE_ERROR16;
1454 TRACE("%d (handle32=%p)\n", hFile, dos_handles[hFile] );
1455 CloseHandle( dos_handles[hFile] );
1456 dos_handles[hFile] = 0;
1457 return 0;
1461 /******************************************************************
1462 * FILE_ReadWriteApc (internal)
1466 static void WINAPI FILE_ReadWriteApc(void* apc_user, PIO_STATUS_BLOCK io_status, ULONG len)
1468 LPOVERLAPPED_COMPLETION_ROUTINE cr = (LPOVERLAPPED_COMPLETION_ROUTINE)apc_user;
1470 cr(RtlNtStatusToDosError(io_status->u.Status), len, (LPOVERLAPPED)io_status);
1473 /***********************************************************************
1474 * ReadFileEx (KERNEL32.@)
1476 BOOL WINAPI ReadFileEx(HANDLE hFile, LPVOID buffer, DWORD bytesToRead,
1477 LPOVERLAPPED overlapped,
1478 LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine)
1480 LARGE_INTEGER offset;
1481 NTSTATUS status;
1482 PIO_STATUS_BLOCK io_status;
1484 if (!overlapped)
1486 SetLastError(ERROR_INVALID_PARAMETER);
1487 return FALSE;
1490 offset.s.LowPart = overlapped->Offset;
1491 offset.s.HighPart = overlapped->OffsetHigh;
1492 io_status = (PIO_STATUS_BLOCK)overlapped;
1493 io_status->u.Status = STATUS_PENDING;
1495 status = NtReadFile(hFile, NULL, FILE_ReadWriteApc, lpCompletionRoutine,
1496 io_status, buffer, bytesToRead, &offset, NULL);
1498 if (status)
1500 SetLastError( RtlNtStatusToDosError(status) );
1501 return FALSE;
1503 return TRUE;
1506 /***********************************************************************
1507 * ReadFile (KERNEL32.@)
1509 BOOL WINAPI ReadFile( HANDLE hFile, LPVOID buffer, DWORD bytesToRead,
1510 LPDWORD bytesRead, LPOVERLAPPED overlapped )
1512 LARGE_INTEGER offset;
1513 PLARGE_INTEGER poffset = NULL;
1514 IO_STATUS_BLOCK iosb;
1515 PIO_STATUS_BLOCK io_status = &iosb;
1516 HANDLE hEvent = 0;
1517 NTSTATUS status;
1519 TRACE("%p %p %ld %p %p\n", hFile, buffer, bytesToRead,
1520 bytesRead, overlapped );
1522 if (bytesRead) *bytesRead = 0; /* Do this before anything else */
1523 if (!bytesToRead) return TRUE;
1525 if (IsBadReadPtr(buffer, bytesToRead))
1527 SetLastError(ERROR_WRITE_FAULT); /* FIXME */
1528 return FALSE;
1530 if (is_console_handle(hFile))
1531 return FILE_ReadConsole(hFile, buffer, bytesToRead, bytesRead, NULL);
1533 if (overlapped != NULL)
1535 offset.s.LowPart = overlapped->Offset;
1536 offset.s.HighPart = overlapped->OffsetHigh;
1537 poffset = &offset;
1538 hEvent = overlapped->hEvent;
1539 io_status = (PIO_STATUS_BLOCK)overlapped;
1541 io_status->u.Status = STATUS_PENDING;
1542 io_status->Information = 0;
1544 status = NtReadFile(hFile, hEvent, NULL, NULL, io_status, buffer, bytesToRead, poffset, NULL);
1546 if (status != STATUS_PENDING && bytesRead)
1547 *bytesRead = io_status->Information;
1549 if (status && status != STATUS_END_OF_FILE)
1551 SetLastError( RtlNtStatusToDosError(status) );
1552 return FALSE;
1554 return TRUE;
1558 /***********************************************************************
1559 * WriteFileEx (KERNEL32.@)
1561 BOOL WINAPI WriteFileEx(HANDLE hFile, LPCVOID buffer, DWORD bytesToWrite,
1562 LPOVERLAPPED overlapped,
1563 LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine)
1565 LARGE_INTEGER offset;
1566 NTSTATUS status;
1567 PIO_STATUS_BLOCK io_status;
1569 TRACE("%p %p %ld %p %p\n",
1570 hFile, buffer, bytesToWrite, overlapped, lpCompletionRoutine);
1572 if (overlapped == NULL)
1574 SetLastError(ERROR_INVALID_PARAMETER);
1575 return FALSE;
1577 offset.s.LowPart = overlapped->Offset;
1578 offset.s.HighPart = overlapped->OffsetHigh;
1580 io_status = (PIO_STATUS_BLOCK)overlapped;
1581 io_status->u.Status = STATUS_PENDING;
1583 status = NtWriteFile(hFile, NULL, FILE_ReadWriteApc, lpCompletionRoutine,
1584 io_status, buffer, bytesToWrite, &offset, NULL);
1586 if (status) SetLastError( RtlNtStatusToDosError(status) );
1587 return !status;
1590 /***********************************************************************
1591 * WriteFile (KERNEL32.@)
1593 BOOL WINAPI WriteFile( HANDLE hFile, LPCVOID buffer, DWORD bytesToWrite,
1594 LPDWORD bytesWritten, LPOVERLAPPED overlapped )
1596 HANDLE hEvent = NULL;
1597 LARGE_INTEGER offset;
1598 PLARGE_INTEGER poffset = NULL;
1599 NTSTATUS status;
1600 IO_STATUS_BLOCK iosb;
1601 PIO_STATUS_BLOCK piosb = &iosb;
1603 TRACE("%p %p %ld %p %p\n",
1604 hFile, buffer, bytesToWrite, bytesWritten, overlapped );
1606 if (is_console_handle(hFile))
1607 return FILE_WriteConsole(hFile, buffer, bytesToWrite, bytesWritten, NULL);
1609 if (IsBadReadPtr(buffer, bytesToWrite))
1611 SetLastError(ERROR_READ_FAULT); /* FIXME */
1612 return FALSE;
1615 if (overlapped)
1617 offset.s.LowPart = overlapped->Offset;
1618 offset.s.HighPart = overlapped->OffsetHigh;
1619 poffset = &offset;
1620 hEvent = overlapped->hEvent;
1621 piosb = (PIO_STATUS_BLOCK)overlapped;
1623 piosb->u.Status = STATUS_PENDING;
1624 piosb->Information = 0;
1626 status = NtWriteFile(hFile, hEvent, NULL, NULL, piosb,
1627 buffer, bytesToWrite, poffset, NULL);
1628 if (status)
1630 SetLastError( RtlNtStatusToDosError(status) );
1631 return FALSE;
1633 if (bytesWritten) *bytesWritten = piosb->Information;
1635 return TRUE;
1639 /***********************************************************************
1640 * SetFilePointer (KERNEL32.@)
1642 DWORD WINAPI SetFilePointer( HANDLE hFile, LONG distance, LONG *highword,
1643 DWORD method )
1645 DWORD ret = INVALID_SET_FILE_POINTER;
1647 TRACE("handle %p offset %ld high %ld origin %ld\n",
1648 hFile, distance, highword?*highword:0, method );
1650 SERVER_START_REQ( set_file_pointer )
1652 req->handle = hFile;
1653 req->low = distance;
1654 req->high = highword ? *highword : (distance >= 0) ? 0 : -1;
1655 /* FIXME: assumes 1:1 mapping between Windows and Unix seek constants */
1656 req->whence = method;
1657 SetLastError( 0 );
1658 if (!wine_server_call_err( req ))
1660 ret = reply->new_low;
1661 if (highword) *highword = reply->new_high;
1664 SERVER_END_REQ;
1665 return ret;
1669 /*************************************************************************
1670 * SetHandleCount (KERNEL32.@)
1672 UINT WINAPI SetHandleCount( UINT count )
1674 return min( 256, count );
1678 /**************************************************************************
1679 * SetEndOfFile (KERNEL32.@)
1681 BOOL WINAPI SetEndOfFile( HANDLE hFile )
1683 BOOL ret;
1684 SERVER_START_REQ( truncate_file )
1686 req->handle = hFile;
1687 ret = !wine_server_call_err( req );
1689 SERVER_END_REQ;
1690 return ret;
1694 /***********************************************************************
1695 * DeleteFileW (KERNEL32.@)
1697 BOOL WINAPI DeleteFileW( LPCWSTR path )
1699 DOS_FULL_NAME full_name;
1700 HANDLE hFile;
1702 TRACE("%s\n", debugstr_w(path) );
1703 if (!path || !*path)
1705 SetLastError(ERROR_PATH_NOT_FOUND);
1706 return FALSE;
1708 if (DOSFS_GetDevice( path ))
1710 WARN("cannot remove DOS device %s!\n", debugstr_w(path));
1711 SetLastError( ERROR_FILE_NOT_FOUND );
1712 return FALSE;
1715 if (!DOSFS_GetFullName( path, TRUE, &full_name )) return FALSE;
1717 /* check if we are allowed to delete the source */
1718 hFile = FILE_CreateFile( full_name.long_name, GENERIC_READ|GENERIC_WRITE, 0,
1719 NULL, OPEN_EXISTING, 0, 0, TRUE,
1720 GetDriveTypeW( full_name.short_name ) );
1721 if (!hFile) return FALSE;
1723 if (unlink( full_name.long_name ) == -1)
1725 FILE_SetDosError();
1726 CloseHandle(hFile);
1727 return FALSE;
1729 CloseHandle(hFile);
1730 return TRUE;
1734 /***********************************************************************
1735 * DeleteFileA (KERNEL32.@)
1737 BOOL WINAPI DeleteFileA( LPCSTR path )
1739 UNICODE_STRING pathW;
1740 BOOL ret = FALSE;
1742 if (!path)
1744 SetLastError(ERROR_INVALID_PARAMETER);
1745 return FALSE;
1748 if (RtlCreateUnicodeStringFromAsciiz(&pathW, path))
1750 ret = DeleteFileW(pathW.Buffer);
1751 RtlFreeUnicodeString(&pathW);
1753 else
1754 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1755 return ret;
1759 /***********************************************************************
1760 * GetFileType (KERNEL32.@)
1762 DWORD WINAPI GetFileType( HANDLE hFile )
1764 DWORD ret = FILE_TYPE_UNKNOWN;
1766 if (is_console_handle( hFile ))
1767 return FILE_TYPE_CHAR;
1769 SERVER_START_REQ( get_file_info )
1771 req->handle = hFile;
1772 if (!wine_server_call_err( req )) ret = reply->type;
1774 SERVER_END_REQ;
1775 return ret;
1779 /* check if a file name is for an executable file (.exe or .com) */
1780 inline static BOOL is_executable( const char *name )
1782 int len = strlen(name);
1784 if (len < 4) return FALSE;
1785 return (!strcasecmp( name + len - 4, ".exe" ) ||
1786 !strcasecmp( name + len - 4, ".com" ));
1790 /***********************************************************************
1791 * FILE_AddBootRenameEntry
1793 * Adds an entry to the registry that is loaded when windows boots and
1794 * checks if there are some files to be removed or renamed/moved.
1795 * <fn1> has to be valid and <fn2> may be NULL. If both pointers are
1796 * non-NULL then the file is moved, otherwise it is deleted. The
1797 * entry of the registrykey is always appended with two zero
1798 * terminated strings. If <fn2> is NULL then the second entry is
1799 * simply a single 0-byte. Otherwise the second filename goes
1800 * there. The entries are prepended with \??\ before the path and the
1801 * second filename gets also a '!' as the first character if
1802 * MOVEFILE_REPLACE_EXISTING is set. After the final string another
1803 * 0-byte follows to indicate the end of the strings.
1804 * i.e.:
1805 * \??\D:\test\file1[0]
1806 * !\??\D:\test\file1_renamed[0]
1807 * \??\D:\Test|delete[0]
1808 * [0] <- file is to be deleted, second string empty
1809 * \??\D:\test\file2[0]
1810 * !\??\D:\test\file2_renamed[0]
1811 * [0] <- indicates end of strings
1813 * or:
1814 * \??\D:\test\file1[0]
1815 * !\??\D:\test\file1_renamed[0]
1816 * \??\D:\Test|delete[0]
1817 * [0] <- file is to be deleted, second string empty
1818 * [0] <- indicates end of strings
1821 static BOOL FILE_AddBootRenameEntry( LPCWSTR fn1, LPCWSTR fn2, DWORD flags )
1823 static const WCHAR PreString[] = {'\\','?','?','\\',0};
1824 static const WCHAR ValueName[] = {'P','e','n','d','i','n','g',
1825 'F','i','l','e','R','e','n','a','m','e',
1826 'O','p','e','r','a','t','i','o','n','s',0};
1827 static const WCHAR SessionW[] = {'M','a','c','h','i','n','e','\\',
1828 'S','y','s','t','e','m','\\',
1829 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
1830 'C','o','n','t','r','o','l','\\',
1831 'S','e','s','s','i','o','n',' ','M','a','n','a','g','e','r',0};
1832 static const int info_size = FIELD_OFFSET( KEY_VALUE_PARTIAL_INFORMATION, Data );
1834 OBJECT_ATTRIBUTES attr;
1835 UNICODE_STRING nameW;
1836 KEY_VALUE_PARTIAL_INFORMATION *info;
1837 BOOL rc = FALSE;
1838 HKEY Reboot = 0;
1839 DWORD len0, len1, len2;
1840 DWORD DataSize = 0;
1841 BYTE *Buffer = NULL;
1842 WCHAR *p;
1844 attr.Length = sizeof(attr);
1845 attr.RootDirectory = 0;
1846 attr.ObjectName = &nameW;
1847 attr.Attributes = 0;
1848 attr.SecurityDescriptor = NULL;
1849 attr.SecurityQualityOfService = NULL;
1850 RtlInitUnicodeString( &nameW, SessionW );
1852 if (NtCreateKey( &Reboot, KEY_ALL_ACCESS, &attr, 0, NULL, 0, NULL ) != STATUS_SUCCESS)
1854 WARN("Error creating key for reboot managment [%s]\n",
1855 "SYSTEM\\CurrentControlSet\\Control\\Session Manager");
1856 return FALSE;
1859 len0 = strlenW(PreString);
1860 len1 = strlenW(fn1) + len0 + 1;
1861 if (fn2)
1863 len2 = strlenW(fn2) + len0 + 1;
1864 if (flags & MOVEFILE_REPLACE_EXISTING) len2++; /* Plus 1 because of the leading '!' */
1866 else len2 = 1; /* minimum is the 0 characters for the empty second string */
1868 /* convert characters to bytes */
1869 len0 *= sizeof(WCHAR);
1870 len1 *= sizeof(WCHAR);
1871 len2 *= sizeof(WCHAR);
1873 RtlInitUnicodeString( &nameW, ValueName );
1875 /* First we check if the key exists and if so how many bytes it already contains. */
1876 if (NtQueryValueKey( Reboot, &nameW, KeyValuePartialInformation,
1877 NULL, 0, &DataSize ) == STATUS_BUFFER_OVERFLOW)
1879 if (!(Buffer = HeapAlloc( GetProcessHeap(), 0, DataSize + len1 + len2 + sizeof(WCHAR) )))
1880 goto Quit;
1881 if (NtQueryValueKey( Reboot, &nameW, KeyValuePartialInformation,
1882 Buffer, DataSize, &DataSize )) goto Quit;
1883 info = (KEY_VALUE_PARTIAL_INFORMATION *)Buffer;
1884 if (info->Type != REG_MULTI_SZ) goto Quit;
1885 if (DataSize > sizeof(info)) DataSize -= sizeof(WCHAR); /* remove terminating null (will be added back later) */
1887 else
1889 DataSize = info_size;
1890 if (!(Buffer = HeapAlloc( GetProcessHeap(), 0, DataSize + len1 + len2 + sizeof(WCHAR) )))
1891 goto Quit;
1894 p = (WCHAR *)(Buffer + DataSize);
1895 strcpyW( p, PreString );
1896 strcatW( p, fn1 );
1897 DataSize += len1;
1898 if (fn2)
1900 p = (WCHAR *)(Buffer + DataSize);
1901 if (flags & MOVEFILE_REPLACE_EXISTING)
1902 *p++ = '!';
1903 strcpyW( p, PreString );
1904 strcatW( p, fn2 );
1905 DataSize += len2;
1907 else
1909 p = (WCHAR *)(Buffer + DataSize);
1910 *p = 0;
1911 DataSize += sizeof(WCHAR);
1914 /* add final null */
1915 p = (WCHAR *)(Buffer + DataSize);
1916 *p = 0;
1917 DataSize += sizeof(WCHAR);
1919 rc = !NtSetValueKey(Reboot, &nameW, 0, REG_MULTI_SZ, Buffer + info_size, DataSize - info_size);
1921 Quit:
1922 if (Reboot) NtClose(Reboot);
1923 if (Buffer) HeapFree( GetProcessHeap(), 0, Buffer );
1924 return(rc);
1928 /**************************************************************************
1929 * MoveFileExW (KERNEL32.@)
1931 BOOL WINAPI MoveFileExW( LPCWSTR fn1, LPCWSTR fn2, DWORD flag )
1933 DOS_FULL_NAME full_name1, full_name2;
1934 HANDLE hFile;
1935 DWORD attr = INVALID_FILE_ATTRIBUTES;
1937 TRACE("(%s,%s,%04lx)\n", debugstr_w(fn1), debugstr_w(fn2), flag);
1939 /* FIXME: <Gerhard W. Gruber>sparhawk@gmx.at
1940 In case of W9x and lesser this function should return 120 (ERROR_CALL_NOT_IMPLEMENTED)
1941 to be really compatible. Most programs wont have any problems though. In case
1942 you encounter one, this is what you should return here. I don't know what's up
1943 with NT 3.5. Is this function available there or not?
1944 Does anybody really care about 3.5? :)
1947 /* Filename1 has to be always set to a valid path. Filename2 may be NULL
1948 if the source file has to be deleted.
1950 if (!fn1) {
1951 SetLastError(ERROR_INVALID_PARAMETER);
1952 return FALSE;
1955 /* This function has to be run through in order to process the name properly.
1956 If the BOOTDELAY flag is set, the file doesn't need to exist though. At least
1957 that is the behaviour on NT 4.0. The operation accepts the filenames as
1958 they are given but it can't reply with a reasonable returncode. Success
1959 means in that case success for entering the values into the registry.
1961 if(!DOSFS_GetFullName( fn1, TRUE, &full_name1 ))
1963 if(!(flag & MOVEFILE_DELAY_UNTIL_REBOOT))
1964 return FALSE;
1967 if (fn2) /* !fn2 means delete fn1 */
1969 if (DOSFS_GetFullName( fn2, TRUE, &full_name2 ))
1971 if(!(flag & MOVEFILE_DELAY_UNTIL_REBOOT))
1973 /* target exists, check if we may overwrite */
1974 if (!(flag & MOVEFILE_REPLACE_EXISTING))
1976 SetLastError( ERROR_FILE_EXISTS );
1977 return FALSE;
1981 else
1983 if (!DOSFS_GetFullName( fn2, FALSE, &full_name2 ))
1985 if(!(flag & MOVEFILE_DELAY_UNTIL_REBOOT))
1986 return FALSE;
1990 /* Source name and target path are valid */
1992 if (flag & MOVEFILE_DELAY_UNTIL_REBOOT)
1994 return FILE_AddBootRenameEntry( fn1, fn2, flag );
1997 attr = GetFileAttributesW( fn1 );
1998 if ( attr == INVALID_FILE_ATTRIBUTES ) return FALSE;
2000 /* check if we are allowed to rename the source */
2001 hFile = FILE_CreateFile( full_name1.long_name, 0, 0,
2002 NULL, OPEN_EXISTING, 0, 0, TRUE,
2003 GetDriveTypeW( full_name1.short_name ) );
2004 if (!hFile)
2006 if (GetLastError() != ERROR_ACCESS_DENIED) return FALSE;
2007 if ( !(attr & FILE_ATTRIBUTE_DIRECTORY) ) return FALSE;
2008 /* if it's a directory we can continue */
2010 else CloseHandle(hFile);
2012 /* check, if we are allowed to delete the destination,
2013 ** (but the file not being there is fine) */
2014 hFile = FILE_CreateFile( full_name2.long_name, GENERIC_READ|GENERIC_WRITE, 0,
2015 NULL, OPEN_EXISTING, 0, 0, TRUE,
2016 GetDriveTypeW( full_name2.short_name ) );
2017 if(!hFile && GetLastError() != ERROR_FILE_NOT_FOUND) return FALSE;
2018 CloseHandle(hFile);
2020 if (full_name1.drive != full_name2.drive)
2022 if (!(flag & MOVEFILE_COPY_ALLOWED))
2024 SetLastError( ERROR_NOT_SAME_DEVICE );
2025 return FALSE;
2027 else if ( attr & FILE_ATTRIBUTE_DIRECTORY )
2029 /* Strange, but that's what Windows returns */
2030 SetLastError ( ERROR_ACCESS_DENIED );
2031 return FALSE;
2034 if (rename( full_name1.long_name, full_name2.long_name ) == -1)
2035 /* Try copy/delete unless it's a directory. */
2036 /* FIXME: This does not handle the (unlikely) case that the two locations
2037 are on the same Wine drive, but on different Unix file systems. */
2039 if ( attr & FILE_ATTRIBUTE_DIRECTORY )
2041 FILE_SetDosError();
2042 return FALSE;
2044 else
2046 if ( ! CopyFileW( fn1, fn2, !(flag & MOVEFILE_REPLACE_EXISTING) ))
2047 return FALSE;
2048 if ( ! DeleteFileW ( fn1 ) )
2049 return FALSE;
2052 if (is_executable( full_name1.long_name ) != is_executable( full_name2.long_name ))
2054 struct stat fstat;
2055 if (stat( full_name2.long_name, &fstat ) != -1)
2057 if (is_executable( full_name2.long_name ))
2058 /* set executable bit where read bit is set */
2059 fstat.st_mode |= (fstat.st_mode & 0444) >> 2;
2060 else
2061 fstat.st_mode &= ~0111;
2062 chmod( full_name2.long_name, fstat.st_mode );
2065 return TRUE;
2067 else /* fn2 == NULL means delete source */
2069 if (flag & MOVEFILE_DELAY_UNTIL_REBOOT)
2071 if (flag & MOVEFILE_COPY_ALLOWED) {
2072 WARN("Illegal flag\n");
2073 SetLastError( ERROR_GEN_FAILURE );
2074 return FALSE;
2077 return FILE_AddBootRenameEntry( fn1, NULL, flag );
2080 if (unlink( full_name1.long_name ) == -1)
2082 FILE_SetDosError();
2083 return FALSE;
2085 return TRUE; /* successfully deleted */
2089 /**************************************************************************
2090 * MoveFileExA (KERNEL32.@)
2092 BOOL WINAPI MoveFileExA( LPCSTR fn1, LPCSTR fn2, DWORD flag )
2094 UNICODE_STRING fn1W, fn2W;
2095 BOOL ret;
2097 if (!fn1)
2099 SetLastError(ERROR_INVALID_PARAMETER);
2100 return FALSE;
2103 RtlCreateUnicodeStringFromAsciiz(&fn1W, fn1);
2104 if (fn2) RtlCreateUnicodeStringFromAsciiz(&fn2W, fn2);
2105 else fn2W.Buffer = NULL;
2107 ret = MoveFileExW( fn1W.Buffer, fn2W.Buffer, flag );
2109 RtlFreeUnicodeString(&fn1W);
2110 RtlFreeUnicodeString(&fn2W);
2111 return ret;
2115 /**************************************************************************
2116 * MoveFileW (KERNEL32.@)
2118 * Move file or directory
2120 BOOL WINAPI MoveFileW( LPCWSTR fn1, LPCWSTR fn2 )
2122 return MoveFileExW( fn1, fn2, MOVEFILE_COPY_ALLOWED );
2126 /**************************************************************************
2127 * MoveFileA (KERNEL32.@)
2129 BOOL WINAPI MoveFileA( LPCSTR fn1, LPCSTR fn2 )
2131 return MoveFileExA( fn1, fn2, MOVEFILE_COPY_ALLOWED );
2135 /**************************************************************************
2136 * CopyFileW (KERNEL32.@)
2138 BOOL WINAPI CopyFileW( LPCWSTR source, LPCWSTR dest, BOOL fail_if_exists )
2140 HANDLE h1, h2;
2141 BY_HANDLE_FILE_INFORMATION info;
2142 DWORD count;
2143 BOOL ret = FALSE;
2144 char buffer[2048];
2146 if (!source || !dest)
2148 SetLastError(ERROR_INVALID_PARAMETER);
2149 return FALSE;
2152 TRACE("%s -> %s\n", debugstr_w(source), debugstr_w(dest));
2154 if ((h1 = CreateFileW(source, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE,
2155 NULL, OPEN_EXISTING, 0, 0)) == INVALID_HANDLE_VALUE)
2157 WARN("Unable to open source %s\n", debugstr_w(source));
2158 return FALSE;
2161 if (!GetFileInformationByHandle( h1, &info ))
2163 WARN("GetFileInformationByHandle returned error for %s\n", debugstr_w(source));
2164 CloseHandle( h1 );
2165 return FALSE;
2168 if ((h2 = CreateFileW( dest, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
2169 fail_if_exists ? CREATE_NEW : CREATE_ALWAYS,
2170 info.dwFileAttributes, h1 )) == INVALID_HANDLE_VALUE)
2172 WARN("Unable to open dest %s\n", debugstr_w(dest));
2173 CloseHandle( h1 );
2174 return FALSE;
2177 while (ReadFile( h1, buffer, sizeof(buffer), &count, NULL ) && count)
2179 char *p = buffer;
2180 while (count != 0)
2182 DWORD res;
2183 if (!WriteFile( h2, p, count, &res, NULL ) || !res) goto done;
2184 p += res;
2185 count -= res;
2188 ret = TRUE;
2189 done:
2190 CloseHandle( h1 );
2191 CloseHandle( h2 );
2192 return ret;
2196 /**************************************************************************
2197 * CopyFileA (KERNEL32.@)
2199 BOOL WINAPI CopyFileA( LPCSTR source, LPCSTR dest, BOOL fail_if_exists)
2201 UNICODE_STRING sourceW, destW;
2202 BOOL ret;
2204 if (!source || !dest)
2206 SetLastError(ERROR_INVALID_PARAMETER);
2207 return FALSE;
2210 RtlCreateUnicodeStringFromAsciiz(&sourceW, source);
2211 RtlCreateUnicodeStringFromAsciiz(&destW, dest);
2213 ret = CopyFileW(sourceW.Buffer, destW.Buffer, fail_if_exists);
2215 RtlFreeUnicodeString(&sourceW);
2216 RtlFreeUnicodeString(&destW);
2217 return ret;
2221 /**************************************************************************
2222 * CopyFileExW (KERNEL32.@)
2224 * This implementation ignores most of the extra parameters passed-in into
2225 * the "ex" version of the method and calls the CopyFile method.
2226 * It will have to be fixed eventually.
2228 BOOL WINAPI CopyFileExW(LPCWSTR sourceFilename, LPCWSTR destFilename,
2229 LPPROGRESS_ROUTINE progressRoutine, LPVOID appData,
2230 LPBOOL cancelFlagPointer, DWORD copyFlags)
2233 * Interpret the only flag that CopyFile can interpret.
2235 return CopyFileW(sourceFilename, destFilename, (copyFlags & COPY_FILE_FAIL_IF_EXISTS) != 0);
2239 /**************************************************************************
2240 * CopyFileExA (KERNEL32.@)
2242 BOOL WINAPI CopyFileExA(LPCSTR sourceFilename, LPCSTR destFilename,
2243 LPPROGRESS_ROUTINE progressRoutine, LPVOID appData,
2244 LPBOOL cancelFlagPointer, DWORD copyFlags)
2246 UNICODE_STRING sourceW, destW;
2247 BOOL ret;
2249 if (!sourceFilename || !destFilename)
2251 SetLastError(ERROR_INVALID_PARAMETER);
2252 return FALSE;
2255 RtlCreateUnicodeStringFromAsciiz(&sourceW, sourceFilename);
2256 RtlCreateUnicodeStringFromAsciiz(&destW, destFilename);
2258 ret = CopyFileExW(sourceW.Buffer, destW.Buffer, progressRoutine, appData,
2259 cancelFlagPointer, copyFlags);
2261 RtlFreeUnicodeString(&sourceW);
2262 RtlFreeUnicodeString(&destW);
2263 return ret;
2267 /***********************************************************************
2268 * SetFileTime (KERNEL32.@)
2270 BOOL WINAPI SetFileTime( HANDLE hFile,
2271 const FILETIME *lpCreationTime,
2272 const FILETIME *lpLastAccessTime,
2273 const FILETIME *lpLastWriteTime )
2275 BOOL ret;
2276 SERVER_START_REQ( set_file_time )
2278 req->handle = hFile;
2279 if (lpLastAccessTime)
2280 RtlTimeToSecondsSince1970( (PLARGE_INTEGER) lpLastAccessTime, (DWORD *)&req->access_time );
2281 else
2282 req->access_time = 0; /* FIXME */
2283 if (lpLastWriteTime)
2284 RtlTimeToSecondsSince1970( (PLARGE_INTEGER) lpLastWriteTime, (DWORD *)&req->write_time );
2285 else
2286 req->write_time = 0; /* FIXME */
2287 ret = !wine_server_call_err( req );
2289 SERVER_END_REQ;
2290 return ret;
2294 /**************************************************************************
2295 * GetFileAttributesExW (KERNEL32.@)
2297 BOOL WINAPI GetFileAttributesExW(
2298 LPCWSTR lpFileName, GET_FILEEX_INFO_LEVELS fInfoLevelId,
2299 LPVOID lpFileInformation)
2301 DOS_FULL_NAME full_name;
2302 BY_HANDLE_FILE_INFORMATION info;
2304 if (!lpFileName || !lpFileInformation)
2306 SetLastError(ERROR_INVALID_PARAMETER);
2307 return FALSE;
2310 if (fInfoLevelId == GetFileExInfoStandard) {
2311 LPWIN32_FILE_ATTRIBUTE_DATA lpFad =
2312 (LPWIN32_FILE_ATTRIBUTE_DATA) lpFileInformation;
2313 if (!DOSFS_GetFullName( lpFileName, TRUE, &full_name )) return FALSE;
2314 if (!FILE_Stat( full_name.long_name, &info, NULL )) return FALSE;
2316 lpFad->dwFileAttributes = info.dwFileAttributes;
2317 lpFad->ftCreationTime = info.ftCreationTime;
2318 lpFad->ftLastAccessTime = info.ftLastAccessTime;
2319 lpFad->ftLastWriteTime = info.ftLastWriteTime;
2320 lpFad->nFileSizeHigh = info.nFileSizeHigh;
2321 lpFad->nFileSizeLow = info.nFileSizeLow;
2323 else {
2324 FIXME("invalid info level %d!\n", fInfoLevelId);
2325 return FALSE;
2328 return TRUE;
2332 /**************************************************************************
2333 * GetFileAttributesExA (KERNEL32.@)
2335 BOOL WINAPI GetFileAttributesExA(
2336 LPCSTR filename, GET_FILEEX_INFO_LEVELS fInfoLevelId,
2337 LPVOID lpFileInformation)
2339 UNICODE_STRING filenameW;
2340 BOOL ret = FALSE;
2342 if (!filename || !lpFileInformation)
2344 SetLastError(ERROR_INVALID_PARAMETER);
2345 return FALSE;
2348 if (RtlCreateUnicodeStringFromAsciiz(&filenameW, filename))
2350 ret = GetFileAttributesExW(filenameW.Buffer, fInfoLevelId, lpFileInformation);
2351 RtlFreeUnicodeString(&filenameW);
2353 else
2354 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
2355 return ret;