Fixed compile warning.
[wine/multimedia.git] / files / file.c
blob875a64de461749c4393e6a89dc873a3a7acf929b
1 /*
2 * File handling functions
4 * Copyright 1993 John Burton
5 * Copyright 1996 Alexandre Julliard
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 * TODO:
22 * Fix the CopyFileEx methods to implement the "extended" functionality.
23 * Right now, they simply call the CopyFile method.
26 #include "config.h"
27 #include "wine/port.h"
29 #include <assert.h>
30 #include <ctype.h>
31 #include <errno.h>
32 #include <fcntl.h>
33 #include <stdlib.h>
34 #include <stdarg.h>
35 #include <stdio.h>
36 #include <string.h>
37 #ifdef HAVE_SYS_ERRNO_H
38 #include <sys/errno.h>
39 #endif
40 #include <sys/types.h>
41 #include <sys/stat.h>
42 #ifdef HAVE_SYS_MMAN_H
43 #include <sys/mman.h>
44 #endif
45 #ifdef HAVE_SYS_TIME_H
46 # include <sys/time.h>
47 #endif
48 #ifdef HAVE_SYS_POLL_H
49 # include <sys/poll.h>
50 #endif
51 #include <time.h>
52 #ifdef HAVE_UNISTD_H
53 # include <unistd.h>
54 #endif
55 #ifdef HAVE_UTIME_H
56 # include <utime.h>
57 #endif
59 #define NONAMELESSUNION
60 #define NONAMELESSSTRUCT
61 #include "winerror.h"
62 #include "ntstatus.h"
63 #include "windef.h"
64 #include "winbase.h"
65 #include "winreg.h"
66 #include "winternl.h"
67 #include "wine/winbase16.h"
68 #include "wine/server.h"
70 #include "drive.h"
71 #include "file.h"
72 #include "heap.h"
73 #include "msdos.h"
74 #include "wincon.h"
75 #include "../kernel/kernel_private.h"
77 #include "smb.h"
78 #include "wine/unicode.h"
79 #include "wine/debug.h"
81 WINE_DEFAULT_DEBUG_CHANNEL(file);
83 #if defined(MAP_ANONYMOUS) && !defined(MAP_ANON)
84 #define MAP_ANON MAP_ANONYMOUS
85 #endif
87 #define IS_OPTION_TRUE(ch) ((ch) == 'y' || (ch) == 'Y' || (ch) == 't' || (ch) == 'T' || (ch) == '1')
89 HANDLE dos_handles[DOS_TABLE_SIZE];
90 mode_t FILE_umask;
92 /***********************************************************************
93 * FILE_ConvertOFMode
95 * Convert OF_* mode into flags for CreateFile.
97 void FILE_ConvertOFMode( INT mode, DWORD *access, DWORD *sharing )
99 switch(mode & 0x03)
101 case OF_READ: *access = GENERIC_READ; break;
102 case OF_WRITE: *access = GENERIC_WRITE; break;
103 case OF_READWRITE: *access = GENERIC_READ | GENERIC_WRITE; break;
104 default: *access = 0; break;
106 switch(mode & 0x70)
108 case OF_SHARE_EXCLUSIVE: *sharing = 0; break;
109 case OF_SHARE_DENY_WRITE: *sharing = FILE_SHARE_READ; break;
110 case OF_SHARE_DENY_READ: *sharing = FILE_SHARE_WRITE; break;
111 case OF_SHARE_DENY_NONE:
112 case OF_SHARE_COMPAT:
113 default: *sharing = FILE_SHARE_READ | FILE_SHARE_WRITE; break;
118 /***********************************************************************
119 * FILE_strcasecmp
121 * locale-independent case conversion for file I/O
123 int FILE_strcasecmp( const char *str1, const char *str2 )
125 int ret = 0;
126 for ( ; ; str1++, str2++)
127 if ((ret = FILE_toupper(*str1) - FILE_toupper(*str2)) || !*str1) break;
128 return ret;
132 /***********************************************************************
133 * FILE_strncasecmp
135 * locale-independent case conversion for file I/O
137 int FILE_strncasecmp( const char *str1, const char *str2, int len )
139 int ret = 0;
140 for ( ; len > 0; len--, str1++, str2++)
141 if ((ret = FILE_toupper(*str1) - FILE_toupper(*str2)) || !*str1) break;
142 return ret;
146 /***********************************************************************
147 * FILE_SetDosError
149 * Set the DOS error code from errno.
151 void FILE_SetDosError(void)
153 int save_errno = errno; /* errno gets overwritten by printf */
155 TRACE("errno = %d %s\n", errno, strerror(errno));
156 switch (save_errno)
158 case EAGAIN:
159 SetLastError( ERROR_SHARING_VIOLATION );
160 break;
161 case EBADF:
162 SetLastError( ERROR_INVALID_HANDLE );
163 break;
164 case ENOSPC:
165 SetLastError( ERROR_HANDLE_DISK_FULL );
166 break;
167 case EACCES:
168 case EPERM:
169 case EROFS:
170 SetLastError( ERROR_ACCESS_DENIED );
171 break;
172 case EBUSY:
173 SetLastError( ERROR_LOCK_VIOLATION );
174 break;
175 case ENOENT:
176 SetLastError( ERROR_FILE_NOT_FOUND );
177 break;
178 case EISDIR:
179 SetLastError( ERROR_CANNOT_MAKE );
180 break;
181 case ENFILE:
182 case EMFILE:
183 SetLastError( ERROR_NO_MORE_FILES );
184 break;
185 case EEXIST:
186 SetLastError( ERROR_FILE_EXISTS );
187 break;
188 case EINVAL:
189 case ESPIPE:
190 SetLastError( ERROR_SEEK );
191 break;
192 case ENOTEMPTY:
193 SetLastError( ERROR_DIR_NOT_EMPTY );
194 break;
195 case ENOEXEC:
196 SetLastError( ERROR_BAD_FORMAT );
197 break;
198 default:
199 WARN("unknown file error: %s\n", strerror(save_errno) );
200 SetLastError( ERROR_GEN_FAILURE );
201 break;
203 errno = save_errno;
207 /***********************************************************************
208 * FILE_GetUnixHandleType
210 * Retrieve the Unix handle corresponding to a file handle.
211 * Returns -1 on failure.
213 static int FILE_GetUnixHandleType( HANDLE handle, DWORD access, enum fd_type *type, int *flags_ptr )
215 int ret, flags, fd = -1;
217 ret = wine_server_handle_to_fd( handle, access, &fd, type, &flags );
218 if (flags_ptr) *flags_ptr = flags;
219 if (ret) SetLastError( RtlNtStatusToDosError(ret) );
220 else if (((access & GENERIC_READ) && (flags & FD_FLAG_RECV_SHUTDOWN)) ||
221 ((access & GENERIC_WRITE) && (flags & FD_FLAG_SEND_SHUTDOWN)))
223 close (fd);
224 SetLastError ( ERROR_PIPE_NOT_CONNECTED );
225 return -1;
227 return fd;
230 /***********************************************************************
231 * FILE_GetUnixHandle
233 * Retrieve the Unix handle corresponding to a file handle.
234 * Returns -1 on failure.
236 int FILE_GetUnixHandle( HANDLE handle, DWORD access )
238 return FILE_GetUnixHandleType( handle, access, NULL, NULL );
241 /******************************************************************
242 * OpenConsoleW (KERNEL32.@)
244 * Undocumented
245 * Open a handle to the current process console.
246 * Returns INVALID_HANDLE_VALUE on failure.
248 HANDLE WINAPI OpenConsoleW(LPCWSTR name, DWORD access, LPSECURITY_ATTRIBUTES sa,
249 DWORD creation)
251 static const WCHAR coninW[] = {'C','O','N','I','N','$',0};
252 static const WCHAR conoutW[] = {'C','O','N','O','U','T','$',0};
253 BOOL output;
254 HANDLE ret;
256 if (strcmpW(coninW, name) == 0)
257 output = FALSE;
258 else if (strcmpW(conoutW, name) == 0)
259 output = TRUE;
260 else
262 SetLastError(ERROR_INVALID_NAME);
263 return INVALID_HANDLE_VALUE;
265 if (creation != OPEN_EXISTING)
267 SetLastError(ERROR_INVALID_PARAMETER);
268 return INVALID_HANDLE_VALUE;
271 SERVER_START_REQ( open_console )
273 req->from = output;
274 req->access = access;
275 req->share = FILE_SHARE_READ | FILE_SHARE_WRITE;
276 req->inherit = (sa && (sa->nLength>=sizeof(*sa)) && sa->bInheritHandle);
277 SetLastError(0);
278 wine_server_call_err( req );
279 ret = reply->handle;
281 SERVER_END_REQ;
282 return ret ? console_handle_map(ret) : INVALID_HANDLE_VALUE;
285 /******************************************************************
286 * VerifyConsoleIoHandle (KERNEL32.@)
288 * Undocumented
290 BOOL WINAPI VerifyConsoleIoHandle(HANDLE handle)
292 BOOL ret;
294 if (!is_console_handle(handle)) return FALSE;
295 SERVER_START_REQ(get_console_mode)
297 req->handle = console_handle_unmap(handle);
298 ret = !wine_server_call_err( req );
300 SERVER_END_REQ;
301 return ret;
304 /******************************************************************
305 * DuplicateConsoleHandle (KERNEL32.@)
307 * Undocumented
309 HANDLE WINAPI DuplicateConsoleHandle(HANDLE handle, DWORD access, BOOL inherit,
310 DWORD options)
312 HANDLE ret;
314 if (!is_console_handle(handle) ||
315 !DuplicateHandle(GetCurrentProcess(), console_handle_unmap(handle),
316 GetCurrentProcess(), &ret, access, inherit, options))
317 return INVALID_HANDLE_VALUE;
318 return console_handle_map(ret);
321 /******************************************************************
322 * CloseConsoleHandle (KERNEL32.@)
324 * Undocumented
326 BOOL WINAPI CloseConsoleHandle(HANDLE handle)
328 if (!is_console_handle(handle))
330 SetLastError(ERROR_INVALID_PARAMETER);
331 return FALSE;
333 return CloseHandle(console_handle_unmap(handle));
336 /******************************************************************
337 * GetConsoleInputWaitHandle (KERNEL32.@)
339 * Undocumented
341 HANDLE WINAPI GetConsoleInputWaitHandle(void)
343 static HANDLE console_wait_event;
345 /* FIXME: this is not thread safe */
346 if (!console_wait_event)
348 SERVER_START_REQ(get_console_wait_event)
350 if (!wine_server_call_err( req )) console_wait_event = reply->handle;
352 SERVER_END_REQ;
354 return console_wait_event;
356 /* end of FIXME */
359 /* FIXME: those routines defined as pointers are needed, because this file is
360 * currently compiled into NTDLL whereas it belongs to kernel32.
361 * this shall go away once all the DLL separation process is done
363 typedef BOOL (WINAPI* pRW)(HANDLE, const void*, DWORD, DWORD*, void*);
365 static BOOL FILE_ReadConsole(HANDLE hCon, void* buf, DWORD nb, DWORD* nr, void* p)
367 static HANDLE hKernel /* = 0 */;
368 static pRW pReadConsole /* = 0 */;
370 if ((!hKernel && !(hKernel = LoadLibraryA("kernel32"))) ||
371 (!pReadConsole &&
372 !(pReadConsole = GetProcAddress(hKernel, "ReadConsoleA"))))
374 *nr = 0;
375 return 0;
377 return (pReadConsole)(hCon, buf, nb, nr, p);
380 static BOOL FILE_WriteConsole(HANDLE hCon, const void* buf, DWORD nb, DWORD* nr, void* p)
382 static HANDLE hKernel /* = 0 */;
383 static pRW pWriteConsole /* = 0 */;
385 if ((!hKernel && !(hKernel = LoadLibraryA("kernel32"))) ||
386 (!pWriteConsole &&
387 !(pWriteConsole = GetProcAddress(hKernel, "WriteConsoleA"))))
389 *nr = 0;
390 return 0;
392 return (pWriteConsole)(hCon, buf, nb, nr, p);
394 /* end of FIXME */
396 /***********************************************************************
397 * FILE_CreateFile
399 * Implementation of CreateFile. Takes a Unix path name.
400 * Returns 0 on failure.
402 HANDLE FILE_CreateFile( LPCSTR filename, DWORD access, DWORD sharing,
403 LPSECURITY_ATTRIBUTES sa, DWORD creation,
404 DWORD attributes, HANDLE template, BOOL fail_read_only,
405 UINT drive_type )
407 unsigned int err;
408 HANDLE ret;
410 for (;;)
412 SERVER_START_REQ( create_file )
414 req->access = access;
415 req->inherit = (sa && (sa->nLength>=sizeof(*sa)) && sa->bInheritHandle);
416 req->sharing = sharing;
417 req->create = creation;
418 req->attrs = attributes;
419 req->drive_type = drive_type;
420 wine_server_add_data( req, filename, strlen(filename) );
421 SetLastError(0);
422 err = wine_server_call( req );
423 ret = reply->handle;
425 SERVER_END_REQ;
427 /* If write access failed, retry without GENERIC_WRITE */
429 if (!ret && !fail_read_only && (access & GENERIC_WRITE))
431 if ((err == STATUS_MEDIA_WRITE_PROTECTED) || (err == STATUS_ACCESS_DENIED))
433 TRACE("Write access failed for file '%s', trying without "
434 "write access\n", filename);
435 access &= ~GENERIC_WRITE;
436 continue;
440 if (err)
442 /* In the case file creation was rejected due to CREATE_NEW flag
443 * was specified and file with that name already exists, correct
444 * last error is ERROR_FILE_EXISTS and not ERROR_ALREADY_EXISTS.
445 * Note: RtlNtStatusToDosError is not the subject to blame here.
447 if (err == STATUS_OBJECT_NAME_COLLISION)
448 SetLastError( ERROR_FILE_EXISTS );
449 else
450 SetLastError( RtlNtStatusToDosError(err) );
453 if (!ret) WARN("Unable to create file '%s' (GLE %ld)\n", filename, GetLastError());
454 return ret;
459 /***********************************************************************
460 * FILE_CreateDevice
462 * Same as FILE_CreateFile but for a device
463 * Returns 0 on failure.
465 HANDLE FILE_CreateDevice( int client_id, DWORD access, LPSECURITY_ATTRIBUTES sa )
467 HANDLE ret;
468 SERVER_START_REQ( create_device )
470 req->access = access;
471 req->inherit = (sa && (sa->nLength>=sizeof(*sa)) && sa->bInheritHandle);
472 req->id = client_id;
473 SetLastError(0);
474 wine_server_call_err( req );
475 ret = reply->handle;
477 SERVER_END_REQ;
478 return ret;
481 static HANDLE FILE_OpenPipe(LPCWSTR name, DWORD access, LPSECURITY_ATTRIBUTES sa )
483 HANDLE ret;
484 DWORD len = 0;
486 if (name && (len = strlenW(name)) > MAX_PATH)
488 SetLastError( ERROR_FILENAME_EXCED_RANGE );
489 return 0;
491 SERVER_START_REQ( open_named_pipe )
493 req->access = access;
494 req->inherit = (sa && (sa->nLength>=sizeof(*sa)) && sa->bInheritHandle);
495 SetLastError(0);
496 wine_server_add_data( req, name, len * sizeof(WCHAR) );
497 wine_server_call_err( req );
498 ret = reply->handle;
500 SERVER_END_REQ;
501 TRACE("Returned %p\n",ret);
502 return ret;
505 /*************************************************************************
506 * CreateFileW [KERNEL32.@] Creates or opens a file or other object
508 * Creates or opens an object, and returns a handle that can be used to
509 * access that object.
511 * PARAMS
513 * filename [in] pointer to filename to be accessed
514 * access [in] access mode requested
515 * sharing [in] share mode
516 * sa [in] pointer to security attributes
517 * creation [in] how to create the file
518 * attributes [in] attributes for newly created file
519 * template [in] handle to file with extended attributes to copy
521 * RETURNS
522 * Success: Open handle to specified file
523 * Failure: INVALID_HANDLE_VALUE
525 * NOTES
526 * Should call SetLastError() on failure.
528 * BUGS
530 * Doesn't support character devices, template files, or a
531 * lot of the 'attributes' flags yet.
533 HANDLE WINAPI CreateFileW( LPCWSTR filename, DWORD access, DWORD sharing,
534 LPSECURITY_ATTRIBUTES sa, DWORD creation,
535 DWORD attributes, HANDLE template )
537 DOS_FULL_NAME full_name;
538 HANDLE ret;
539 static const WCHAR bkslashes_with_question_markW[] = {'\\','\\','?','\\',0};
540 static const WCHAR bkslashes_with_dotW[] = {'\\','\\','.','\\',0};
541 static const WCHAR bkslashesW[] = {'\\','\\',0};
542 static const WCHAR coninW[] = {'C','O','N','I','N','$',0};
543 static const WCHAR conoutW[] = {'C','O','N','O','U','T','$',0};
545 if (!filename)
547 SetLastError( ERROR_INVALID_PARAMETER );
548 return INVALID_HANDLE_VALUE;
550 TRACE("%s %s%s%s%s%s%s%s attributes 0x%lx\n", debugstr_w(filename),
551 ((access & GENERIC_READ)==GENERIC_READ)?"GENERIC_READ ":"",
552 ((access & GENERIC_WRITE)==GENERIC_WRITE)?"GENERIC_WRITE ":"",
553 (!access)?"QUERY_ACCESS ":"",
554 ((sharing & FILE_SHARE_READ)==FILE_SHARE_READ)?"FILE_SHARE_READ ":"",
555 ((sharing & FILE_SHARE_WRITE)==FILE_SHARE_WRITE)?"FILE_SHARE_WRITE ":"",
556 ((sharing & FILE_SHARE_DELETE)==FILE_SHARE_DELETE)?"FILE_SHARE_DELETE ":"",
557 (creation ==CREATE_NEW)?"CREATE_NEW":
558 (creation ==CREATE_ALWAYS)?"CREATE_ALWAYS ":
559 (creation ==OPEN_EXISTING)?"OPEN_EXISTING ":
560 (creation ==OPEN_ALWAYS)?"OPEN_ALWAYS ":
561 (creation ==TRUNCATE_EXISTING)?"TRUNCATE_EXISTING ":"", attributes);
563 /* If the name starts with '\\?\', ignore the first 4 chars. */
564 if (!strncmpW(filename, bkslashes_with_question_markW, 4))
566 static const WCHAR uncW[] = {'U','N','C','\\',0};
567 filename += 4;
568 if (!strncmpiW(filename, uncW, 4))
570 FIXME("UNC name (%s) not supported.\n", debugstr_w(filename) );
571 SetLastError( ERROR_PATH_NOT_FOUND );
572 return INVALID_HANDLE_VALUE;
576 if (!strncmpW(filename, bkslashes_with_dotW, 4))
578 static const WCHAR pipeW[] = {'P','I','P','E','\\',0};
579 if(!strncmpiW(filename + 4, pipeW, 5))
581 TRACE("Opening a pipe: %s\n", debugstr_w(filename));
582 ret = FILE_OpenPipe( filename, access, sa );
583 goto done;
585 else if (isalphaW(filename[4]) && filename[5] == ':' && filename[6] == '\0')
587 ret = FILE_CreateDevice( (toupperW(filename[4]) - 'A') | 0x20000, access, sa );
588 goto done;
590 else if (!DOSFS_GetDevice( filename ))
592 ret = DEVICE_Open( filename+4, access, sa );
593 goto done;
595 else
596 filename+=4; /* fall into DOSFS_Device case below */
599 /* If the name still starts with '\\', it's a UNC name. */
600 if (!strncmpW(filename, bkslashesW, 2))
602 ret = SMB_CreateFileW(filename, access, sharing, sa, creation, attributes, template );
603 goto done;
606 /* If the name contains a DOS wild card (* or ?), do no create a file */
607 if(strchrW(filename, '*') || strchrW(filename, '?'))
609 SetLastError(ERROR_BAD_PATHNAME);
610 return INVALID_HANDLE_VALUE;
613 /* Open a console for CONIN$ or CONOUT$ */
614 if (!strcmpiW(filename, coninW) || !strcmpiW(filename, conoutW))
616 ret = OpenConsoleW(filename, access, sa, creation);
617 goto done;
620 if (DOSFS_GetDevice( filename ))
622 TRACE("opening device %s\n", debugstr_w(filename) );
624 if (!(ret = DOSFS_OpenDevice( filename, access, attributes, sa )))
626 /* Do not silence this please. It is a critical error. -MM */
627 ERR("Couldn't open device %s!\n", debugstr_w(filename));
628 SetLastError( ERROR_FILE_NOT_FOUND );
630 goto done;
633 /* check for filename, don't check for last entry if creating */
634 if (!DOSFS_GetFullName( filename,
635 (creation == OPEN_EXISTING) ||
636 (creation == TRUNCATE_EXISTING),
637 &full_name )) {
638 WARN("Unable to get full filename from %s (GLE %ld)\n",
639 debugstr_w(filename), GetLastError());
640 return INVALID_HANDLE_VALUE;
643 ret = FILE_CreateFile( full_name.long_name, access, sharing,
644 sa, creation, attributes, template,
645 DRIVE_GetFlags(full_name.drive) & DRIVE_FAIL_READ_ONLY,
646 GetDriveTypeW( full_name.short_name ) );
647 done:
648 if (!ret) ret = INVALID_HANDLE_VALUE;
649 TRACE("returning %p\n", ret);
650 return ret;
655 /*************************************************************************
656 * CreateFileA (KERNEL32.@)
658 HANDLE WINAPI CreateFileA( LPCSTR filename, DWORD access, DWORD sharing,
659 LPSECURITY_ATTRIBUTES sa, DWORD creation,
660 DWORD attributes, HANDLE template)
662 UNICODE_STRING filenameW;
663 HANDLE ret = INVALID_HANDLE_VALUE;
665 if (!filename)
667 SetLastError( ERROR_INVALID_PARAMETER );
668 return INVALID_HANDLE_VALUE;
671 if (RtlCreateUnicodeStringFromAsciiz(&filenameW, filename))
673 ret = CreateFileW(filenameW.Buffer, access, sharing, sa, creation,
674 attributes, template);
675 RtlFreeUnicodeString(&filenameW);
677 else
678 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
679 return ret;
683 /***********************************************************************
684 * FILE_FillInfo
686 * Fill a file information from a struct stat.
688 static void FILE_FillInfo( struct stat *st, BY_HANDLE_FILE_INFORMATION *info )
690 if (S_ISDIR(st->st_mode))
691 info->dwFileAttributes = FILE_ATTRIBUTE_DIRECTORY;
692 else
693 info->dwFileAttributes = FILE_ATTRIBUTE_ARCHIVE;
694 if (!(st->st_mode & S_IWUSR))
695 info->dwFileAttributes |= FILE_ATTRIBUTE_READONLY;
697 RtlSecondsSince1970ToTime( st->st_mtime, (LARGE_INTEGER *)&info->ftCreationTime );
698 RtlSecondsSince1970ToTime( st->st_mtime, (LARGE_INTEGER *)&info->ftLastWriteTime );
699 RtlSecondsSince1970ToTime( st->st_atime, (LARGE_INTEGER *)&info->ftLastAccessTime );
701 info->dwVolumeSerialNumber = 0; /* FIXME */
702 info->nFileSizeHigh = 0;
703 info->nFileSizeLow = 0;
704 if (!S_ISDIR(st->st_mode)) {
705 info->nFileSizeHigh = st->st_size >> 32;
706 info->nFileSizeLow = st->st_size & 0xffffffff;
708 info->nNumberOfLinks = st->st_nlink;
709 info->nFileIndexHigh = 0;
710 info->nFileIndexLow = st->st_ino;
714 /***********************************************************************
715 * get_show_dot_files_option
717 static BOOL get_show_dot_files_option(void)
719 static const WCHAR WineW[] = {'M','a','c','h','i','n','e','\\',
720 'S','o','f','t','w','a','r','e','\\',
721 'W','i','n','e','\\','W','i','n','e','\\',
722 'C','o','n','f','i','g','\\','W','i','n','e',0};
723 static const WCHAR ShowDotFilesW[] = {'S','h','o','w','D','o','t','F','i','l','e','s',0};
725 char tmp[80];
726 HKEY hkey;
727 DWORD dummy;
728 OBJECT_ATTRIBUTES attr;
729 UNICODE_STRING nameW;
730 BOOL ret = FALSE;
732 attr.Length = sizeof(attr);
733 attr.RootDirectory = 0;
734 attr.ObjectName = &nameW;
735 attr.Attributes = 0;
736 attr.SecurityDescriptor = NULL;
737 attr.SecurityQualityOfService = NULL;
738 RtlInitUnicodeString( &nameW, WineW );
740 if (!NtOpenKey( &hkey, KEY_ALL_ACCESS, &attr ))
742 RtlInitUnicodeString( &nameW, ShowDotFilesW );
743 if (!NtQueryValueKey( hkey, &nameW, KeyValuePartialInformation, tmp, sizeof(tmp), &dummy ))
745 WCHAR *str = (WCHAR *)((KEY_VALUE_PARTIAL_INFORMATION *)tmp)->Data;
746 ret = IS_OPTION_TRUE( str[0] );
748 NtClose( hkey );
750 return ret;
754 /***********************************************************************
755 * FILE_Stat
757 * Stat a Unix path name. Return TRUE if OK.
759 BOOL FILE_Stat( LPCSTR unixName, BY_HANDLE_FILE_INFORMATION *info, BOOL *is_symlink_ptr )
761 struct stat st;
762 int is_symlink;
763 LPCSTR p;
765 if (lstat( unixName, &st ) == -1)
767 FILE_SetDosError();
768 return FALSE;
770 is_symlink = S_ISLNK(st.st_mode);
771 if (is_symlink)
773 /* do a "real" stat to find out
774 about the type of the symlink destination */
775 if (stat( unixName, &st ) == -1)
777 FILE_SetDosError();
778 return FALSE;
782 /* fill in the information we gathered so far */
783 FILE_FillInfo( &st, info );
785 /* and now see if this is a hidden file, based on the name */
786 p = strrchr( unixName, '/');
787 p = p ? p + 1 : unixName;
788 if (*p == '.' && *(p+1) && (*(p+1) != '.' || *(p+2)))
790 static int show_dot_files = -1;
791 if (show_dot_files == -1)
792 show_dot_files = get_show_dot_files_option();
793 if (!show_dot_files)
794 info->dwFileAttributes |= FILE_ATTRIBUTE_HIDDEN;
796 if (is_symlink_ptr) *is_symlink_ptr = is_symlink;
797 return TRUE;
801 /***********************************************************************
802 * GetFileInformationByHandle (KERNEL32.@)
804 DWORD WINAPI GetFileInformationByHandle( HANDLE hFile,
805 BY_HANDLE_FILE_INFORMATION *info )
807 DWORD ret;
808 if (!info) return 0;
810 TRACE("%p\n", hFile);
812 SERVER_START_REQ( get_file_info )
814 req->handle = hFile;
815 if ((ret = !wine_server_call_err( req )))
817 /* FIXME: which file types are supported ?
818 * Serial ports (FILE_TYPE_CHAR) are not,
819 * and MSDN also says that pipes are not supported.
820 * FILE_TYPE_REMOTE seems to be supported according to
821 * MSDN q234741.txt */
822 if ((reply->type == FILE_TYPE_DISK) || (reply->type == FILE_TYPE_REMOTE))
824 RtlSecondsSince1970ToTime( reply->write_time, (LARGE_INTEGER *)&info->ftCreationTime );
825 RtlSecondsSince1970ToTime( reply->write_time, (LARGE_INTEGER *)&info->ftLastWriteTime );
826 RtlSecondsSince1970ToTime( reply->access_time, (LARGE_INTEGER *)&info->ftLastAccessTime );
827 info->dwFileAttributes = reply->attr;
828 info->dwVolumeSerialNumber = reply->serial;
829 info->nFileSizeHigh = reply->size_high;
830 info->nFileSizeLow = reply->size_low;
831 info->nNumberOfLinks = reply->links;
832 info->nFileIndexHigh = reply->index_high;
833 info->nFileIndexLow = reply->index_low;
835 else
837 SetLastError(ERROR_NOT_SUPPORTED);
838 ret = 0;
842 SERVER_END_REQ;
843 return ret;
847 /**************************************************************************
848 * GetFileAttributesW (KERNEL32.@)
850 DWORD WINAPI GetFileAttributesW( LPCWSTR name )
852 DOS_FULL_NAME full_name;
853 BY_HANDLE_FILE_INFORMATION info;
855 if (name == NULL)
857 SetLastError( ERROR_INVALID_PARAMETER );
858 return -1;
860 if (!DOSFS_GetFullName( name, TRUE, &full_name) )
861 return -1;
862 if (!FILE_Stat( full_name.long_name, &info, NULL )) return -1;
863 return info.dwFileAttributes;
867 /**************************************************************************
868 * GetFileAttributesA (KERNEL32.@)
870 DWORD WINAPI GetFileAttributesA( LPCSTR name )
872 UNICODE_STRING nameW;
873 DWORD ret = (DWORD)-1;
875 if (!name)
877 SetLastError( ERROR_INVALID_PARAMETER );
878 return (DWORD)-1;
881 if (RtlCreateUnicodeStringFromAsciiz(&nameW, name))
883 ret = GetFileAttributesW(nameW.Buffer);
884 RtlFreeUnicodeString(&nameW);
886 else
887 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
888 return ret;
892 /**************************************************************************
893 * SetFileAttributesW (KERNEL32.@)
895 BOOL WINAPI SetFileAttributesW(LPCWSTR lpFileName, DWORD attributes)
897 struct stat buf;
898 DOS_FULL_NAME full_name;
900 if (!lpFileName)
902 SetLastError( ERROR_INVALID_PARAMETER );
903 return FALSE;
906 TRACE("(%s,%lx)\n", debugstr_w(lpFileName), attributes);
908 if (!DOSFS_GetFullName( lpFileName, TRUE, &full_name ))
909 return FALSE;
911 if(stat(full_name.long_name,&buf)==-1)
913 FILE_SetDosError();
914 return FALSE;
916 if (attributes & FILE_ATTRIBUTE_READONLY)
918 if(S_ISDIR(buf.st_mode))
919 /* FIXME */
920 WARN("FILE_ATTRIBUTE_READONLY ignored for directory.\n");
921 else
922 buf.st_mode &= ~0222; /* octal!, clear write permission bits */
923 attributes &= ~FILE_ATTRIBUTE_READONLY;
925 else
927 /* add write permission */
928 buf.st_mode |= (0600 | ((buf.st_mode & 044) >> 1)) & (~FILE_umask);
930 if (attributes & FILE_ATTRIBUTE_DIRECTORY)
932 if (!S_ISDIR(buf.st_mode))
933 FIXME("SetFileAttributes expected the file %s to be a directory\n",
934 debugstr_w(lpFileName));
935 attributes &= ~FILE_ATTRIBUTE_DIRECTORY;
937 attributes &= ~(FILE_ATTRIBUTE_NORMAL|FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_HIDDEN|FILE_ATTRIBUTE_SYSTEM);
938 if (attributes)
939 FIXME("(%s):%lx attribute(s) not implemented.\n", debugstr_w(lpFileName), attributes);
940 if (-1==chmod(full_name.long_name,buf.st_mode))
942 if (GetDriveTypeW(lpFileName) == DRIVE_CDROM)
944 SetLastError( ERROR_ACCESS_DENIED );
945 return FALSE;
949 * FIXME: We don't return FALSE here because of differences between
950 * Linux and Windows privileges. Under Linux only the owner of
951 * the file is allowed to change file attributes. Under Windows,
952 * applications expect that if you can write to a file, you can also
953 * change its attributes (see GENERIC_WRITE). We could try to be
954 * clever here but that would break multi-user installations where
955 * users share read-only DLLs. This is because some installers like
956 * to change attributes of already installed DLLs.
958 FIXME("Couldn't set file attributes for existing file \"%s\".\n"
959 "Check permissions or set VFAT \"quiet\" mount flag\n", full_name.long_name);
961 return TRUE;
965 /**************************************************************************
966 * SetFileAttributesA (KERNEL32.@)
968 BOOL WINAPI SetFileAttributesA(LPCSTR lpFileName, DWORD attributes)
970 UNICODE_STRING filenameW;
971 BOOL ret = FALSE;
973 if (!lpFileName)
975 SetLastError( ERROR_INVALID_PARAMETER );
976 return FALSE;
979 if (RtlCreateUnicodeStringFromAsciiz(&filenameW, lpFileName))
981 ret = SetFileAttributesW(filenameW.Buffer, attributes);
982 RtlFreeUnicodeString(&filenameW);
984 else
985 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
986 return ret;
990 /***********************************************************************
991 * GetFileTime (KERNEL32.@)
993 BOOL WINAPI GetFileTime( HANDLE hFile, FILETIME *lpCreationTime,
994 FILETIME *lpLastAccessTime,
995 FILETIME *lpLastWriteTime )
997 BY_HANDLE_FILE_INFORMATION info;
998 if (!GetFileInformationByHandle( hFile, &info )) return FALSE;
999 if (lpCreationTime) *lpCreationTime = info.ftCreationTime;
1000 if (lpLastAccessTime) *lpLastAccessTime = info.ftLastAccessTime;
1001 if (lpLastWriteTime) *lpLastWriteTime = info.ftLastWriteTime;
1002 return TRUE;
1006 /***********************************************************************
1007 * FILE_GetTempFileName : utility for GetTempFileName
1009 static UINT FILE_GetTempFileName( LPCWSTR path, LPCWSTR prefix, UINT unique,
1010 LPWSTR buffer )
1012 static UINT unique_temp;
1013 DOS_FULL_NAME full_name;
1014 int i;
1015 LPWSTR p;
1016 UINT num;
1017 char buf[20];
1019 if ( !path || !prefix || !buffer )
1021 SetLastError( ERROR_INVALID_PARAMETER );
1022 return 0;
1025 if (!unique_temp) unique_temp = time(NULL) & 0xffff;
1026 num = unique ? (unique & 0xffff) : (unique_temp++ & 0xffff);
1028 strcpyW( buffer, path );
1029 p = buffer + strlenW(buffer);
1031 /* add a \, if there isn't one and path is more than just the drive letter ... */
1032 if ( !((strlenW(buffer) == 2) && (buffer[1] == ':'))
1033 && ((p == buffer) || (p[-1] != '\\'))) *p++ = '\\';
1035 for (i = 3; (i > 0) && (*prefix); i--) *p++ = *prefix++;
1037 sprintf( buf, "%04x.tmp", num );
1038 MultiByteToWideChar(CP_ACP, 0, buf, -1, p, 20);
1040 /* Now try to create it */
1042 if (!unique)
1046 HANDLE handle = CreateFileW( buffer, GENERIC_WRITE, 0, NULL,
1047 CREATE_NEW, FILE_ATTRIBUTE_NORMAL, 0 );
1048 if (handle != INVALID_HANDLE_VALUE)
1049 { /* We created it */
1050 TRACE("created %s\n", debugstr_w(buffer) );
1051 CloseHandle( handle );
1052 break;
1054 if (GetLastError() != ERROR_FILE_EXISTS &&
1055 GetLastError() != ERROR_SHARING_VIOLATION)
1056 break; /* No need to go on */
1057 num++;
1058 sprintf( buf, "%04x.tmp", num );
1059 MultiByteToWideChar(CP_ACP, 0, buf, -1, p, 20);
1060 } while (num != (unique & 0xffff));
1063 /* Get the full path name */
1065 if (DOSFS_GetFullName( buffer, FALSE, &full_name ))
1067 char *slash;
1068 /* Check if we have write access in the directory */
1069 if ((slash = strrchr( full_name.long_name, '/' ))) *slash = '\0';
1070 if (access( full_name.long_name, W_OK ) == -1)
1071 WARN("returns %s, which doesn't seem to be writeable.\n",
1072 debugstr_w(buffer) );
1074 TRACE("returning %s\n", debugstr_w(buffer) );
1075 return unique ? unique : num;
1079 /***********************************************************************
1080 * GetTempFileNameA (KERNEL32.@)
1082 UINT WINAPI GetTempFileNameA( LPCSTR path, LPCSTR prefix, UINT unique,
1083 LPSTR buffer)
1085 UNICODE_STRING pathW, prefixW;
1086 WCHAR bufferW[MAX_PATH];
1087 UINT ret;
1089 if ( !path || !prefix || !buffer )
1091 SetLastError( ERROR_INVALID_PARAMETER );
1092 return 0;
1095 RtlCreateUnicodeStringFromAsciiz(&pathW, path);
1096 RtlCreateUnicodeStringFromAsciiz(&prefixW, prefix);
1098 ret = GetTempFileNameW(pathW.Buffer, prefixW.Buffer, unique, bufferW);
1099 if (ret)
1100 WideCharToMultiByte(CP_ACP, 0, bufferW, -1, buffer, MAX_PATH, NULL, NULL);
1102 RtlFreeUnicodeString(&pathW);
1103 RtlFreeUnicodeString(&prefixW);
1104 return ret;
1107 /***********************************************************************
1108 * GetTempFileNameW (KERNEL32.@)
1110 UINT WINAPI GetTempFileNameW( LPCWSTR path, LPCWSTR prefix, UINT unique,
1111 LPWSTR buffer )
1113 return FILE_GetTempFileName( path, prefix, unique, buffer );
1117 /***********************************************************************
1118 * FILE_DoOpenFile
1120 * Implementation of OpenFile16() and OpenFile32().
1122 static HFILE FILE_DoOpenFile( LPCSTR name, OFSTRUCT *ofs, UINT mode, BOOL win32 )
1124 HFILE hFileRet;
1125 HANDLE handle;
1126 FILETIME filetime;
1127 WORD filedatetime[2];
1128 DOS_FULL_NAME full_name;
1129 DWORD access, sharing;
1130 WCHAR *p;
1131 WCHAR buffer[MAX_PATH];
1132 LPWSTR nameW;
1134 if (!ofs) return HFILE_ERROR;
1136 TRACE("%s %s %s %s%s%s%s%s%s%s%s%s\n",name,
1137 ((mode & 0x3 )==OF_READ)?"OF_READ":
1138 ((mode & 0x3 )==OF_WRITE)?"OF_WRITE":
1139 ((mode & 0x3 )==OF_READWRITE)?"OF_READWRITE":"unknown",
1140 ((mode & 0x70 )==OF_SHARE_COMPAT)?"OF_SHARE_COMPAT":
1141 ((mode & 0x70 )==OF_SHARE_DENY_NONE)?"OF_SHARE_DENY_NONE":
1142 ((mode & 0x70 )==OF_SHARE_DENY_READ)?"OF_SHARE_DENY_READ":
1143 ((mode & 0x70 )==OF_SHARE_DENY_WRITE)?"OF_SHARE_DENY_WRITE":
1144 ((mode & 0x70 )==OF_SHARE_EXCLUSIVE)?"OF_SHARE_EXCLUSIVE":"unknown",
1145 ((mode & OF_PARSE )==OF_PARSE)?"OF_PARSE ":"",
1146 ((mode & OF_DELETE )==OF_DELETE)?"OF_DELETE ":"",
1147 ((mode & OF_VERIFY )==OF_VERIFY)?"OF_VERIFY ":"",
1148 ((mode & OF_SEARCH )==OF_SEARCH)?"OF_SEARCH ":"",
1149 ((mode & OF_CANCEL )==OF_CANCEL)?"OF_CANCEL ":"",
1150 ((mode & OF_CREATE )==OF_CREATE)?"OF_CREATE ":"",
1151 ((mode & OF_PROMPT )==OF_PROMPT)?"OF_PROMPT ":"",
1152 ((mode & OF_EXIST )==OF_EXIST)?"OF_EXIST ":"",
1153 ((mode & OF_REOPEN )==OF_REOPEN)?"OF_REOPEN ":""
1157 ofs->cBytes = sizeof(OFSTRUCT);
1158 ofs->nErrCode = 0;
1159 if (mode & OF_REOPEN) name = ofs->szPathName;
1161 if (!name) {
1162 ERR("called with `name' set to NULL ! Please debug.\n");
1163 return HFILE_ERROR;
1166 TRACE("%s %04x\n", name, mode );
1168 /* the watcom 10.6 IDE relies on a valid path returned in ofs->szPathName
1169 Are there any cases where getting the path here is wrong?
1170 Uwe Bonnes 1997 Apr 2 */
1171 if (!GetFullPathNameA( name, sizeof(ofs->szPathName),
1172 ofs->szPathName, NULL )) goto error;
1173 FILE_ConvertOFMode( mode, &access, &sharing );
1175 /* OF_PARSE simply fills the structure */
1177 if (mode & OF_PARSE)
1179 ofs->fFixedDisk = (GetDriveType16( ofs->szPathName[0]-'A' )
1180 != DRIVE_REMOVABLE);
1181 TRACE("(%s): OF_PARSE, res = '%s'\n",
1182 name, ofs->szPathName );
1183 return 0;
1186 /* OF_CREATE is completely different from all other options, so
1187 handle it first */
1189 if (mode & OF_CREATE)
1191 if ((handle = CreateFileA( name, GENERIC_READ | GENERIC_WRITE,
1192 sharing, NULL, CREATE_ALWAYS,
1193 FILE_ATTRIBUTE_NORMAL, 0 ))== INVALID_HANDLE_VALUE)
1194 goto error;
1195 goto success;
1198 MultiByteToWideChar(CP_ACP, 0, name, -1, buffer, MAX_PATH);
1199 nameW = buffer;
1201 /* If OF_SEARCH is set, ignore the given path */
1203 if ((mode & OF_SEARCH) && !(mode & OF_REOPEN))
1205 /* First try the file name as is */
1206 if (DOSFS_GetFullName( nameW, TRUE, &full_name )) goto found;
1207 /* Now remove the path */
1208 if (nameW[0] && (nameW[1] == ':')) nameW += 2;
1209 if ((p = strrchrW( nameW, '\\' ))) nameW = p + 1;
1210 if ((p = strrchrW( nameW, '/' ))) nameW = p + 1;
1211 if (!nameW[0]) goto not_found;
1214 /* Now look for the file */
1216 if (!DIR_SearchPath( NULL, nameW, NULL, &full_name, win32 )) goto not_found;
1218 found:
1219 TRACE("found %s = %s\n",
1220 full_name.long_name, debugstr_w(full_name.short_name) );
1221 WideCharToMultiByte(CP_ACP, 0, full_name.short_name, -1,
1222 ofs->szPathName, sizeof(ofs->szPathName), NULL, NULL);
1224 if (mode & OF_SHARE_EXCLUSIVE)
1225 /* Some InstallShield version uses OF_SHARE_EXCLUSIVE
1226 on the file <tempdir>/_ins0432._mp to determine how
1227 far installation has proceeded.
1228 _ins0432._mp is an executable and while running the
1229 application expects the open with OF_SHARE_ to fail*/
1230 /* Probable FIXME:
1231 As our loader closes the files after loading the executable,
1232 we can't find the running executable with FILE_InUse.
1233 The loader should keep the file open, as Windows does that, too.
1236 char *last = strrchr(full_name.long_name,'/');
1237 if (!last)
1238 last = full_name.long_name - 1;
1239 if (GetModuleHandle16(last+1))
1241 TRACE("Denying shared open for %s\n",full_name.long_name);
1242 return HFILE_ERROR;
1246 if (mode & OF_DELETE)
1248 if (unlink( full_name.long_name ) == -1) goto not_found;
1249 TRACE("(%s): OF_DELETE return = OK\n", name);
1250 return 1;
1253 handle = FILE_CreateFile( full_name.long_name, access, sharing,
1254 NULL, OPEN_EXISTING, 0, 0,
1255 DRIVE_GetFlags(full_name.drive) & DRIVE_FAIL_READ_ONLY,
1256 GetDriveTypeW( full_name.short_name ) );
1257 if (!handle) goto not_found;
1259 GetFileTime( handle, NULL, NULL, &filetime );
1260 FileTimeToDosDateTime( &filetime, &filedatetime[0], &filedatetime[1] );
1261 if ((mode & OF_VERIFY) && (mode & OF_REOPEN))
1263 if (ofs->Reserved1 != filedatetime[0] || ofs->Reserved2 != filedatetime[1] )
1265 CloseHandle( handle );
1266 WARN("(%s): OF_VERIFY failed\n", name );
1267 /* FIXME: what error here? */
1268 SetLastError( ERROR_FILE_NOT_FOUND );
1269 goto error;
1272 ofs->Reserved1 = filedatetime[0];
1273 ofs->Reserved2 = filedatetime[1];
1275 success: /* We get here if the open was successful */
1276 TRACE("(%s): OK, return = %p\n", name, handle );
1277 if (win32)
1279 hFileRet = (HFILE)handle;
1280 if (mode & OF_EXIST) /* Return the handle, but close it first */
1281 CloseHandle( handle );
1283 else
1285 hFileRet = Win32HandleToDosFileHandle( handle );
1286 if (hFileRet == HFILE_ERROR16) goto error;
1287 if (mode & OF_EXIST) /* Return the handle, but close it first */
1288 _lclose16( hFileRet );
1290 return hFileRet;
1292 not_found: /* We get here if the file does not exist */
1293 WARN("'%s' not found or sharing violation\n", name );
1294 SetLastError( ERROR_FILE_NOT_FOUND );
1295 /* fall through */
1297 error: /* We get here if there was an error opening the file */
1298 ofs->nErrCode = GetLastError();
1299 WARN("(%s): return = HFILE_ERROR error= %d\n",
1300 name,ofs->nErrCode );
1301 return HFILE_ERROR;
1305 /***********************************************************************
1306 * OpenFile (KERNEL.74)
1307 * OpenFileEx (KERNEL.360)
1309 HFILE16 WINAPI OpenFile16( LPCSTR name, OFSTRUCT *ofs, UINT16 mode )
1311 return FILE_DoOpenFile( name, ofs, mode, FALSE );
1315 /***********************************************************************
1316 * OpenFile (KERNEL32.@)
1318 HFILE WINAPI OpenFile( LPCSTR name, OFSTRUCT *ofs, UINT mode )
1320 return FILE_DoOpenFile( name, ofs, mode, TRUE );
1324 /***********************************************************************
1325 * FILE_InitProcessDosHandles
1327 * Allocates the default DOS handles for a process. Called either by
1328 * Win32HandleToDosFileHandle below or by the DOSVM stuff.
1330 static void FILE_InitProcessDosHandles( void )
1332 HANDLE cp = GetCurrentProcess();
1333 DuplicateHandle(cp, GetStdHandle(STD_INPUT_HANDLE), cp, &dos_handles[0],
1334 0, TRUE, DUPLICATE_SAME_ACCESS);
1335 DuplicateHandle(cp, GetStdHandle(STD_OUTPUT_HANDLE), cp, &dos_handles[1],
1336 0, TRUE, DUPLICATE_SAME_ACCESS);
1337 DuplicateHandle(cp, GetStdHandle(STD_ERROR_HANDLE), cp, &dos_handles[2],
1338 0, TRUE, DUPLICATE_SAME_ACCESS);
1339 DuplicateHandle(cp, GetStdHandle(STD_ERROR_HANDLE), cp, &dos_handles[3],
1340 0, TRUE, DUPLICATE_SAME_ACCESS);
1341 DuplicateHandle(cp, GetStdHandle(STD_ERROR_HANDLE), cp, &dos_handles[4],
1342 0, TRUE, DUPLICATE_SAME_ACCESS);
1345 /***********************************************************************
1346 * Win32HandleToDosFileHandle (KERNEL32.21)
1348 * Allocate a DOS handle for a Win32 handle. The Win32 handle is no
1349 * longer valid after this function (even on failure).
1351 * Note: this is not exactly right, since on Win95 the Win32 handles
1352 * are on top of DOS handles and we do it the other way
1353 * around. Should be good enough though.
1355 HFILE WINAPI Win32HandleToDosFileHandle( HANDLE handle )
1357 int i;
1359 if (!handle || (handle == INVALID_HANDLE_VALUE))
1360 return HFILE_ERROR;
1362 for (i = 5; i < DOS_TABLE_SIZE; i++)
1363 if (!dos_handles[i])
1365 dos_handles[i] = handle;
1366 TRACE("Got %d for h32 %p\n", i, handle );
1367 return (HFILE)i;
1369 CloseHandle( handle );
1370 SetLastError( ERROR_TOO_MANY_OPEN_FILES );
1371 return HFILE_ERROR;
1375 /***********************************************************************
1376 * DosFileHandleToWin32Handle (KERNEL32.20)
1378 * Return the Win32 handle for a DOS handle.
1380 * Note: this is not exactly right, since on Win95 the Win32 handles
1381 * are on top of DOS handles and we do it the other way
1382 * around. Should be good enough though.
1384 HANDLE WINAPI DosFileHandleToWin32Handle( HFILE handle )
1386 HFILE16 hfile = (HFILE16)handle;
1387 if (hfile < 5 && !dos_handles[hfile]) FILE_InitProcessDosHandles();
1388 if ((hfile >= DOS_TABLE_SIZE) || !dos_handles[hfile])
1390 SetLastError( ERROR_INVALID_HANDLE );
1391 return INVALID_HANDLE_VALUE;
1393 return dos_handles[hfile];
1397 /***********************************************************************
1398 * DisposeLZ32Handle (KERNEL32.22)
1400 * Note: this is not entirely correct, we should only close the
1401 * 32-bit handle and not the 16-bit one, but we cannot do
1402 * this because of the way our DOS handles are implemented.
1403 * It shouldn't break anything though.
1405 void WINAPI DisposeLZ32Handle( HANDLE handle )
1407 int i;
1409 if (!handle || (handle == INVALID_HANDLE_VALUE)) return;
1411 for (i = 5; i < DOS_TABLE_SIZE; i++)
1412 if (dos_handles[i] == handle)
1414 dos_handles[i] = 0;
1415 CloseHandle( handle );
1416 break;
1421 /***********************************************************************
1422 * FILE_Dup2
1424 * dup2() function for DOS handles.
1426 HFILE16 FILE_Dup2( HFILE16 hFile1, HFILE16 hFile2 )
1428 HANDLE new_handle;
1430 if (hFile1 < 5 && !dos_handles[hFile1]) FILE_InitProcessDosHandles();
1432 if ((hFile1 >= DOS_TABLE_SIZE) || (hFile2 >= DOS_TABLE_SIZE) || !dos_handles[hFile1])
1434 SetLastError( ERROR_INVALID_HANDLE );
1435 return HFILE_ERROR16;
1437 if (!DuplicateHandle( GetCurrentProcess(), dos_handles[hFile1],
1438 GetCurrentProcess(), &new_handle,
1439 0, FALSE, DUPLICATE_SAME_ACCESS ))
1440 return HFILE_ERROR16;
1441 if (dos_handles[hFile2]) CloseHandle( dos_handles[hFile2] );
1442 dos_handles[hFile2] = new_handle;
1443 return hFile2;
1447 /***********************************************************************
1448 * _lclose (KERNEL.81)
1450 HFILE16 WINAPI _lclose16( HFILE16 hFile )
1452 if ((hFile >= DOS_TABLE_SIZE) || !dos_handles[hFile])
1454 SetLastError( ERROR_INVALID_HANDLE );
1455 return HFILE_ERROR16;
1457 TRACE("%d (handle32=%p)\n", hFile, dos_handles[hFile] );
1458 CloseHandle( dos_handles[hFile] );
1459 dos_handles[hFile] = 0;
1460 return 0;
1464 /******************************************************************
1465 * FILE_ReadWriteApc (internal)
1469 static void WINAPI FILE_ReadWriteApc(void* apc_user, PIO_STATUS_BLOCK io_status, ULONG len)
1471 LPOVERLAPPED_COMPLETION_ROUTINE cr = (LPOVERLAPPED_COMPLETION_ROUTINE)apc_user;
1473 cr(RtlNtStatusToDosError(io_status->u.Status), len, (LPOVERLAPPED)io_status);
1476 /***********************************************************************
1477 * ReadFileEx (KERNEL32.@)
1479 BOOL WINAPI ReadFileEx(HANDLE hFile, LPVOID buffer, DWORD bytesToRead,
1480 LPOVERLAPPED overlapped,
1481 LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine)
1483 LARGE_INTEGER offset;
1484 NTSTATUS status;
1485 PIO_STATUS_BLOCK io_status;
1487 if (!overlapped)
1489 SetLastError(ERROR_INVALID_PARAMETER);
1490 return FALSE;
1493 offset.s.LowPart = overlapped->Offset;
1494 offset.s.HighPart = overlapped->OffsetHigh;
1495 io_status = (PIO_STATUS_BLOCK)overlapped;
1496 io_status->u.Status = STATUS_PENDING;
1498 status = NtReadFile(hFile, NULL, FILE_ReadWriteApc, lpCompletionRoutine,
1499 io_status, buffer, bytesToRead, &offset, NULL);
1501 if (status)
1503 SetLastError( RtlNtStatusToDosError(status) );
1504 return FALSE;
1506 return TRUE;
1509 /***********************************************************************
1510 * ReadFile (KERNEL32.@)
1512 BOOL WINAPI ReadFile( HANDLE hFile, LPVOID buffer, DWORD bytesToRead,
1513 LPDWORD bytesRead, LPOVERLAPPED overlapped )
1515 LARGE_INTEGER offset;
1516 PLARGE_INTEGER poffset = NULL;
1517 IO_STATUS_BLOCK iosb;
1518 PIO_STATUS_BLOCK io_status = &iosb;
1519 HANDLE hEvent = 0;
1520 NTSTATUS status;
1522 TRACE("%p %p %ld %p %p\n", hFile, buffer, bytesToRead,
1523 bytesRead, overlapped );
1525 if (bytesRead) *bytesRead = 0; /* Do this before anything else */
1526 if (!bytesToRead) return TRUE;
1528 if (IsBadReadPtr(buffer, bytesToRead))
1530 SetLastError(ERROR_WRITE_FAULT); /* FIXME */
1531 return FALSE;
1533 if (is_console_handle(hFile))
1534 return FILE_ReadConsole(hFile, buffer, bytesToRead, bytesRead, NULL);
1536 if (overlapped != NULL)
1538 offset.s.LowPart = overlapped->Offset;
1539 offset.s.HighPart = overlapped->OffsetHigh;
1540 poffset = &offset;
1541 hEvent = overlapped->hEvent;
1542 io_status = (PIO_STATUS_BLOCK)overlapped;
1544 io_status->u.Status = STATUS_PENDING;
1545 io_status->Information = 0;
1547 status = NtReadFile(hFile, hEvent, NULL, NULL, io_status, buffer, bytesToRead, poffset, NULL);
1549 if (status != STATUS_PENDING && bytesRead)
1550 *bytesRead = io_status->Information;
1552 if (status && status != STATUS_END_OF_FILE)
1554 SetLastError( RtlNtStatusToDosError(status) );
1555 return FALSE;
1557 return TRUE;
1561 /***********************************************************************
1562 * WriteFileEx (KERNEL32.@)
1564 BOOL WINAPI WriteFileEx(HANDLE hFile, LPCVOID buffer, DWORD bytesToWrite,
1565 LPOVERLAPPED overlapped,
1566 LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine)
1568 LARGE_INTEGER offset;
1569 NTSTATUS status;
1570 PIO_STATUS_BLOCK io_status;
1572 TRACE("%p %p %ld %p %p\n",
1573 hFile, buffer, bytesToWrite, overlapped, lpCompletionRoutine);
1575 if (overlapped == NULL)
1577 SetLastError(ERROR_INVALID_PARAMETER);
1578 return FALSE;
1580 offset.s.LowPart = overlapped->Offset;
1581 offset.s.HighPart = overlapped->OffsetHigh;
1583 io_status = (PIO_STATUS_BLOCK)overlapped;
1584 io_status->u.Status = STATUS_PENDING;
1586 status = NtWriteFile(hFile, NULL, FILE_ReadWriteApc, lpCompletionRoutine,
1587 io_status, buffer, bytesToWrite, &offset, NULL);
1589 if (status) SetLastError( RtlNtStatusToDosError(status) );
1590 return !status;
1593 /***********************************************************************
1594 * WriteFile (KERNEL32.@)
1596 BOOL WINAPI WriteFile( HANDLE hFile, LPCVOID buffer, DWORD bytesToWrite,
1597 LPDWORD bytesWritten, LPOVERLAPPED overlapped )
1599 HANDLE hEvent = NULL;
1600 LARGE_INTEGER offset;
1601 PLARGE_INTEGER poffset = NULL;
1602 NTSTATUS status;
1603 IO_STATUS_BLOCK iosb;
1604 PIO_STATUS_BLOCK piosb = &iosb;
1606 TRACE("%p %p %ld %p %p\n",
1607 hFile, buffer, bytesToWrite, bytesWritten, overlapped );
1609 if (is_console_handle(hFile))
1610 return FILE_WriteConsole(hFile, buffer, bytesToWrite, bytesWritten, NULL);
1612 if (IsBadReadPtr(buffer, bytesToWrite))
1614 SetLastError(ERROR_READ_FAULT); /* FIXME */
1615 return FALSE;
1618 if (overlapped)
1620 offset.s.LowPart = overlapped->Offset;
1621 offset.s.HighPart = overlapped->OffsetHigh;
1622 poffset = &offset;
1623 hEvent = overlapped->hEvent;
1624 piosb = (PIO_STATUS_BLOCK)overlapped;
1626 piosb->u.Status = STATUS_PENDING;
1627 piosb->Information = 0;
1629 status = NtWriteFile(hFile, hEvent, NULL, NULL, piosb,
1630 buffer, bytesToWrite, poffset, NULL);
1631 if (status)
1633 SetLastError( RtlNtStatusToDosError(status) );
1634 return FALSE;
1636 if (bytesWritten) *bytesWritten = piosb->Information;
1638 return TRUE;
1642 /***********************************************************************
1643 * SetFilePointer (KERNEL32.@)
1645 DWORD WINAPI SetFilePointer( HANDLE hFile, LONG distance, LONG *highword,
1646 DWORD method )
1648 DWORD ret = INVALID_SET_FILE_POINTER;
1650 TRACE("handle %p offset %ld high %ld origin %ld\n",
1651 hFile, distance, highword?*highword:0, method );
1653 SERVER_START_REQ( set_file_pointer )
1655 req->handle = hFile;
1656 req->low = distance;
1657 req->high = highword ? *highword : (distance >= 0) ? 0 : -1;
1658 /* FIXME: assumes 1:1 mapping between Windows and Unix seek constants */
1659 req->whence = method;
1660 SetLastError( 0 );
1661 if (!wine_server_call_err( req ))
1663 ret = reply->new_low;
1664 if (highword) *highword = reply->new_high;
1667 SERVER_END_REQ;
1668 return ret;
1672 /*************************************************************************
1673 * SetHandleCount (KERNEL32.@)
1675 UINT WINAPI SetHandleCount( UINT count )
1677 return min( 256, count );
1681 /**************************************************************************
1682 * SetEndOfFile (KERNEL32.@)
1684 BOOL WINAPI SetEndOfFile( HANDLE hFile )
1686 BOOL ret;
1687 SERVER_START_REQ( truncate_file )
1689 req->handle = hFile;
1690 ret = !wine_server_call_err( req );
1692 SERVER_END_REQ;
1693 return ret;
1697 /***********************************************************************
1698 * DeleteFileW (KERNEL32.@)
1700 BOOL WINAPI DeleteFileW( LPCWSTR path )
1702 DOS_FULL_NAME full_name;
1703 HANDLE hFile;
1705 TRACE("%s\n", debugstr_w(path) );
1706 if (!path || !*path)
1708 SetLastError(ERROR_PATH_NOT_FOUND);
1709 return FALSE;
1711 if (DOSFS_GetDevice( path ))
1713 WARN("cannot remove DOS device %s!\n", debugstr_w(path));
1714 SetLastError( ERROR_FILE_NOT_FOUND );
1715 return FALSE;
1718 if (!DOSFS_GetFullName( path, TRUE, &full_name )) return FALSE;
1720 /* check if we are allowed to delete the source */
1721 hFile = FILE_CreateFile( full_name.long_name, GENERIC_READ|GENERIC_WRITE, 0,
1722 NULL, OPEN_EXISTING, 0, 0, TRUE,
1723 GetDriveTypeW( full_name.short_name ) );
1724 if (!hFile) return FALSE;
1726 if (unlink( full_name.long_name ) == -1)
1728 FILE_SetDosError();
1729 CloseHandle(hFile);
1730 return FALSE;
1732 CloseHandle(hFile);
1733 return TRUE;
1737 /***********************************************************************
1738 * DeleteFileA (KERNEL32.@)
1740 BOOL WINAPI DeleteFileA( LPCSTR path )
1742 UNICODE_STRING pathW;
1743 BOOL ret = FALSE;
1745 if (!path)
1747 SetLastError(ERROR_INVALID_PARAMETER);
1748 return FALSE;
1751 if (RtlCreateUnicodeStringFromAsciiz(&pathW, path))
1753 ret = DeleteFileW(pathW.Buffer);
1754 RtlFreeUnicodeString(&pathW);
1756 else
1757 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1758 return ret;
1762 /***********************************************************************
1763 * GetFileType (KERNEL32.@)
1765 DWORD WINAPI GetFileType( HANDLE hFile )
1767 DWORD ret = FILE_TYPE_UNKNOWN;
1769 if (is_console_handle( hFile ))
1770 return FILE_TYPE_CHAR;
1772 SERVER_START_REQ( get_file_info )
1774 req->handle = hFile;
1775 if (!wine_server_call_err( req )) ret = reply->type;
1777 SERVER_END_REQ;
1778 return ret;
1782 /* check if a file name is for an executable file (.exe or .com) */
1783 inline static BOOL is_executable( const char *name )
1785 int len = strlen(name);
1787 if (len < 4) return FALSE;
1788 return (!strcasecmp( name + len - 4, ".exe" ) ||
1789 !strcasecmp( name + len - 4, ".com" ));
1793 /***********************************************************************
1794 * FILE_AddBootRenameEntry
1796 * Adds an entry to the registry that is loaded when windows boots and
1797 * checks if there are some files to be removed or renamed/moved.
1798 * <fn1> has to be valid and <fn2> may be NULL. If both pointers are
1799 * non-NULL then the file is moved, otherwise it is deleted. The
1800 * entry of the registrykey is always appended with two zero
1801 * terminated strings. If <fn2> is NULL then the second entry is
1802 * simply a single 0-byte. Otherwise the second filename goes
1803 * there. The entries are prepended with \??\ before the path and the
1804 * second filename gets also a '!' as the first character if
1805 * MOVEFILE_REPLACE_EXISTING is set. After the final string another
1806 * 0-byte follows to indicate the end of the strings.
1807 * i.e.:
1808 * \??\D:\test\file1[0]
1809 * !\??\D:\test\file1_renamed[0]
1810 * \??\D:\Test|delete[0]
1811 * [0] <- file is to be deleted, second string empty
1812 * \??\D:\test\file2[0]
1813 * !\??\D:\test\file2_renamed[0]
1814 * [0] <- indicates end of strings
1816 * or:
1817 * \??\D:\test\file1[0]
1818 * !\??\D:\test\file1_renamed[0]
1819 * \??\D:\Test|delete[0]
1820 * [0] <- file is to be deleted, second string empty
1821 * [0] <- indicates end of strings
1824 static BOOL FILE_AddBootRenameEntry( LPCWSTR fn1, LPCWSTR fn2, DWORD flags )
1826 static const WCHAR PreString[] = {'\\','?','?','\\',0};
1827 static const WCHAR ValueName[] = {'P','e','n','d','i','n','g',
1828 'F','i','l','e','R','e','n','a','m','e',
1829 'O','p','e','r','a','t','i','o','n','s',0};
1830 static const WCHAR SessionW[] = {'M','a','c','h','i','n','e','\\',
1831 'S','y','s','t','e','m','\\',
1832 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
1833 'C','o','n','t','r','o','l','\\',
1834 'S','e','s','s','i','o','n',' ','M','a','n','a','g','e','r',0};
1835 static const int info_size = FIELD_OFFSET( KEY_VALUE_PARTIAL_INFORMATION, Data );
1837 OBJECT_ATTRIBUTES attr;
1838 UNICODE_STRING nameW;
1839 KEY_VALUE_PARTIAL_INFORMATION *info;
1840 BOOL rc = FALSE;
1841 HKEY Reboot = 0;
1842 DWORD len0, len1, len2;
1843 DWORD DataSize = 0;
1844 BYTE *Buffer = NULL;
1845 WCHAR *p;
1847 attr.Length = sizeof(attr);
1848 attr.RootDirectory = 0;
1849 attr.ObjectName = &nameW;
1850 attr.Attributes = 0;
1851 attr.SecurityDescriptor = NULL;
1852 attr.SecurityQualityOfService = NULL;
1853 RtlInitUnicodeString( &nameW, SessionW );
1855 if (NtCreateKey( &Reboot, KEY_ALL_ACCESS, &attr, 0, NULL, 0, NULL ) != STATUS_SUCCESS)
1857 WARN("Error creating key for reboot managment [%s]\n",
1858 "SYSTEM\\CurrentControlSet\\Control\\Session Manager");
1859 return FALSE;
1862 len0 = strlenW(PreString);
1863 len1 = strlenW(fn1) + len0 + 1;
1864 if (fn2)
1866 len2 = strlenW(fn2) + len0 + 1;
1867 if (flags & MOVEFILE_REPLACE_EXISTING) len2++; /* Plus 1 because of the leading '!' */
1869 else len2 = 1; /* minimum is the 0 characters for the empty second string */
1871 /* convert characters to bytes */
1872 len0 *= sizeof(WCHAR);
1873 len1 *= sizeof(WCHAR);
1874 len2 *= sizeof(WCHAR);
1876 RtlInitUnicodeString( &nameW, ValueName );
1878 /* First we check if the key exists and if so how many bytes it already contains. */
1879 if (NtQueryValueKey( Reboot, &nameW, KeyValuePartialInformation,
1880 NULL, 0, &DataSize ) == STATUS_BUFFER_OVERFLOW)
1882 if (!(Buffer = HeapAlloc( GetProcessHeap(), 0, DataSize + len1 + len2 + sizeof(WCHAR) )))
1883 goto Quit;
1884 if (NtQueryValueKey( Reboot, &nameW, KeyValuePartialInformation,
1885 Buffer, DataSize, &DataSize )) goto Quit;
1886 info = (KEY_VALUE_PARTIAL_INFORMATION *)Buffer;
1887 if (info->Type != REG_MULTI_SZ) goto Quit;
1888 if (DataSize > sizeof(info)) DataSize -= sizeof(WCHAR); /* remove terminating null (will be added back later) */
1890 else
1892 DataSize = info_size;
1893 if (!(Buffer = HeapAlloc( GetProcessHeap(), 0, DataSize + len1 + len2 + sizeof(WCHAR) )))
1894 goto Quit;
1897 p = (WCHAR *)(Buffer + DataSize);
1898 strcpyW( p, PreString );
1899 strcatW( p, fn1 );
1900 DataSize += len1;
1901 if (fn2)
1903 p = (WCHAR *)(Buffer + DataSize);
1904 if (flags & MOVEFILE_REPLACE_EXISTING)
1905 *p++ = '!';
1906 strcpyW( p, PreString );
1907 strcatW( p, fn2 );
1908 DataSize += len2;
1910 else
1912 p = (WCHAR *)(Buffer + DataSize);
1913 *p = 0;
1914 DataSize += sizeof(WCHAR);
1917 /* add final null */
1918 p = (WCHAR *)(Buffer + DataSize);
1919 *p = 0;
1920 DataSize += sizeof(WCHAR);
1922 rc = !NtSetValueKey(Reboot, &nameW, 0, REG_MULTI_SZ, Buffer + info_size, DataSize - info_size);
1924 Quit:
1925 if (Reboot) NtClose(Reboot);
1926 if (Buffer) HeapFree( GetProcessHeap(), 0, Buffer );
1927 return(rc);
1931 /**************************************************************************
1932 * MoveFileExW (KERNEL32.@)
1934 BOOL WINAPI MoveFileExW( LPCWSTR fn1, LPCWSTR fn2, DWORD flag )
1936 DOS_FULL_NAME full_name1, full_name2;
1937 HANDLE hFile;
1938 DWORD attr = INVALID_FILE_ATTRIBUTES;
1940 TRACE("(%s,%s,%04lx)\n", debugstr_w(fn1), debugstr_w(fn2), flag);
1942 /* FIXME: <Gerhard W. Gruber>sparhawk@gmx.at
1943 In case of W9x and lesser this function should return 120 (ERROR_CALL_NOT_IMPLEMENTED)
1944 to be really compatible. Most programs wont have any problems though. In case
1945 you encounter one, this is what you should return here. I don't know what's up
1946 with NT 3.5. Is this function available there or not?
1947 Does anybody really care about 3.5? :)
1950 /* Filename1 has to be always set to a valid path. Filename2 may be NULL
1951 if the source file has to be deleted.
1953 if (!fn1) {
1954 SetLastError(ERROR_INVALID_PARAMETER);
1955 return FALSE;
1958 /* This function has to be run through in order to process the name properly.
1959 If the BOOTDELAY flag is set, the file doesn't need to exist though. At least
1960 that is the behaviour on NT 4.0. The operation accepts the filenames as
1961 they are given but it can't reply with a reasonable returncode. Success
1962 means in that case success for entering the values into the registry.
1964 if(!DOSFS_GetFullName( fn1, TRUE, &full_name1 ))
1966 if(!(flag & MOVEFILE_DELAY_UNTIL_REBOOT))
1967 return FALSE;
1970 if (fn2) /* !fn2 means delete fn1 */
1972 if (DOSFS_GetFullName( fn2, TRUE, &full_name2 ))
1974 if(!(flag & MOVEFILE_DELAY_UNTIL_REBOOT))
1976 /* target exists, check if we may overwrite */
1977 if (!(flag & MOVEFILE_REPLACE_EXISTING))
1979 SetLastError( ERROR_FILE_EXISTS );
1980 return FALSE;
1984 else
1986 if (!DOSFS_GetFullName( fn2, FALSE, &full_name2 ))
1988 if(!(flag & MOVEFILE_DELAY_UNTIL_REBOOT))
1989 return FALSE;
1993 /* Source name and target path are valid */
1995 if (flag & MOVEFILE_DELAY_UNTIL_REBOOT)
1997 return FILE_AddBootRenameEntry( fn1, fn2, flag );
2000 attr = GetFileAttributesW( fn1 );
2001 if ( attr == INVALID_FILE_ATTRIBUTES ) return FALSE;
2003 /* check if we are allowed to rename the source */
2004 hFile = FILE_CreateFile( full_name1.long_name, 0, 0,
2005 NULL, OPEN_EXISTING, 0, 0, TRUE,
2006 GetDriveTypeW( full_name1.short_name ) );
2007 if (!hFile)
2009 if (GetLastError() != ERROR_ACCESS_DENIED) return FALSE;
2010 if ( !(attr & FILE_ATTRIBUTE_DIRECTORY) ) return FALSE;
2011 /* if it's a directory we can continue */
2013 else CloseHandle(hFile);
2015 /* check, if we are allowed to delete the destination,
2016 ** (but the file not being there is fine) */
2017 hFile = FILE_CreateFile( full_name2.long_name, GENERIC_READ|GENERIC_WRITE, 0,
2018 NULL, OPEN_EXISTING, 0, 0, TRUE,
2019 GetDriveTypeW( full_name2.short_name ) );
2020 if(!hFile && GetLastError() != ERROR_FILE_NOT_FOUND) return FALSE;
2021 CloseHandle(hFile);
2023 if (full_name1.drive != full_name2.drive)
2025 if (!(flag & MOVEFILE_COPY_ALLOWED))
2027 SetLastError( ERROR_NOT_SAME_DEVICE );
2028 return FALSE;
2030 else if ( attr & FILE_ATTRIBUTE_DIRECTORY )
2032 /* Strange, but that's what Windows returns */
2033 SetLastError ( ERROR_ACCESS_DENIED );
2034 return FALSE;
2037 if (rename( full_name1.long_name, full_name2.long_name ) == -1)
2038 /* Try copy/delete unless it's a directory. */
2039 /* FIXME: This does not handle the (unlikely) case that the two locations
2040 are on the same Wine drive, but on different Unix file systems. */
2042 if ( attr & FILE_ATTRIBUTE_DIRECTORY )
2044 FILE_SetDosError();
2045 return FALSE;
2047 else
2049 if ( ! CopyFileW( fn1, fn2, !(flag & MOVEFILE_REPLACE_EXISTING) ))
2050 return FALSE;
2051 if ( ! DeleteFileW ( fn1 ) )
2052 return FALSE;
2055 if (is_executable( full_name1.long_name ) != is_executable( full_name2.long_name ))
2057 struct stat fstat;
2058 if (stat( full_name2.long_name, &fstat ) != -1)
2060 if (is_executable( full_name2.long_name ))
2061 /* set executable bit where read bit is set */
2062 fstat.st_mode |= (fstat.st_mode & 0444) >> 2;
2063 else
2064 fstat.st_mode &= ~0111;
2065 chmod( full_name2.long_name, fstat.st_mode );
2068 return TRUE;
2070 else /* fn2 == NULL means delete source */
2072 if (flag & MOVEFILE_DELAY_UNTIL_REBOOT)
2074 if (flag & MOVEFILE_COPY_ALLOWED) {
2075 WARN("Illegal flag\n");
2076 SetLastError( ERROR_GEN_FAILURE );
2077 return FALSE;
2080 return FILE_AddBootRenameEntry( fn1, NULL, flag );
2083 if (unlink( full_name1.long_name ) == -1)
2085 FILE_SetDosError();
2086 return FALSE;
2088 return TRUE; /* successfully deleted */
2092 /**************************************************************************
2093 * MoveFileExA (KERNEL32.@)
2095 BOOL WINAPI MoveFileExA( LPCSTR fn1, LPCSTR fn2, DWORD flag )
2097 UNICODE_STRING fn1W, fn2W;
2098 BOOL ret;
2100 if (!fn1)
2102 SetLastError(ERROR_INVALID_PARAMETER);
2103 return FALSE;
2106 RtlCreateUnicodeStringFromAsciiz(&fn1W, fn1);
2107 if (fn2) RtlCreateUnicodeStringFromAsciiz(&fn2W, fn2);
2108 else fn2W.Buffer = NULL;
2110 ret = MoveFileExW( fn1W.Buffer, fn2W.Buffer, flag );
2112 RtlFreeUnicodeString(&fn1W);
2113 RtlFreeUnicodeString(&fn2W);
2114 return ret;
2118 /**************************************************************************
2119 * MoveFileW (KERNEL32.@)
2121 * Move file or directory
2123 BOOL WINAPI MoveFileW( LPCWSTR fn1, LPCWSTR fn2 )
2125 return MoveFileExW( fn1, fn2, MOVEFILE_COPY_ALLOWED );
2129 /**************************************************************************
2130 * MoveFileA (KERNEL32.@)
2132 BOOL WINAPI MoveFileA( LPCSTR fn1, LPCSTR fn2 )
2134 return MoveFileExA( fn1, fn2, MOVEFILE_COPY_ALLOWED );
2138 /**************************************************************************
2139 * CopyFileW (KERNEL32.@)
2141 BOOL WINAPI CopyFileW( LPCWSTR source, LPCWSTR dest, BOOL fail_if_exists )
2143 HANDLE h1, h2;
2144 BY_HANDLE_FILE_INFORMATION info;
2145 DWORD count;
2146 BOOL ret = FALSE;
2147 char buffer[2048];
2149 if (!source || !dest)
2151 SetLastError(ERROR_INVALID_PARAMETER);
2152 return FALSE;
2155 TRACE("%s -> %s\n", debugstr_w(source), debugstr_w(dest));
2157 if ((h1 = CreateFileW(source, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE,
2158 NULL, OPEN_EXISTING, 0, 0)) == INVALID_HANDLE_VALUE)
2160 WARN("Unable to open source %s\n", debugstr_w(source));
2161 return FALSE;
2164 if (!GetFileInformationByHandle( h1, &info ))
2166 WARN("GetFileInformationByHandle returned error for %s\n", debugstr_w(source));
2167 CloseHandle( h1 );
2168 return FALSE;
2171 if ((h2 = CreateFileW( dest, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
2172 fail_if_exists ? CREATE_NEW : CREATE_ALWAYS,
2173 info.dwFileAttributes, h1 )) == INVALID_HANDLE_VALUE)
2175 WARN("Unable to open dest %s\n", debugstr_w(dest));
2176 CloseHandle( h1 );
2177 return FALSE;
2180 while (ReadFile( h1, buffer, sizeof(buffer), &count, NULL ) && count)
2182 char *p = buffer;
2183 while (count != 0)
2185 DWORD res;
2186 if (!WriteFile( h2, p, count, &res, NULL ) || !res) goto done;
2187 p += res;
2188 count -= res;
2191 ret = TRUE;
2192 done:
2193 CloseHandle( h1 );
2194 CloseHandle( h2 );
2195 return ret;
2199 /**************************************************************************
2200 * CopyFileA (KERNEL32.@)
2202 BOOL WINAPI CopyFileA( LPCSTR source, LPCSTR dest, BOOL fail_if_exists)
2204 UNICODE_STRING sourceW, destW;
2205 BOOL ret;
2207 if (!source || !dest)
2209 SetLastError(ERROR_INVALID_PARAMETER);
2210 return FALSE;
2213 RtlCreateUnicodeStringFromAsciiz(&sourceW, source);
2214 RtlCreateUnicodeStringFromAsciiz(&destW, dest);
2216 ret = CopyFileW(sourceW.Buffer, destW.Buffer, fail_if_exists);
2218 RtlFreeUnicodeString(&sourceW);
2219 RtlFreeUnicodeString(&destW);
2220 return ret;
2224 /**************************************************************************
2225 * CopyFileExW (KERNEL32.@)
2227 * This implementation ignores most of the extra parameters passed-in into
2228 * the "ex" version of the method and calls the CopyFile method.
2229 * It will have to be fixed eventually.
2231 BOOL WINAPI CopyFileExW(LPCWSTR sourceFilename, LPCWSTR destFilename,
2232 LPPROGRESS_ROUTINE progressRoutine, LPVOID appData,
2233 LPBOOL cancelFlagPointer, DWORD copyFlags)
2236 * Interpret the only flag that CopyFile can interpret.
2238 return CopyFileW(sourceFilename, destFilename, (copyFlags & COPY_FILE_FAIL_IF_EXISTS) != 0);
2242 /**************************************************************************
2243 * CopyFileExA (KERNEL32.@)
2245 BOOL WINAPI CopyFileExA(LPCSTR sourceFilename, LPCSTR destFilename,
2246 LPPROGRESS_ROUTINE progressRoutine, LPVOID appData,
2247 LPBOOL cancelFlagPointer, DWORD copyFlags)
2249 UNICODE_STRING sourceW, destW;
2250 BOOL ret;
2252 if (!sourceFilename || !destFilename)
2254 SetLastError(ERROR_INVALID_PARAMETER);
2255 return FALSE;
2258 RtlCreateUnicodeStringFromAsciiz(&sourceW, sourceFilename);
2259 RtlCreateUnicodeStringFromAsciiz(&destW, destFilename);
2261 ret = CopyFileExW(sourceW.Buffer, destW.Buffer, progressRoutine, appData,
2262 cancelFlagPointer, copyFlags);
2264 RtlFreeUnicodeString(&sourceW);
2265 RtlFreeUnicodeString(&destW);
2266 return ret;
2270 /***********************************************************************
2271 * SetFileTime (KERNEL32.@)
2273 BOOL WINAPI SetFileTime( HANDLE hFile,
2274 const FILETIME *lpCreationTime,
2275 const FILETIME *lpLastAccessTime,
2276 const FILETIME *lpLastWriteTime )
2278 BOOL ret;
2279 SERVER_START_REQ( set_file_time )
2281 req->handle = hFile;
2282 if (lpLastAccessTime)
2283 RtlTimeToSecondsSince1970( (PLARGE_INTEGER) lpLastAccessTime, (DWORD *)&req->access_time );
2284 else
2285 req->access_time = 0; /* FIXME */
2286 if (lpLastWriteTime)
2287 RtlTimeToSecondsSince1970( (PLARGE_INTEGER) lpLastWriteTime, (DWORD *)&req->write_time );
2288 else
2289 req->write_time = 0; /* FIXME */
2290 ret = !wine_server_call_err( req );
2292 SERVER_END_REQ;
2293 return ret;
2297 /**************************************************************************
2298 * GetFileAttributesExW (KERNEL32.@)
2300 BOOL WINAPI GetFileAttributesExW(
2301 LPCWSTR lpFileName, GET_FILEEX_INFO_LEVELS fInfoLevelId,
2302 LPVOID lpFileInformation)
2304 DOS_FULL_NAME full_name;
2305 BY_HANDLE_FILE_INFORMATION info;
2307 if (!lpFileName || !lpFileInformation)
2309 SetLastError(ERROR_INVALID_PARAMETER);
2310 return FALSE;
2313 if (fInfoLevelId == GetFileExInfoStandard) {
2314 LPWIN32_FILE_ATTRIBUTE_DATA lpFad =
2315 (LPWIN32_FILE_ATTRIBUTE_DATA) lpFileInformation;
2316 if (!DOSFS_GetFullName( lpFileName, TRUE, &full_name )) return FALSE;
2317 if (!FILE_Stat( full_name.long_name, &info, NULL )) return FALSE;
2319 lpFad->dwFileAttributes = info.dwFileAttributes;
2320 lpFad->ftCreationTime = info.ftCreationTime;
2321 lpFad->ftLastAccessTime = info.ftLastAccessTime;
2322 lpFad->ftLastWriteTime = info.ftLastWriteTime;
2323 lpFad->nFileSizeHigh = info.nFileSizeHigh;
2324 lpFad->nFileSizeLow = info.nFileSizeLow;
2326 else {
2327 FIXME("invalid info level %d!\n", fInfoLevelId);
2328 return FALSE;
2331 return TRUE;
2335 /**************************************************************************
2336 * GetFileAttributesExA (KERNEL32.@)
2338 BOOL WINAPI GetFileAttributesExA(
2339 LPCSTR filename, GET_FILEEX_INFO_LEVELS fInfoLevelId,
2340 LPVOID lpFileInformation)
2342 UNICODE_STRING filenameW;
2343 BOOL ret = FALSE;
2345 if (!filename || !lpFileInformation)
2347 SetLastError(ERROR_INVALID_PARAMETER);
2348 return FALSE;
2351 if (RtlCreateUnicodeStringFromAsciiz(&filenameW, filename))
2353 ret = GetFileAttributesExW(filenameW.Buffer, fInfoLevelId, lpFileInformation);
2354 RtlFreeUnicodeString(&filenameW);
2356 else
2357 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
2358 return ret;