Check brush style before printing FIXME.
[wine.git] / files / file.c
blobaa41f201189f55e7445d21d2df2a0f24af3c24d2
1 /*
2 * File handling functions
4 * Copyright 1993 John Burton
5 * Copyright 1996 Alexandre Julliard
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 * TODO:
22 * Fix the CopyFileEx methods to implement the "extended" functionality.
23 * Right now, they simply call the CopyFile method.
26 #include "config.h"
27 #include "wine/port.h"
29 #include <assert.h>
30 #include <ctype.h>
31 #include <errno.h>
32 #include <fcntl.h>
33 #include <stdlib.h>
34 #include <stdarg.h>
35 #include <stdio.h>
36 #include <string.h>
37 #ifdef HAVE_SYS_ERRNO_H
38 #include <sys/errno.h>
39 #endif
40 #include <sys/types.h>
41 #include <sys/stat.h>
42 #ifdef HAVE_SYS_MMAN_H
43 #include <sys/mman.h>
44 #endif
45 #ifdef HAVE_SYS_TIME_H
46 # include <sys/time.h>
47 #endif
48 #ifdef HAVE_SYS_POLL_H
49 # include <sys/poll.h>
50 #endif
51 #include <time.h>
52 #ifdef HAVE_UNISTD_H
53 # include <unistd.h>
54 #endif
55 #ifdef HAVE_UTIME_H
56 # include <utime.h>
57 #endif
59 #define NONAMELESSUNION
60 #define NONAMELESSSTRUCT
61 #include "winerror.h"
62 #include "ntstatus.h"
63 #include "windef.h"
64 #include "winbase.h"
65 #include "winreg.h"
66 #include "winternl.h"
67 #include "wine/winbase16.h"
68 #include "wine/server.h"
70 #include "drive.h"
71 #include "file.h"
72 #include "wincon.h"
73 #include "kernel_private.h"
75 #include "smb.h"
76 #include "wine/unicode.h"
77 #include "wine/debug.h"
79 WINE_DEFAULT_DEBUG_CHANNEL(file);
81 #if defined(MAP_ANONYMOUS) && !defined(MAP_ANON)
82 #define MAP_ANON MAP_ANONYMOUS
83 #endif
85 #define IS_OPTION_TRUE(ch) ((ch) == 'y' || (ch) == 'Y' || (ch) == 't' || (ch) == 'T' || (ch) == '1')
87 HANDLE dos_handles[DOS_TABLE_SIZE];
88 mode_t FILE_umask;
90 /***********************************************************************
91 * FILE_ConvertOFMode
93 * Convert OF_* mode into flags for CreateFile.
95 void FILE_ConvertOFMode( INT mode, DWORD *access, DWORD *sharing )
97 switch(mode & 0x03)
99 case OF_READ: *access = GENERIC_READ; break;
100 case OF_WRITE: *access = GENERIC_WRITE; break;
101 case OF_READWRITE: *access = GENERIC_READ | GENERIC_WRITE; break;
102 default: *access = 0; break;
104 switch(mode & 0x70)
106 case OF_SHARE_EXCLUSIVE: *sharing = 0; break;
107 case OF_SHARE_DENY_WRITE: *sharing = FILE_SHARE_READ; break;
108 case OF_SHARE_DENY_READ: *sharing = FILE_SHARE_WRITE; break;
109 case OF_SHARE_DENY_NONE:
110 case OF_SHARE_COMPAT:
111 default: *sharing = FILE_SHARE_READ | FILE_SHARE_WRITE; break;
116 /***********************************************************************
117 * FILE_strcasecmp
119 * locale-independent case conversion for file I/O
121 int FILE_strcasecmp( const char *str1, const char *str2 )
123 int ret = 0;
124 for ( ; ; str1++, str2++)
125 if ((ret = FILE_toupper(*str1) - FILE_toupper(*str2)) || !*str1) break;
126 return ret;
130 /***********************************************************************
131 * FILE_strncasecmp
133 * locale-independent case conversion for file I/O
135 int FILE_strncasecmp( const char *str1, const char *str2, int len )
137 int ret = 0;
138 for ( ; len > 0; len--, str1++, str2++)
139 if ((ret = FILE_toupper(*str1) - FILE_toupper(*str2)) || !*str1) break;
140 return ret;
144 /***********************************************************************
145 * FILE_SetDosError
147 * Set the DOS error code from errno.
149 void FILE_SetDosError(void)
151 int save_errno = errno; /* errno gets overwritten by printf */
153 TRACE("errno = %d %s\n", errno, strerror(errno));
154 switch (save_errno)
156 case EAGAIN:
157 SetLastError( ERROR_SHARING_VIOLATION );
158 break;
159 case EBADF:
160 SetLastError( ERROR_INVALID_HANDLE );
161 break;
162 case ENOSPC:
163 SetLastError( ERROR_HANDLE_DISK_FULL );
164 break;
165 case EACCES:
166 case EPERM:
167 case EROFS:
168 SetLastError( ERROR_ACCESS_DENIED );
169 break;
170 case EBUSY:
171 SetLastError( ERROR_LOCK_VIOLATION );
172 break;
173 case ENOENT:
174 SetLastError( ERROR_FILE_NOT_FOUND );
175 break;
176 case EISDIR:
177 SetLastError( ERROR_CANNOT_MAKE );
178 break;
179 case ENFILE:
180 case EMFILE:
181 SetLastError( ERROR_NO_MORE_FILES );
182 break;
183 case EEXIST:
184 SetLastError( ERROR_FILE_EXISTS );
185 break;
186 case EINVAL:
187 case ESPIPE:
188 SetLastError( ERROR_SEEK );
189 break;
190 case ENOTEMPTY:
191 SetLastError( ERROR_DIR_NOT_EMPTY );
192 break;
193 case ENOEXEC:
194 SetLastError( ERROR_BAD_FORMAT );
195 break;
196 default:
197 WARN("unknown file error: %s\n", strerror(save_errno) );
198 SetLastError( ERROR_GEN_FAILURE );
199 break;
201 errno = save_errno;
205 /******************************************************************
206 * OpenConsoleW (KERNEL32.@)
208 * Undocumented
209 * Open a handle to the current process console.
210 * Returns INVALID_HANDLE_VALUE on failure.
212 HANDLE WINAPI OpenConsoleW(LPCWSTR name, DWORD access, LPSECURITY_ATTRIBUTES sa,
213 DWORD creation)
215 static const WCHAR coninW[] = {'C','O','N','I','N','$',0};
216 static const WCHAR conoutW[] = {'C','O','N','O','U','T','$',0};
217 BOOL output;
218 HANDLE ret;
220 if (strcmpW(coninW, name) == 0)
221 output = FALSE;
222 else if (strcmpW(conoutW, name) == 0)
223 output = TRUE;
224 else
226 SetLastError(ERROR_INVALID_NAME);
227 return INVALID_HANDLE_VALUE;
229 if (creation != OPEN_EXISTING)
231 SetLastError(ERROR_INVALID_PARAMETER);
232 return INVALID_HANDLE_VALUE;
235 SERVER_START_REQ( open_console )
237 req->from = output;
238 req->access = access;
239 req->share = FILE_SHARE_READ | FILE_SHARE_WRITE;
240 req->inherit = (sa && (sa->nLength>=sizeof(*sa)) && sa->bInheritHandle);
241 SetLastError(0);
242 wine_server_call_err( req );
243 ret = reply->handle;
245 SERVER_END_REQ;
246 return ret ? console_handle_map(ret) : INVALID_HANDLE_VALUE;
249 /******************************************************************
250 * VerifyConsoleIoHandle (KERNEL32.@)
252 * Undocumented
254 BOOL WINAPI VerifyConsoleIoHandle(HANDLE handle)
256 BOOL ret;
258 if (!is_console_handle(handle)) return FALSE;
259 SERVER_START_REQ(get_console_mode)
261 req->handle = console_handle_unmap(handle);
262 ret = !wine_server_call_err( req );
264 SERVER_END_REQ;
265 return ret;
268 /******************************************************************
269 * DuplicateConsoleHandle (KERNEL32.@)
271 * Undocumented
273 HANDLE WINAPI DuplicateConsoleHandle(HANDLE handle, DWORD access, BOOL inherit,
274 DWORD options)
276 HANDLE ret;
278 if (!is_console_handle(handle) ||
279 !DuplicateHandle(GetCurrentProcess(), console_handle_unmap(handle),
280 GetCurrentProcess(), &ret, access, inherit, options))
281 return INVALID_HANDLE_VALUE;
282 return console_handle_map(ret);
285 /******************************************************************
286 * CloseConsoleHandle (KERNEL32.@)
288 * Undocumented
290 BOOL WINAPI CloseConsoleHandle(HANDLE handle)
292 if (!is_console_handle(handle))
294 SetLastError(ERROR_INVALID_PARAMETER);
295 return FALSE;
297 return CloseHandle(console_handle_unmap(handle));
300 /******************************************************************
301 * GetConsoleInputWaitHandle (KERNEL32.@)
303 * Undocumented
305 HANDLE WINAPI GetConsoleInputWaitHandle(void)
307 static HANDLE console_wait_event;
309 /* FIXME: this is not thread safe */
310 if (!console_wait_event)
312 SERVER_START_REQ(get_console_wait_event)
314 if (!wine_server_call_err( req )) console_wait_event = reply->handle;
316 SERVER_END_REQ;
318 return console_wait_event;
320 /* end of FIXME */
323 /***********************************************************************
324 * FILE_CreateFile
326 * Implementation of CreateFile. Takes a Unix path name.
327 * Returns 0 on failure.
329 HANDLE FILE_CreateFile( LPCSTR filename, DWORD access, DWORD sharing,
330 LPSECURITY_ATTRIBUTES sa, DWORD creation,
331 DWORD attributes, HANDLE template, BOOL fail_read_only,
332 UINT drive_type )
334 unsigned int err;
335 HANDLE ret;
337 for (;;)
339 SERVER_START_REQ( create_file )
341 req->access = access;
342 req->inherit = (sa && (sa->nLength>=sizeof(*sa)) && sa->bInheritHandle);
343 req->sharing = sharing;
344 req->create = creation;
345 req->attrs = attributes;
346 req->removable = (drive_type == DRIVE_REMOVABLE || drive_type == DRIVE_CDROM);
347 wine_server_add_data( req, filename, strlen(filename) );
348 SetLastError(0);
349 err = wine_server_call( req );
350 ret = reply->handle;
352 SERVER_END_REQ;
354 /* If write access failed, retry without GENERIC_WRITE */
356 if (!ret && !fail_read_only && (access & GENERIC_WRITE))
358 if ((err == STATUS_MEDIA_WRITE_PROTECTED) || (err == STATUS_ACCESS_DENIED))
360 TRACE("Write access failed for file '%s', trying without "
361 "write access\n", filename);
362 access &= ~GENERIC_WRITE;
363 continue;
367 if (err)
369 /* In the case file creation was rejected due to CREATE_NEW flag
370 * was specified and file with that name already exists, correct
371 * last error is ERROR_FILE_EXISTS and not ERROR_ALREADY_EXISTS.
372 * Note: RtlNtStatusToDosError is not the subject to blame here.
374 if (err == STATUS_OBJECT_NAME_COLLISION)
375 SetLastError( ERROR_FILE_EXISTS );
376 else
377 SetLastError( RtlNtStatusToDosError(err) );
380 if (!ret) WARN("Unable to create file '%s' (GLE %ld)\n", filename, GetLastError());
381 return ret;
386 /***********************************************************************
387 * FILE_CreateDevice
389 * Same as FILE_CreateFile but for a device
390 * Returns 0 on failure.
392 HANDLE FILE_CreateDevice( int client_id, DWORD access, LPSECURITY_ATTRIBUTES sa )
394 HANDLE ret;
395 SERVER_START_REQ( create_device )
397 req->access = access;
398 req->inherit = (sa && (sa->nLength>=sizeof(*sa)) && sa->bInheritHandle);
399 req->id = client_id;
400 SetLastError(0);
401 wine_server_call_err( req );
402 ret = reply->handle;
404 SERVER_END_REQ;
405 return ret;
408 static HANDLE FILE_OpenPipe(LPCWSTR name, DWORD access, LPSECURITY_ATTRIBUTES sa )
410 HANDLE ret;
411 DWORD len = 0;
413 if (name && (len = strlenW(name)) > MAX_PATH)
415 SetLastError( ERROR_FILENAME_EXCED_RANGE );
416 return 0;
418 SERVER_START_REQ( open_named_pipe )
420 req->access = access;
421 req->inherit = (sa && (sa->nLength>=sizeof(*sa)) && sa->bInheritHandle);
422 SetLastError(0);
423 wine_server_add_data( req, name, len * sizeof(WCHAR) );
424 wine_server_call_err( req );
425 ret = reply->handle;
427 SERVER_END_REQ;
428 TRACE("Returned %p\n",ret);
429 return ret;
432 /*************************************************************************
433 * CreateFileW [KERNEL32.@] Creates or opens a file or other object
435 * Creates or opens an object, and returns a handle that can be used to
436 * access that object.
438 * PARAMS
440 * filename [in] pointer to filename to be accessed
441 * access [in] access mode requested
442 * sharing [in] share mode
443 * sa [in] pointer to security attributes
444 * creation [in] how to create the file
445 * attributes [in] attributes for newly created file
446 * template [in] handle to file with extended attributes to copy
448 * RETURNS
449 * Success: Open handle to specified file
450 * Failure: INVALID_HANDLE_VALUE
452 * NOTES
453 * Should call SetLastError() on failure.
455 * BUGS
457 * Doesn't support character devices, template files, or a
458 * lot of the 'attributes' flags yet.
460 HANDLE WINAPI CreateFileW( LPCWSTR filename, DWORD access, DWORD sharing,
461 LPSECURITY_ATTRIBUTES sa, DWORD creation,
462 DWORD attributes, HANDLE template )
464 DOS_FULL_NAME full_name;
465 HANDLE ret;
466 static const WCHAR bkslashes_with_question_markW[] = {'\\','\\','?','\\',0};
467 static const WCHAR bkslashes_with_dotW[] = {'\\','\\','.','\\',0};
468 static const WCHAR bkslashesW[] = {'\\','\\',0};
469 static const WCHAR coninW[] = {'C','O','N','I','N','$',0};
470 static const WCHAR conoutW[] = {'C','O','N','O','U','T','$',0};
472 if (!filename)
474 SetLastError( ERROR_INVALID_PARAMETER );
475 return INVALID_HANDLE_VALUE;
477 TRACE("%s %s%s%s%s%s%s%s attributes 0x%lx\n", debugstr_w(filename),
478 ((access & GENERIC_READ)==GENERIC_READ)?"GENERIC_READ ":"",
479 ((access & GENERIC_WRITE)==GENERIC_WRITE)?"GENERIC_WRITE ":"",
480 (!access)?"QUERY_ACCESS ":"",
481 ((sharing & FILE_SHARE_READ)==FILE_SHARE_READ)?"FILE_SHARE_READ ":"",
482 ((sharing & FILE_SHARE_WRITE)==FILE_SHARE_WRITE)?"FILE_SHARE_WRITE ":"",
483 ((sharing & FILE_SHARE_DELETE)==FILE_SHARE_DELETE)?"FILE_SHARE_DELETE ":"",
484 (creation ==CREATE_NEW)?"CREATE_NEW":
485 (creation ==CREATE_ALWAYS)?"CREATE_ALWAYS ":
486 (creation ==OPEN_EXISTING)?"OPEN_EXISTING ":
487 (creation ==OPEN_ALWAYS)?"OPEN_ALWAYS ":
488 (creation ==TRUNCATE_EXISTING)?"TRUNCATE_EXISTING ":"", attributes);
490 /* If the name starts with '\\?\', ignore the first 4 chars. */
491 if (!strncmpW(filename, bkslashes_with_question_markW, 4))
493 static const WCHAR uncW[] = {'U','N','C','\\',0};
494 filename += 4;
495 if (!strncmpiW(filename, uncW, 4))
497 FIXME("UNC name (%s) not supported.\n", debugstr_w(filename) );
498 SetLastError( ERROR_PATH_NOT_FOUND );
499 return INVALID_HANDLE_VALUE;
503 if (!strncmpW(filename, bkslashes_with_dotW, 4))
505 static const WCHAR pipeW[] = {'P','I','P','E','\\',0};
506 if(!strncmpiW(filename + 4, pipeW, 5))
508 TRACE("Opening a pipe: %s\n", debugstr_w(filename));
509 ret = FILE_OpenPipe( filename, access, sa );
510 goto done;
512 else if (isalphaW(filename[4]) && filename[5] == ':' && filename[6] == '\0')
514 ret = FILE_CreateDevice( (toupperW(filename[4]) - 'A') | 0x20000, access, sa );
515 goto done;
517 else if (!DOSFS_GetDevice( filename ))
519 ret = DEVICE_Open( filename+4, access, sa );
520 goto done;
522 else
523 filename+=4; /* fall into DOSFS_Device case below */
526 /* If the name still starts with '\\', it's a UNC name. */
527 if (!strncmpW(filename, bkslashesW, 2))
529 ret = SMB_CreateFileW(filename, access, sharing, sa, creation, attributes, template );
530 goto done;
533 /* If the name contains a DOS wild card (* or ?), do no create a file */
534 if(strchrW(filename, '*') || strchrW(filename, '?'))
536 SetLastError(ERROR_BAD_PATHNAME);
537 return INVALID_HANDLE_VALUE;
540 /* Open a console for CONIN$ or CONOUT$ */
541 if (!strcmpiW(filename, coninW) || !strcmpiW(filename, conoutW))
543 ret = OpenConsoleW(filename, access, sa, creation);
544 goto done;
547 if (DOSFS_GetDevice( filename ))
549 TRACE("opening device %s\n", debugstr_w(filename) );
551 if (!(ret = DOSFS_OpenDevice( filename, access, attributes, sa )))
553 /* Do not silence this please. It is a critical error. -MM */
554 ERR("Couldn't open device %s!\n", debugstr_w(filename));
555 SetLastError( ERROR_FILE_NOT_FOUND );
557 goto done;
560 /* check for filename, don't check for last entry if creating */
561 if (!DOSFS_GetFullName( filename,
562 (creation == OPEN_EXISTING) ||
563 (creation == TRUNCATE_EXISTING),
564 &full_name )) {
565 WARN("Unable to get full filename from %s (GLE %ld)\n",
566 debugstr_w(filename), GetLastError());
567 return INVALID_HANDLE_VALUE;
570 ret = FILE_CreateFile( full_name.long_name, access, sharing,
571 sa, creation, attributes, template,
572 DRIVE_GetFlags(full_name.drive) & DRIVE_FAIL_READ_ONLY,
573 GetDriveTypeW( full_name.short_name ) );
574 done:
575 if (!ret) ret = INVALID_HANDLE_VALUE;
576 TRACE("returning %p\n", ret);
577 return ret;
582 /*************************************************************************
583 * CreateFileA (KERNEL32.@)
585 HANDLE WINAPI CreateFileA( LPCSTR filename, DWORD access, DWORD sharing,
586 LPSECURITY_ATTRIBUTES sa, DWORD creation,
587 DWORD attributes, HANDLE template)
589 UNICODE_STRING filenameW;
590 HANDLE ret = INVALID_HANDLE_VALUE;
592 if (!filename)
594 SetLastError( ERROR_INVALID_PARAMETER );
595 return INVALID_HANDLE_VALUE;
598 if (RtlCreateUnicodeStringFromAsciiz(&filenameW, filename))
600 ret = CreateFileW(filenameW.Buffer, access, sharing, sa, creation,
601 attributes, template);
602 RtlFreeUnicodeString(&filenameW);
604 else
605 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
606 return ret;
610 /***********************************************************************
611 * FILE_FillInfo
613 * Fill a file information from a struct stat.
615 static void FILE_FillInfo( struct stat *st, BY_HANDLE_FILE_INFORMATION *info )
617 if (S_ISDIR(st->st_mode))
618 info->dwFileAttributes = FILE_ATTRIBUTE_DIRECTORY;
619 else
620 info->dwFileAttributes = FILE_ATTRIBUTE_ARCHIVE;
621 if (!(st->st_mode & S_IWUSR))
622 info->dwFileAttributes |= FILE_ATTRIBUTE_READONLY;
624 RtlSecondsSince1970ToTime( st->st_mtime, (LARGE_INTEGER *)&info->ftCreationTime );
625 RtlSecondsSince1970ToTime( st->st_mtime, (LARGE_INTEGER *)&info->ftLastWriteTime );
626 RtlSecondsSince1970ToTime( st->st_atime, (LARGE_INTEGER *)&info->ftLastAccessTime );
628 info->dwVolumeSerialNumber = 0; /* FIXME */
629 info->nFileSizeHigh = 0;
630 info->nFileSizeLow = 0;
631 if (!S_ISDIR(st->st_mode)) {
632 info->nFileSizeHigh = st->st_size >> 32;
633 info->nFileSizeLow = st->st_size & 0xffffffff;
635 info->nNumberOfLinks = st->st_nlink;
636 info->nFileIndexHigh = 0;
637 info->nFileIndexLow = st->st_ino;
641 /***********************************************************************
642 * get_show_dot_files_option
644 static BOOL get_show_dot_files_option(void)
646 static const WCHAR WineW[] = {'M','a','c','h','i','n','e','\\',
647 'S','o','f','t','w','a','r','e','\\',
648 'W','i','n','e','\\','W','i','n','e','\\',
649 'C','o','n','f','i','g','\\','W','i','n','e',0};
650 static const WCHAR ShowDotFilesW[] = {'S','h','o','w','D','o','t','F','i','l','e','s',0};
652 char tmp[80];
653 HKEY hkey;
654 DWORD dummy;
655 OBJECT_ATTRIBUTES attr;
656 UNICODE_STRING nameW;
657 BOOL ret = FALSE;
659 attr.Length = sizeof(attr);
660 attr.RootDirectory = 0;
661 attr.ObjectName = &nameW;
662 attr.Attributes = 0;
663 attr.SecurityDescriptor = NULL;
664 attr.SecurityQualityOfService = NULL;
665 RtlInitUnicodeString( &nameW, WineW );
667 if (!NtOpenKey( &hkey, KEY_ALL_ACCESS, &attr ))
669 RtlInitUnicodeString( &nameW, ShowDotFilesW );
670 if (!NtQueryValueKey( hkey, &nameW, KeyValuePartialInformation, tmp, sizeof(tmp), &dummy ))
672 WCHAR *str = (WCHAR *)((KEY_VALUE_PARTIAL_INFORMATION *)tmp)->Data;
673 ret = IS_OPTION_TRUE( str[0] );
675 NtClose( hkey );
677 return ret;
681 /***********************************************************************
682 * FILE_Stat
684 * Stat a Unix path name. Return TRUE if OK.
686 BOOL FILE_Stat( LPCSTR unixName, BY_HANDLE_FILE_INFORMATION *info, BOOL *is_symlink_ptr )
688 struct stat st;
689 int is_symlink;
690 LPCSTR p;
692 if (lstat( unixName, &st ) == -1)
694 FILE_SetDosError();
695 return FALSE;
697 is_symlink = S_ISLNK(st.st_mode);
698 if (is_symlink)
700 /* do a "real" stat to find out
701 about the type of the symlink destination */
702 if (stat( unixName, &st ) == -1)
704 FILE_SetDosError();
705 return FALSE;
709 /* fill in the information we gathered so far */
710 FILE_FillInfo( &st, info );
712 /* and now see if this is a hidden file, based on the name */
713 p = strrchr( unixName, '/');
714 p = p ? p + 1 : unixName;
715 if (*p == '.' && *(p+1) && (*(p+1) != '.' || *(p+2)))
717 static int show_dot_files = -1;
718 if (show_dot_files == -1)
719 show_dot_files = get_show_dot_files_option();
720 if (!show_dot_files)
721 info->dwFileAttributes |= FILE_ATTRIBUTE_HIDDEN;
723 if (is_symlink_ptr) *is_symlink_ptr = is_symlink;
724 return TRUE;
728 /***********************************************************************
729 * GetFileInformationByHandle (KERNEL32.@)
731 DWORD WINAPI GetFileInformationByHandle( HANDLE hFile,
732 BY_HANDLE_FILE_INFORMATION *info )
734 DWORD ret;
735 if (!info) return 0;
737 TRACE("%p\n", hFile);
739 SERVER_START_REQ( get_file_info )
741 req->handle = hFile;
742 if ((ret = !wine_server_call_err( req )))
744 /* FIXME: which file types are supported ?
745 * Serial ports (FILE_TYPE_CHAR) are not,
746 * and MSDN also says that pipes are not supported.
747 * FILE_TYPE_REMOTE seems to be supported according to
748 * MSDN q234741.txt */
749 if ((reply->type == FILE_TYPE_DISK) || (reply->type == FILE_TYPE_REMOTE))
751 RtlSecondsSince1970ToTime( reply->write_time, (LARGE_INTEGER *)&info->ftCreationTime );
752 RtlSecondsSince1970ToTime( reply->write_time, (LARGE_INTEGER *)&info->ftLastWriteTime );
753 RtlSecondsSince1970ToTime( reply->access_time, (LARGE_INTEGER *)&info->ftLastAccessTime );
754 info->dwFileAttributes = reply->attr;
755 info->dwVolumeSerialNumber = reply->serial;
756 info->nFileSizeHigh = reply->size_high;
757 info->nFileSizeLow = reply->size_low;
758 info->nNumberOfLinks = reply->links;
759 info->nFileIndexHigh = reply->index_high;
760 info->nFileIndexLow = reply->index_low;
762 else
764 SetLastError(ERROR_NOT_SUPPORTED);
765 ret = 0;
769 SERVER_END_REQ;
770 return ret;
774 /**************************************************************************
775 * GetFileAttributesW (KERNEL32.@)
777 DWORD WINAPI GetFileAttributesW( LPCWSTR name )
779 DOS_FULL_NAME full_name;
780 BY_HANDLE_FILE_INFORMATION info;
782 if (name == NULL)
784 SetLastError( ERROR_INVALID_PARAMETER );
785 return INVALID_FILE_ATTRIBUTES;
787 if (!DOSFS_GetFullName( name, TRUE, &full_name) )
788 return INVALID_FILE_ATTRIBUTES;
789 if (!FILE_Stat( full_name.long_name, &info, NULL ))
790 return INVALID_FILE_ATTRIBUTES;
791 return info.dwFileAttributes;
795 /**************************************************************************
796 * GetFileAttributesA (KERNEL32.@)
798 DWORD WINAPI GetFileAttributesA( LPCSTR name )
800 UNICODE_STRING nameW;
801 DWORD ret = INVALID_FILE_ATTRIBUTES;
803 if (!name)
805 SetLastError( ERROR_INVALID_PARAMETER );
806 return INVALID_FILE_ATTRIBUTES;
809 if (RtlCreateUnicodeStringFromAsciiz(&nameW, name))
811 ret = GetFileAttributesW(nameW.Buffer);
812 RtlFreeUnicodeString(&nameW);
814 else
815 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
816 return ret;
820 /**************************************************************************
821 * SetFileAttributesW (KERNEL32.@)
823 BOOL WINAPI SetFileAttributesW(LPCWSTR lpFileName, DWORD attributes)
825 struct stat buf;
826 DOS_FULL_NAME full_name;
828 if (!lpFileName)
830 SetLastError( ERROR_INVALID_PARAMETER );
831 return FALSE;
834 TRACE("(%s,%lx)\n", debugstr_w(lpFileName), attributes);
836 if (!DOSFS_GetFullName( lpFileName, TRUE, &full_name ))
837 return FALSE;
839 if(stat(full_name.long_name,&buf)==-1)
841 FILE_SetDosError();
842 return FALSE;
844 if (attributes & FILE_ATTRIBUTE_READONLY)
846 if(S_ISDIR(buf.st_mode))
847 /* FIXME */
848 WARN("FILE_ATTRIBUTE_READONLY ignored for directory.\n");
849 else
850 buf.st_mode &= ~0222; /* octal!, clear write permission bits */
851 attributes &= ~FILE_ATTRIBUTE_READONLY;
853 else
855 /* add write permission */
856 buf.st_mode |= (0600 | ((buf.st_mode & 044) >> 1)) & (~FILE_umask);
858 if (attributes & FILE_ATTRIBUTE_DIRECTORY)
860 if (!S_ISDIR(buf.st_mode))
861 FIXME("SetFileAttributes expected the file %s to be a directory\n",
862 debugstr_w(lpFileName));
863 attributes &= ~FILE_ATTRIBUTE_DIRECTORY;
865 attributes &= ~(FILE_ATTRIBUTE_NORMAL|FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_HIDDEN|FILE_ATTRIBUTE_SYSTEM);
866 if (attributes)
867 FIXME("(%s):%lx attribute(s) not implemented.\n", debugstr_w(lpFileName), attributes);
868 if (-1==chmod(full_name.long_name,buf.st_mode))
870 if (GetDriveTypeW(lpFileName) == DRIVE_CDROM)
872 SetLastError( ERROR_ACCESS_DENIED );
873 return FALSE;
877 * FIXME: We don't return FALSE here because of differences between
878 * Linux and Windows privileges. Under Linux only the owner of
879 * the file is allowed to change file attributes. Under Windows,
880 * applications expect that if you can write to a file, you can also
881 * change its attributes (see GENERIC_WRITE). We could try to be
882 * clever here but that would break multi-user installations where
883 * users share read-only DLLs. This is because some installers like
884 * to change attributes of already installed DLLs.
886 FIXME("Couldn't set file attributes for existing file \"%s\".\n"
887 "Check permissions or set VFAT \"quiet\" mount flag\n", full_name.long_name);
889 return TRUE;
893 /**************************************************************************
894 * SetFileAttributesA (KERNEL32.@)
896 BOOL WINAPI SetFileAttributesA(LPCSTR lpFileName, DWORD attributes)
898 UNICODE_STRING filenameW;
899 BOOL ret = FALSE;
901 if (!lpFileName)
903 SetLastError( ERROR_INVALID_PARAMETER );
904 return FALSE;
907 if (RtlCreateUnicodeStringFromAsciiz(&filenameW, lpFileName))
909 ret = SetFileAttributesW(filenameW.Buffer, attributes);
910 RtlFreeUnicodeString(&filenameW);
912 else
913 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
914 return ret;
918 /******************************************************************************
919 * GetCompressedFileSizeA [KERNEL32.@]
921 DWORD WINAPI GetCompressedFileSizeA(
922 LPCSTR lpFileName,
923 LPDWORD lpFileSizeHigh)
925 UNICODE_STRING filenameW;
926 DWORD ret;
928 if (RtlCreateUnicodeStringFromAsciiz(&filenameW, lpFileName))
930 ret = GetCompressedFileSizeW(filenameW.Buffer, lpFileSizeHigh);
931 RtlFreeUnicodeString(&filenameW);
933 else
935 ret = INVALID_FILE_SIZE;
936 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
938 return ret;
942 /******************************************************************************
943 * GetCompressedFileSizeW [KERNEL32.@]
945 * RETURNS
946 * Success: Low-order doubleword of number of bytes
947 * Failure: INVALID_FILE_SIZE
949 DWORD WINAPI GetCompressedFileSizeW(
950 LPCWSTR lpFileName, /* [in] Pointer to name of file */
951 LPDWORD lpFileSizeHigh) /* [out] Receives high-order doubleword of size */
953 DOS_FULL_NAME full_name;
954 struct stat st;
955 DWORD low;
957 TRACE("(%s,%p)\n",debugstr_w(lpFileName),lpFileSizeHigh);
959 if (!DOSFS_GetFullName( lpFileName, TRUE, &full_name )) return INVALID_FILE_SIZE;
960 if (stat(full_name.long_name, &st) != 0)
962 FILE_SetDosError();
963 return INVALID_FILE_SIZE;
965 #if HAVE_STRUCT_STAT_ST_BLOCKS
966 /* blocks are 512 bytes long */
967 if (lpFileSizeHigh) *lpFileSizeHigh = (st.st_blocks >> 23);
968 low = (DWORD)(st.st_blocks << 9);
969 #else
970 if (lpFileSizeHigh) *lpFileSizeHigh = (st.st_size >> 32);
971 low = (DWORD)st.st_size;
972 #endif
973 return low;
977 /***********************************************************************
978 * GetFileTime (KERNEL32.@)
980 BOOL WINAPI GetFileTime( HANDLE hFile, FILETIME *lpCreationTime,
981 FILETIME *lpLastAccessTime,
982 FILETIME *lpLastWriteTime )
984 BY_HANDLE_FILE_INFORMATION info;
985 if (!GetFileInformationByHandle( hFile, &info )) return FALSE;
986 if (lpCreationTime) *lpCreationTime = info.ftCreationTime;
987 if (lpLastAccessTime) *lpLastAccessTime = info.ftLastAccessTime;
988 if (lpLastWriteTime) *lpLastWriteTime = info.ftLastWriteTime;
989 return TRUE;
993 /***********************************************************************
994 * GetTempFileNameA (KERNEL32.@)
996 UINT WINAPI GetTempFileNameA( LPCSTR path, LPCSTR prefix, UINT unique,
997 LPSTR buffer)
999 UNICODE_STRING pathW, prefixW;
1000 WCHAR bufferW[MAX_PATH];
1001 UINT ret;
1003 if ( !path || !prefix || !buffer )
1005 SetLastError( ERROR_INVALID_PARAMETER );
1006 return 0;
1009 RtlCreateUnicodeStringFromAsciiz(&pathW, path);
1010 RtlCreateUnicodeStringFromAsciiz(&prefixW, prefix);
1012 ret = GetTempFileNameW(pathW.Buffer, prefixW.Buffer, unique, bufferW);
1013 if (ret)
1014 WideCharToMultiByte(CP_ACP, 0, bufferW, -1, buffer, MAX_PATH, NULL, NULL);
1016 RtlFreeUnicodeString(&pathW);
1017 RtlFreeUnicodeString(&prefixW);
1018 return ret;
1021 /***********************************************************************
1022 * GetTempFileNameW (KERNEL32.@)
1024 UINT WINAPI GetTempFileNameW( LPCWSTR path, LPCWSTR prefix, UINT unique,
1025 LPWSTR buffer )
1027 static const WCHAR formatW[] = {'%','0','4','x','.','t','m','p',0};
1029 DOS_FULL_NAME full_name;
1030 int i;
1031 LPWSTR p;
1033 if ( !path || !prefix || !buffer )
1035 SetLastError( ERROR_INVALID_PARAMETER );
1036 return 0;
1039 strcpyW( buffer, path );
1040 p = buffer + strlenW(buffer);
1042 /* add a \, if there isn't one and path is more than just the drive letter ... */
1043 if ( !((strlenW(buffer) == 2) && (buffer[1] == ':'))
1044 && ((p == buffer) || (p[-1] != '\\'))) *p++ = '\\';
1046 for (i = 3; (i > 0) && (*prefix); i--) *p++ = *prefix++;
1048 unique &= 0xffff;
1050 if (unique) sprintfW( p, formatW, unique );
1051 else
1053 /* get a "random" unique number and try to create the file */
1054 HANDLE handle;
1055 UINT num = GetTickCount() & 0xffff;
1057 if (!num) num = 1;
1058 unique = num;
1061 sprintfW( p, formatW, unique );
1062 handle = CreateFileW( buffer, GENERIC_WRITE, 0, NULL,
1063 CREATE_NEW, FILE_ATTRIBUTE_NORMAL, 0 );
1064 if (handle != INVALID_HANDLE_VALUE)
1065 { /* We created it */
1066 TRACE("created %s\n", debugstr_w(buffer) );
1067 CloseHandle( handle );
1068 break;
1070 if (GetLastError() != ERROR_FILE_EXISTS &&
1071 GetLastError() != ERROR_SHARING_VIOLATION)
1072 break; /* No need to go on */
1073 if (!(++unique & 0xffff)) unique = 1;
1074 } while (unique != num);
1077 /* Get the full path name */
1079 if (DOSFS_GetFullName( buffer, FALSE, &full_name ))
1081 char *slash;
1082 /* Check if we have write access in the directory */
1083 if ((slash = strrchr( full_name.long_name, '/' ))) *slash = '\0';
1084 if (access( full_name.long_name, W_OK ) == -1)
1085 WARN("returns %s, which doesn't seem to be writeable.\n",
1086 debugstr_w(buffer) );
1088 TRACE("returning %s\n", debugstr_w(buffer) );
1089 return unique;
1093 /***********************************************************************
1094 * FILE_DoOpenFile
1096 * Implementation of OpenFile16() and OpenFile32().
1098 static HFILE FILE_DoOpenFile( LPCSTR name, OFSTRUCT *ofs, UINT mode, BOOL win32 )
1100 HFILE hFileRet;
1101 HANDLE handle;
1102 FILETIME filetime;
1103 WORD filedatetime[2];
1104 DOS_FULL_NAME full_name;
1105 DWORD access, sharing;
1106 WCHAR *p;
1107 WCHAR buffer[MAX_PATH];
1108 LPWSTR nameW;
1110 if (!ofs) return HFILE_ERROR;
1112 TRACE("%s %s %s %s%s%s%s%s%s%s%s%s\n",name,
1113 ((mode & 0x3 )==OF_READ)?"OF_READ":
1114 ((mode & 0x3 )==OF_WRITE)?"OF_WRITE":
1115 ((mode & 0x3 )==OF_READWRITE)?"OF_READWRITE":"unknown",
1116 ((mode & 0x70 )==OF_SHARE_COMPAT)?"OF_SHARE_COMPAT":
1117 ((mode & 0x70 )==OF_SHARE_DENY_NONE)?"OF_SHARE_DENY_NONE":
1118 ((mode & 0x70 )==OF_SHARE_DENY_READ)?"OF_SHARE_DENY_READ":
1119 ((mode & 0x70 )==OF_SHARE_DENY_WRITE)?"OF_SHARE_DENY_WRITE":
1120 ((mode & 0x70 )==OF_SHARE_EXCLUSIVE)?"OF_SHARE_EXCLUSIVE":"unknown",
1121 ((mode & OF_PARSE )==OF_PARSE)?"OF_PARSE ":"",
1122 ((mode & OF_DELETE )==OF_DELETE)?"OF_DELETE ":"",
1123 ((mode & OF_VERIFY )==OF_VERIFY)?"OF_VERIFY ":"",
1124 ((mode & OF_SEARCH )==OF_SEARCH)?"OF_SEARCH ":"",
1125 ((mode & OF_CANCEL )==OF_CANCEL)?"OF_CANCEL ":"",
1126 ((mode & OF_CREATE )==OF_CREATE)?"OF_CREATE ":"",
1127 ((mode & OF_PROMPT )==OF_PROMPT)?"OF_PROMPT ":"",
1128 ((mode & OF_EXIST )==OF_EXIST)?"OF_EXIST ":"",
1129 ((mode & OF_REOPEN )==OF_REOPEN)?"OF_REOPEN ":""
1133 ofs->cBytes = sizeof(OFSTRUCT);
1134 ofs->nErrCode = 0;
1135 if (mode & OF_REOPEN) name = ofs->szPathName;
1137 if (!name) {
1138 ERR("called with `name' set to NULL ! Please debug.\n");
1139 return HFILE_ERROR;
1142 TRACE("%s %04x\n", name, mode );
1144 /* the watcom 10.6 IDE relies on a valid path returned in ofs->szPathName
1145 Are there any cases where getting the path here is wrong?
1146 Uwe Bonnes 1997 Apr 2 */
1147 if (!GetFullPathNameA( name, sizeof(ofs->szPathName),
1148 ofs->szPathName, NULL )) goto error;
1149 FILE_ConvertOFMode( mode, &access, &sharing );
1151 /* OF_PARSE simply fills the structure */
1153 if (mode & OF_PARSE)
1155 ofs->fFixedDisk = (GetDriveType16( ofs->szPathName[0]-'A' )
1156 != DRIVE_REMOVABLE);
1157 TRACE("(%s): OF_PARSE, res = '%s'\n",
1158 name, ofs->szPathName );
1159 return 0;
1162 /* OF_CREATE is completely different from all other options, so
1163 handle it first */
1165 if (mode & OF_CREATE)
1167 if ((handle = CreateFileA( name, GENERIC_READ | GENERIC_WRITE,
1168 sharing, NULL, CREATE_ALWAYS,
1169 FILE_ATTRIBUTE_NORMAL, 0 ))== INVALID_HANDLE_VALUE)
1170 goto error;
1171 goto success;
1174 MultiByteToWideChar(CP_ACP, 0, name, -1, buffer, MAX_PATH);
1175 nameW = buffer;
1177 /* If OF_SEARCH is set, ignore the given path */
1179 if ((mode & OF_SEARCH) && !(mode & OF_REOPEN))
1181 /* First try the file name as is */
1182 if (DOSFS_GetFullName( nameW, TRUE, &full_name )) goto found;
1183 /* Now remove the path */
1184 if (nameW[0] && (nameW[1] == ':')) nameW += 2;
1185 if ((p = strrchrW( nameW, '\\' ))) nameW = p + 1;
1186 if ((p = strrchrW( nameW, '/' ))) nameW = p + 1;
1187 if (!nameW[0]) goto not_found;
1190 /* Now look for the file */
1192 if (!DIR_SearchPath( NULL, nameW, NULL, &full_name, win32 )) goto not_found;
1194 found:
1195 TRACE("found %s = %s\n",
1196 full_name.long_name, debugstr_w(full_name.short_name) );
1197 WideCharToMultiByte(CP_ACP, 0, full_name.short_name, -1,
1198 ofs->szPathName, sizeof(ofs->szPathName), NULL, NULL);
1200 if (mode & OF_DELETE)
1202 handle = FILE_CreateFile( full_name.long_name, GENERIC_READ|GENERIC_WRITE, 0,
1203 NULL, OPEN_EXISTING, 0, 0, TRUE,
1204 GetDriveTypeW( full_name.short_name ) );
1205 if (!handle) goto error;
1206 CloseHandle( handle );
1207 if (unlink( full_name.long_name ) == -1) goto not_found;
1208 TRACE("(%s): OF_DELETE return = OK\n", name);
1209 return 1;
1212 handle = FILE_CreateFile( full_name.long_name, access, sharing,
1213 NULL, OPEN_EXISTING, 0, 0,
1214 DRIVE_GetFlags(full_name.drive) & DRIVE_FAIL_READ_ONLY,
1215 GetDriveTypeW( full_name.short_name ) );
1216 if (!handle) goto not_found;
1218 GetFileTime( handle, NULL, NULL, &filetime );
1219 FileTimeToDosDateTime( &filetime, &filedatetime[0], &filedatetime[1] );
1220 if ((mode & OF_VERIFY) && (mode & OF_REOPEN))
1222 if (ofs->Reserved1 != filedatetime[0] || ofs->Reserved2 != filedatetime[1] )
1224 CloseHandle( handle );
1225 WARN("(%s): OF_VERIFY failed\n", name );
1226 /* FIXME: what error here? */
1227 SetLastError( ERROR_FILE_NOT_FOUND );
1228 goto error;
1231 ofs->Reserved1 = filedatetime[0];
1232 ofs->Reserved2 = filedatetime[1];
1234 success: /* We get here if the open was successful */
1235 TRACE("(%s): OK, return = %p\n", name, handle );
1236 if (win32)
1238 hFileRet = (HFILE)handle;
1239 if (mode & OF_EXIST) /* Return the handle, but close it first */
1240 CloseHandle( handle );
1242 else
1244 hFileRet = Win32HandleToDosFileHandle( handle );
1245 if (hFileRet == HFILE_ERROR16) goto error;
1246 if (mode & OF_EXIST) /* Return the handle, but close it first */
1247 _lclose16( hFileRet );
1249 return hFileRet;
1251 not_found: /* We get here if the file does not exist */
1252 WARN("'%s' not found or sharing violation\n", name );
1253 SetLastError( ERROR_FILE_NOT_FOUND );
1254 /* fall through */
1256 error: /* We get here if there was an error opening the file */
1257 ofs->nErrCode = GetLastError();
1258 WARN("(%s): return = HFILE_ERROR error= %d\n",
1259 name,ofs->nErrCode );
1260 return HFILE_ERROR;
1264 /***********************************************************************
1265 * OpenFile (KERNEL.74)
1266 * OpenFileEx (KERNEL.360)
1268 HFILE16 WINAPI OpenFile16( LPCSTR name, OFSTRUCT *ofs, UINT16 mode )
1270 return FILE_DoOpenFile( name, ofs, mode, FALSE );
1274 /***********************************************************************
1275 * OpenFile (KERNEL32.@)
1277 HFILE WINAPI OpenFile( LPCSTR name, OFSTRUCT *ofs, UINT mode )
1279 return FILE_DoOpenFile( name, ofs, mode, TRUE );
1283 /***********************************************************************
1284 * FILE_InitProcessDosHandles
1286 * Allocates the default DOS handles for a process. Called either by
1287 * Win32HandleToDosFileHandle below or by the DOSVM stuff.
1289 static void FILE_InitProcessDosHandles( void )
1291 HANDLE cp = GetCurrentProcess();
1292 DuplicateHandle(cp, GetStdHandle(STD_INPUT_HANDLE), cp, &dos_handles[0],
1293 0, TRUE, DUPLICATE_SAME_ACCESS);
1294 DuplicateHandle(cp, GetStdHandle(STD_OUTPUT_HANDLE), cp, &dos_handles[1],
1295 0, TRUE, DUPLICATE_SAME_ACCESS);
1296 DuplicateHandle(cp, GetStdHandle(STD_ERROR_HANDLE), cp, &dos_handles[2],
1297 0, TRUE, DUPLICATE_SAME_ACCESS);
1298 DuplicateHandle(cp, GetStdHandle(STD_ERROR_HANDLE), cp, &dos_handles[3],
1299 0, TRUE, DUPLICATE_SAME_ACCESS);
1300 DuplicateHandle(cp, GetStdHandle(STD_ERROR_HANDLE), cp, &dos_handles[4],
1301 0, TRUE, DUPLICATE_SAME_ACCESS);
1304 /***********************************************************************
1305 * Win32HandleToDosFileHandle (KERNEL32.21)
1307 * Allocate a DOS handle for a Win32 handle. The Win32 handle is no
1308 * longer valid after this function (even on failure).
1310 * Note: this is not exactly right, since on Win95 the Win32 handles
1311 * are on top of DOS handles and we do it the other way
1312 * around. Should be good enough though.
1314 HFILE WINAPI Win32HandleToDosFileHandle( HANDLE handle )
1316 int i;
1318 if (!handle || (handle == INVALID_HANDLE_VALUE))
1319 return HFILE_ERROR;
1321 for (i = 5; i < DOS_TABLE_SIZE; i++)
1322 if (!dos_handles[i])
1324 dos_handles[i] = handle;
1325 TRACE("Got %d for h32 %p\n", i, handle );
1326 return (HFILE)i;
1328 CloseHandle( handle );
1329 SetLastError( ERROR_TOO_MANY_OPEN_FILES );
1330 return HFILE_ERROR;
1334 /***********************************************************************
1335 * DosFileHandleToWin32Handle (KERNEL32.20)
1337 * Return the Win32 handle for a DOS handle.
1339 * Note: this is not exactly right, since on Win95 the Win32 handles
1340 * are on top of DOS handles and we do it the other way
1341 * around. Should be good enough though.
1343 HANDLE WINAPI DosFileHandleToWin32Handle( HFILE handle )
1345 HFILE16 hfile = (HFILE16)handle;
1346 if (hfile < 5 && !dos_handles[hfile]) FILE_InitProcessDosHandles();
1347 if ((hfile >= DOS_TABLE_SIZE) || !dos_handles[hfile])
1349 SetLastError( ERROR_INVALID_HANDLE );
1350 return INVALID_HANDLE_VALUE;
1352 return dos_handles[hfile];
1356 /***********************************************************************
1357 * DisposeLZ32Handle (KERNEL32.22)
1359 * Note: this is not entirely correct, we should only close the
1360 * 32-bit handle and not the 16-bit one, but we cannot do
1361 * this because of the way our DOS handles are implemented.
1362 * It shouldn't break anything though.
1364 void WINAPI DisposeLZ32Handle( HANDLE handle )
1366 int i;
1368 if (!handle || (handle == INVALID_HANDLE_VALUE)) return;
1370 for (i = 5; i < DOS_TABLE_SIZE; i++)
1371 if (dos_handles[i] == handle)
1373 dos_handles[i] = 0;
1374 CloseHandle( handle );
1375 break;
1380 /***********************************************************************
1381 * FILE_Dup2
1383 * dup2() function for DOS handles.
1385 HFILE16 FILE_Dup2( HFILE16 hFile1, HFILE16 hFile2 )
1387 HANDLE new_handle;
1389 if (hFile1 < 5 && !dos_handles[hFile1]) FILE_InitProcessDosHandles();
1391 if ((hFile1 >= DOS_TABLE_SIZE) || (hFile2 >= DOS_TABLE_SIZE) || !dos_handles[hFile1])
1393 SetLastError( ERROR_INVALID_HANDLE );
1394 return HFILE_ERROR16;
1396 if (!DuplicateHandle( GetCurrentProcess(), dos_handles[hFile1],
1397 GetCurrentProcess(), &new_handle,
1398 0, FALSE, DUPLICATE_SAME_ACCESS ))
1399 return HFILE_ERROR16;
1400 if (dos_handles[hFile2]) CloseHandle( dos_handles[hFile2] );
1401 dos_handles[hFile2] = new_handle;
1402 return hFile2;
1406 /***********************************************************************
1407 * _lclose (KERNEL.81)
1409 HFILE16 WINAPI _lclose16( HFILE16 hFile )
1411 if ((hFile >= DOS_TABLE_SIZE) || !dos_handles[hFile])
1413 SetLastError( ERROR_INVALID_HANDLE );
1414 return HFILE_ERROR16;
1416 TRACE("%d (handle32=%p)\n", hFile, dos_handles[hFile] );
1417 CloseHandle( dos_handles[hFile] );
1418 dos_handles[hFile] = 0;
1419 return 0;
1423 /******************************************************************
1424 * FILE_ReadWriteApc (internal)
1428 static void WINAPI FILE_ReadWriteApc(void* apc_user, PIO_STATUS_BLOCK io_status, ULONG len)
1430 LPOVERLAPPED_COMPLETION_ROUTINE cr = (LPOVERLAPPED_COMPLETION_ROUTINE)apc_user;
1432 cr(RtlNtStatusToDosError(io_status->u.Status), len, (LPOVERLAPPED)io_status);
1435 /***********************************************************************
1436 * ReadFileEx (KERNEL32.@)
1438 BOOL WINAPI ReadFileEx(HANDLE hFile, LPVOID buffer, DWORD bytesToRead,
1439 LPOVERLAPPED overlapped,
1440 LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine)
1442 LARGE_INTEGER offset;
1443 NTSTATUS status;
1444 PIO_STATUS_BLOCK io_status;
1446 if (!overlapped)
1448 SetLastError(ERROR_INVALID_PARAMETER);
1449 return FALSE;
1452 offset.s.LowPart = overlapped->Offset;
1453 offset.s.HighPart = overlapped->OffsetHigh;
1454 io_status = (PIO_STATUS_BLOCK)overlapped;
1455 io_status->u.Status = STATUS_PENDING;
1457 status = NtReadFile(hFile, NULL, FILE_ReadWriteApc, lpCompletionRoutine,
1458 io_status, buffer, bytesToRead, &offset, NULL);
1460 if (status)
1462 SetLastError( RtlNtStatusToDosError(status) );
1463 return FALSE;
1465 return TRUE;
1468 /***********************************************************************
1469 * ReadFile (KERNEL32.@)
1471 BOOL WINAPI ReadFile( HANDLE hFile, LPVOID buffer, DWORD bytesToRead,
1472 LPDWORD bytesRead, LPOVERLAPPED overlapped )
1474 LARGE_INTEGER offset;
1475 PLARGE_INTEGER poffset = NULL;
1476 IO_STATUS_BLOCK iosb;
1477 PIO_STATUS_BLOCK io_status = &iosb;
1478 HANDLE hEvent = 0;
1479 NTSTATUS status;
1481 TRACE("%p %p %ld %p %p\n", hFile, buffer, bytesToRead,
1482 bytesRead, overlapped );
1484 if (bytesRead) *bytesRead = 0; /* Do this before anything else */
1485 if (!bytesToRead) return TRUE;
1487 if (IsBadReadPtr(buffer, bytesToRead))
1489 SetLastError(ERROR_WRITE_FAULT); /* FIXME */
1490 return FALSE;
1492 if (is_console_handle(hFile))
1493 return ReadConsoleA(hFile, buffer, bytesToRead, bytesRead, NULL);
1495 if (overlapped != NULL)
1497 offset.s.LowPart = overlapped->Offset;
1498 offset.s.HighPart = overlapped->OffsetHigh;
1499 poffset = &offset;
1500 hEvent = overlapped->hEvent;
1501 io_status = (PIO_STATUS_BLOCK)overlapped;
1503 io_status->u.Status = STATUS_PENDING;
1504 io_status->Information = 0;
1506 status = NtReadFile(hFile, hEvent, NULL, NULL, io_status, buffer, bytesToRead, poffset, NULL);
1508 if (status != STATUS_PENDING && bytesRead)
1509 *bytesRead = io_status->Information;
1511 if (status && status != STATUS_END_OF_FILE)
1513 SetLastError( RtlNtStatusToDosError(status) );
1514 return FALSE;
1516 return TRUE;
1520 /***********************************************************************
1521 * WriteFileEx (KERNEL32.@)
1523 BOOL WINAPI WriteFileEx(HANDLE hFile, LPCVOID buffer, DWORD bytesToWrite,
1524 LPOVERLAPPED overlapped,
1525 LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine)
1527 LARGE_INTEGER offset;
1528 NTSTATUS status;
1529 PIO_STATUS_BLOCK io_status;
1531 TRACE("%p %p %ld %p %p\n",
1532 hFile, buffer, bytesToWrite, overlapped, lpCompletionRoutine);
1534 if (overlapped == NULL)
1536 SetLastError(ERROR_INVALID_PARAMETER);
1537 return FALSE;
1539 offset.s.LowPart = overlapped->Offset;
1540 offset.s.HighPart = overlapped->OffsetHigh;
1542 io_status = (PIO_STATUS_BLOCK)overlapped;
1543 io_status->u.Status = STATUS_PENDING;
1545 status = NtWriteFile(hFile, NULL, FILE_ReadWriteApc, lpCompletionRoutine,
1546 io_status, buffer, bytesToWrite, &offset, NULL);
1548 if (status) SetLastError( RtlNtStatusToDosError(status) );
1549 return !status;
1552 /***********************************************************************
1553 * WriteFile (KERNEL32.@)
1555 BOOL WINAPI WriteFile( HANDLE hFile, LPCVOID buffer, DWORD bytesToWrite,
1556 LPDWORD bytesWritten, LPOVERLAPPED overlapped )
1558 HANDLE hEvent = NULL;
1559 LARGE_INTEGER offset;
1560 PLARGE_INTEGER poffset = NULL;
1561 NTSTATUS status;
1562 IO_STATUS_BLOCK iosb;
1563 PIO_STATUS_BLOCK piosb = &iosb;
1565 TRACE("%p %p %ld %p %p\n",
1566 hFile, buffer, bytesToWrite, bytesWritten, overlapped );
1568 if (is_console_handle(hFile))
1569 return WriteConsoleA(hFile, buffer, bytesToWrite, bytesWritten, NULL);
1571 if (IsBadReadPtr(buffer, bytesToWrite))
1573 SetLastError(ERROR_READ_FAULT); /* FIXME */
1574 return FALSE;
1577 if (overlapped)
1579 offset.s.LowPart = overlapped->Offset;
1580 offset.s.HighPart = overlapped->OffsetHigh;
1581 poffset = &offset;
1582 hEvent = overlapped->hEvent;
1583 piosb = (PIO_STATUS_BLOCK)overlapped;
1585 piosb->u.Status = STATUS_PENDING;
1586 piosb->Information = 0;
1588 status = NtWriteFile(hFile, hEvent, NULL, NULL, piosb,
1589 buffer, bytesToWrite, poffset, NULL);
1590 if (status)
1592 SetLastError( RtlNtStatusToDosError(status) );
1593 return FALSE;
1595 if (bytesWritten) *bytesWritten = piosb->Information;
1597 return TRUE;
1601 /***********************************************************************
1602 * SetFilePointer (KERNEL32.@)
1604 DWORD WINAPI SetFilePointer( HANDLE hFile, LONG distance, LONG *highword,
1605 DWORD method )
1607 DWORD ret = INVALID_SET_FILE_POINTER;
1609 TRACE("handle %p offset %ld high %ld origin %ld\n",
1610 hFile, distance, highword?*highword:0, method );
1612 SERVER_START_REQ( set_file_pointer )
1614 req->handle = hFile;
1615 req->low = distance;
1616 req->high = highword ? *highword : (distance >= 0) ? 0 : -1;
1617 /* FIXME: assumes 1:1 mapping between Windows and Unix seek constants */
1618 req->whence = method;
1619 SetLastError( 0 );
1620 if (!wine_server_call_err( req ))
1622 ret = reply->new_low;
1623 if (highword) *highword = reply->new_high;
1626 SERVER_END_REQ;
1627 return ret;
1631 /*************************************************************************
1632 * SetHandleCount (KERNEL32.@)
1634 UINT WINAPI SetHandleCount( UINT count )
1636 return min( 256, count );
1640 /**************************************************************************
1641 * SetEndOfFile (KERNEL32.@)
1643 BOOL WINAPI SetEndOfFile( HANDLE hFile )
1645 BOOL ret;
1646 SERVER_START_REQ( truncate_file )
1648 req->handle = hFile;
1649 ret = !wine_server_call_err( req );
1651 SERVER_END_REQ;
1652 return ret;
1656 /***********************************************************************
1657 * DeleteFileW (KERNEL32.@)
1659 BOOL WINAPI DeleteFileW( LPCWSTR path )
1661 DOS_FULL_NAME full_name;
1662 HANDLE hFile;
1664 TRACE("%s\n", debugstr_w(path) );
1665 if (!path || !*path)
1667 SetLastError(ERROR_PATH_NOT_FOUND);
1668 return FALSE;
1670 if (DOSFS_GetDevice( path ))
1672 WARN("cannot remove DOS device %s!\n", debugstr_w(path));
1673 SetLastError( ERROR_FILE_NOT_FOUND );
1674 return FALSE;
1677 if (!DOSFS_GetFullName( path, TRUE, &full_name )) return FALSE;
1679 /* check if we are allowed to delete the source */
1680 hFile = FILE_CreateFile( full_name.long_name, GENERIC_READ|GENERIC_WRITE, 0,
1681 NULL, OPEN_EXISTING, 0, 0, TRUE,
1682 GetDriveTypeW( full_name.short_name ) );
1683 if (!hFile) return FALSE;
1685 if (unlink( full_name.long_name ) == -1)
1687 FILE_SetDosError();
1688 CloseHandle(hFile);
1689 return FALSE;
1691 CloseHandle(hFile);
1692 return TRUE;
1696 /***********************************************************************
1697 * DeleteFileA (KERNEL32.@)
1699 BOOL WINAPI DeleteFileA( LPCSTR path )
1701 UNICODE_STRING pathW;
1702 BOOL ret = FALSE;
1704 if (!path)
1706 SetLastError(ERROR_INVALID_PARAMETER);
1707 return FALSE;
1710 if (RtlCreateUnicodeStringFromAsciiz(&pathW, path))
1712 ret = DeleteFileW(pathW.Buffer);
1713 RtlFreeUnicodeString(&pathW);
1715 else
1716 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1717 return ret;
1721 /***********************************************************************
1722 * GetFileType (KERNEL32.@)
1724 DWORD WINAPI GetFileType( HANDLE hFile )
1726 DWORD ret = FILE_TYPE_UNKNOWN;
1728 if (is_console_handle( hFile ))
1729 return FILE_TYPE_CHAR;
1731 SERVER_START_REQ( get_file_info )
1733 req->handle = hFile;
1734 if (!wine_server_call_err( req )) ret = reply->type;
1736 SERVER_END_REQ;
1737 return ret;
1741 /* check if a file name is for an executable file (.exe or .com) */
1742 inline static BOOL is_executable( const char *name )
1744 int len = strlen(name);
1746 if (len < 4) return FALSE;
1747 return (!strcasecmp( name + len - 4, ".exe" ) ||
1748 !strcasecmp( name + len - 4, ".com" ));
1752 /***********************************************************************
1753 * FILE_AddBootRenameEntry
1755 * Adds an entry to the registry that is loaded when windows boots and
1756 * checks if there are some files to be removed or renamed/moved.
1757 * <fn1> has to be valid and <fn2> may be NULL. If both pointers are
1758 * non-NULL then the file is moved, otherwise it is deleted. The
1759 * entry of the registrykey is always appended with two zero
1760 * terminated strings. If <fn2> is NULL then the second entry is
1761 * simply a single 0-byte. Otherwise the second filename goes
1762 * there. The entries are prepended with \??\ before the path and the
1763 * second filename gets also a '!' as the first character if
1764 * MOVEFILE_REPLACE_EXISTING is set. After the final string another
1765 * 0-byte follows to indicate the end of the strings.
1766 * i.e.:
1767 * \??\D:\test\file1[0]
1768 * !\??\D:\test\file1_renamed[0]
1769 * \??\D:\Test|delete[0]
1770 * [0] <- file is to be deleted, second string empty
1771 * \??\D:\test\file2[0]
1772 * !\??\D:\test\file2_renamed[0]
1773 * [0] <- indicates end of strings
1775 * or:
1776 * \??\D:\test\file1[0]
1777 * !\??\D:\test\file1_renamed[0]
1778 * \??\D:\Test|delete[0]
1779 * [0] <- file is to be deleted, second string empty
1780 * [0] <- indicates end of strings
1783 static BOOL FILE_AddBootRenameEntry( LPCWSTR fn1, LPCWSTR fn2, DWORD flags )
1785 static const WCHAR PreString[] = {'\\','?','?','\\',0};
1786 static const WCHAR ValueName[] = {'P','e','n','d','i','n','g',
1787 'F','i','l','e','R','e','n','a','m','e',
1788 'O','p','e','r','a','t','i','o','n','s',0};
1789 static const WCHAR SessionW[] = {'M','a','c','h','i','n','e','\\',
1790 'S','y','s','t','e','m','\\',
1791 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
1792 'C','o','n','t','r','o','l','\\',
1793 'S','e','s','s','i','o','n',' ','M','a','n','a','g','e','r',0};
1794 static const int info_size = FIELD_OFFSET( KEY_VALUE_PARTIAL_INFORMATION, Data );
1796 OBJECT_ATTRIBUTES attr;
1797 UNICODE_STRING nameW;
1798 KEY_VALUE_PARTIAL_INFORMATION *info;
1799 BOOL rc = FALSE;
1800 HKEY Reboot = 0;
1801 DWORD len0, len1, len2;
1802 DWORD DataSize = 0;
1803 BYTE *Buffer = NULL;
1804 WCHAR *p;
1806 attr.Length = sizeof(attr);
1807 attr.RootDirectory = 0;
1808 attr.ObjectName = &nameW;
1809 attr.Attributes = 0;
1810 attr.SecurityDescriptor = NULL;
1811 attr.SecurityQualityOfService = NULL;
1812 RtlInitUnicodeString( &nameW, SessionW );
1814 if (NtCreateKey( &Reboot, KEY_ALL_ACCESS, &attr, 0, NULL, 0, NULL ) != STATUS_SUCCESS)
1816 WARN("Error creating key for reboot managment [%s]\n",
1817 "SYSTEM\\CurrentControlSet\\Control\\Session Manager");
1818 return FALSE;
1821 len0 = strlenW(PreString);
1822 len1 = strlenW(fn1) + len0 + 1;
1823 if (fn2)
1825 len2 = strlenW(fn2) + len0 + 1;
1826 if (flags & MOVEFILE_REPLACE_EXISTING) len2++; /* Plus 1 because of the leading '!' */
1828 else len2 = 1; /* minimum is the 0 characters for the empty second string */
1830 /* convert characters to bytes */
1831 len0 *= sizeof(WCHAR);
1832 len1 *= sizeof(WCHAR);
1833 len2 *= sizeof(WCHAR);
1835 RtlInitUnicodeString( &nameW, ValueName );
1837 /* First we check if the key exists and if so how many bytes it already contains. */
1838 if (NtQueryValueKey( Reboot, &nameW, KeyValuePartialInformation,
1839 NULL, 0, &DataSize ) == STATUS_BUFFER_OVERFLOW)
1841 if (!(Buffer = HeapAlloc( GetProcessHeap(), 0, DataSize + len1 + len2 + sizeof(WCHAR) )))
1842 goto Quit;
1843 if (NtQueryValueKey( Reboot, &nameW, KeyValuePartialInformation,
1844 Buffer, DataSize, &DataSize )) goto Quit;
1845 info = (KEY_VALUE_PARTIAL_INFORMATION *)Buffer;
1846 if (info->Type != REG_MULTI_SZ) goto Quit;
1847 if (DataSize > sizeof(info)) DataSize -= sizeof(WCHAR); /* remove terminating null (will be added back later) */
1849 else
1851 DataSize = info_size;
1852 if (!(Buffer = HeapAlloc( GetProcessHeap(), 0, DataSize + len1 + len2 + sizeof(WCHAR) )))
1853 goto Quit;
1856 p = (WCHAR *)(Buffer + DataSize);
1857 strcpyW( p, PreString );
1858 strcatW( p, fn1 );
1859 DataSize += len1;
1860 if (fn2)
1862 p = (WCHAR *)(Buffer + DataSize);
1863 if (flags & MOVEFILE_REPLACE_EXISTING)
1864 *p++ = '!';
1865 strcpyW( p, PreString );
1866 strcatW( p, fn2 );
1867 DataSize += len2;
1869 else
1871 p = (WCHAR *)(Buffer + DataSize);
1872 *p = 0;
1873 DataSize += sizeof(WCHAR);
1876 /* add final null */
1877 p = (WCHAR *)(Buffer + DataSize);
1878 *p = 0;
1879 DataSize += sizeof(WCHAR);
1881 rc = !NtSetValueKey(Reboot, &nameW, 0, REG_MULTI_SZ, Buffer + info_size, DataSize - info_size);
1883 Quit:
1884 if (Reboot) NtClose(Reboot);
1885 if (Buffer) HeapFree( GetProcessHeap(), 0, Buffer );
1886 return(rc);
1890 /**************************************************************************
1891 * MoveFileExW (KERNEL32.@)
1893 BOOL WINAPI MoveFileExW( LPCWSTR fn1, LPCWSTR fn2, DWORD flag )
1895 DOS_FULL_NAME full_name1, full_name2;
1896 HANDLE hFile;
1897 DWORD attr = INVALID_FILE_ATTRIBUTES;
1899 TRACE("(%s,%s,%04lx)\n", debugstr_w(fn1), debugstr_w(fn2), flag);
1901 /* FIXME: <Gerhard W. Gruber>sparhawk@gmx.at
1902 In case of W9x and lesser this function should return 120 (ERROR_CALL_NOT_IMPLEMENTED)
1903 to be really compatible. Most programs wont have any problems though. In case
1904 you encounter one, this is what you should return here. I don't know what's up
1905 with NT 3.5. Is this function available there or not?
1906 Does anybody really care about 3.5? :)
1909 /* Filename1 has to be always set to a valid path. Filename2 may be NULL
1910 if the source file has to be deleted.
1912 if (!fn1) {
1913 SetLastError(ERROR_INVALID_PARAMETER);
1914 return FALSE;
1917 /* This function has to be run through in order to process the name properly.
1918 If the BOOTDELAY flag is set, the file doesn't need to exist though. At least
1919 that is the behaviour on NT 4.0. The operation accepts the filenames as
1920 they are given but it can't reply with a reasonable returncode. Success
1921 means in that case success for entering the values into the registry.
1923 if(!DOSFS_GetFullName( fn1, TRUE, &full_name1 ))
1925 if(!(flag & MOVEFILE_DELAY_UNTIL_REBOOT))
1926 return FALSE;
1929 if (fn2) /* !fn2 means delete fn1 */
1931 if (DOSFS_GetFullName( fn2, TRUE, &full_name2 ))
1933 if(!(flag & MOVEFILE_DELAY_UNTIL_REBOOT))
1935 /* target exists, check if we may overwrite */
1936 if (!(flag & MOVEFILE_REPLACE_EXISTING))
1938 SetLastError( ERROR_FILE_EXISTS );
1939 return FALSE;
1943 else
1945 if (!DOSFS_GetFullName( fn2, FALSE, &full_name2 ))
1947 if(!(flag & MOVEFILE_DELAY_UNTIL_REBOOT))
1948 return FALSE;
1952 /* Source name and target path are valid */
1954 if (flag & MOVEFILE_DELAY_UNTIL_REBOOT)
1956 return FILE_AddBootRenameEntry( fn1, fn2, flag );
1959 attr = GetFileAttributesW( fn1 );
1960 if ( attr == INVALID_FILE_ATTRIBUTES ) return FALSE;
1962 /* check if we are allowed to rename the source */
1963 hFile = FILE_CreateFile( full_name1.long_name, 0, 0,
1964 NULL, OPEN_EXISTING, 0, 0, TRUE,
1965 GetDriveTypeW( full_name1.short_name ) );
1966 if (!hFile)
1968 if (GetLastError() != ERROR_ACCESS_DENIED) return FALSE;
1969 if ( !(attr & FILE_ATTRIBUTE_DIRECTORY) ) return FALSE;
1970 /* if it's a directory we can continue */
1972 else CloseHandle(hFile);
1974 /* check, if we are allowed to delete the destination,
1975 ** (but the file not being there is fine) */
1976 hFile = FILE_CreateFile( full_name2.long_name, GENERIC_READ|GENERIC_WRITE, 0,
1977 NULL, OPEN_EXISTING, 0, 0, TRUE,
1978 GetDriveTypeW( full_name2.short_name ) );
1979 if(!hFile && GetLastError() != ERROR_FILE_NOT_FOUND) return FALSE;
1980 CloseHandle(hFile);
1982 if (full_name1.drive != full_name2.drive)
1984 if (!(flag & MOVEFILE_COPY_ALLOWED))
1986 SetLastError( ERROR_NOT_SAME_DEVICE );
1987 return FALSE;
1989 else if ( attr & FILE_ATTRIBUTE_DIRECTORY )
1991 /* Strange, but that's what Windows returns */
1992 SetLastError ( ERROR_ACCESS_DENIED );
1993 return FALSE;
1996 if (rename( full_name1.long_name, full_name2.long_name ) == -1)
1997 /* Try copy/delete unless it's a directory. */
1998 /* FIXME: This does not handle the (unlikely) case that the two locations
1999 are on the same Wine drive, but on different Unix file systems. */
2001 if ( attr & FILE_ATTRIBUTE_DIRECTORY )
2003 FILE_SetDosError();
2004 return FALSE;
2006 else
2008 if ( ! CopyFileW( fn1, fn2, !(flag & MOVEFILE_REPLACE_EXISTING) ))
2009 return FALSE;
2010 if ( ! DeleteFileW ( fn1 ) )
2011 return FALSE;
2014 if (is_executable( full_name1.long_name ) != is_executable( full_name2.long_name ))
2016 struct stat fstat;
2017 if (stat( full_name2.long_name, &fstat ) != -1)
2019 if (is_executable( full_name2.long_name ))
2020 /* set executable bit where read bit is set */
2021 fstat.st_mode |= (fstat.st_mode & 0444) >> 2;
2022 else
2023 fstat.st_mode &= ~0111;
2024 chmod( full_name2.long_name, fstat.st_mode );
2027 return TRUE;
2029 else /* fn2 == NULL means delete source */
2031 if (flag & MOVEFILE_DELAY_UNTIL_REBOOT)
2033 if (flag & MOVEFILE_COPY_ALLOWED) {
2034 WARN("Illegal flag\n");
2035 SetLastError( ERROR_GEN_FAILURE );
2036 return FALSE;
2039 return FILE_AddBootRenameEntry( fn1, NULL, flag );
2042 if (unlink( full_name1.long_name ) == -1)
2044 FILE_SetDosError();
2045 return FALSE;
2047 return TRUE; /* successfully deleted */
2051 /**************************************************************************
2052 * MoveFileExA (KERNEL32.@)
2054 BOOL WINAPI MoveFileExA( LPCSTR fn1, LPCSTR fn2, DWORD flag )
2056 UNICODE_STRING fn1W, fn2W;
2057 BOOL ret;
2059 if (!fn1)
2061 SetLastError(ERROR_INVALID_PARAMETER);
2062 return FALSE;
2065 RtlCreateUnicodeStringFromAsciiz(&fn1W, fn1);
2066 if (fn2) RtlCreateUnicodeStringFromAsciiz(&fn2W, fn2);
2067 else fn2W.Buffer = NULL;
2069 ret = MoveFileExW( fn1W.Buffer, fn2W.Buffer, flag );
2071 RtlFreeUnicodeString(&fn1W);
2072 RtlFreeUnicodeString(&fn2W);
2073 return ret;
2077 /**************************************************************************
2078 * MoveFileW (KERNEL32.@)
2080 * Move file or directory
2082 BOOL WINAPI MoveFileW( LPCWSTR fn1, LPCWSTR fn2 )
2084 return MoveFileExW( fn1, fn2, MOVEFILE_COPY_ALLOWED );
2088 /**************************************************************************
2089 * MoveFileA (KERNEL32.@)
2091 BOOL WINAPI MoveFileA( LPCSTR fn1, LPCSTR fn2 )
2093 return MoveFileExA( fn1, fn2, MOVEFILE_COPY_ALLOWED );
2097 /**************************************************************************
2098 * CopyFileW (KERNEL32.@)
2100 BOOL WINAPI CopyFileW( LPCWSTR source, LPCWSTR dest, BOOL fail_if_exists )
2102 HANDLE h1, h2;
2103 BY_HANDLE_FILE_INFORMATION info;
2104 DWORD count;
2105 BOOL ret = FALSE;
2106 char buffer[2048];
2108 if (!source || !dest)
2110 SetLastError(ERROR_INVALID_PARAMETER);
2111 return FALSE;
2114 TRACE("%s -> %s\n", debugstr_w(source), debugstr_w(dest));
2116 if ((h1 = CreateFileW(source, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE,
2117 NULL, OPEN_EXISTING, 0, 0)) == INVALID_HANDLE_VALUE)
2119 WARN("Unable to open source %s\n", debugstr_w(source));
2120 return FALSE;
2123 if (!GetFileInformationByHandle( h1, &info ))
2125 WARN("GetFileInformationByHandle returned error for %s\n", debugstr_w(source));
2126 CloseHandle( h1 );
2127 return FALSE;
2130 if ((h2 = CreateFileW( dest, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
2131 fail_if_exists ? CREATE_NEW : CREATE_ALWAYS,
2132 info.dwFileAttributes, h1 )) == INVALID_HANDLE_VALUE)
2134 WARN("Unable to open dest %s\n", debugstr_w(dest));
2135 CloseHandle( h1 );
2136 return FALSE;
2139 while (ReadFile( h1, buffer, sizeof(buffer), &count, NULL ) && count)
2141 char *p = buffer;
2142 while (count != 0)
2144 DWORD res;
2145 if (!WriteFile( h2, p, count, &res, NULL ) || !res) goto done;
2146 p += res;
2147 count -= res;
2150 ret = TRUE;
2151 done:
2152 CloseHandle( h1 );
2153 CloseHandle( h2 );
2154 return ret;
2158 /**************************************************************************
2159 * CopyFileA (KERNEL32.@)
2161 BOOL WINAPI CopyFileA( LPCSTR source, LPCSTR dest, BOOL fail_if_exists)
2163 UNICODE_STRING sourceW, destW;
2164 BOOL ret;
2166 if (!source || !dest)
2168 SetLastError(ERROR_INVALID_PARAMETER);
2169 return FALSE;
2172 RtlCreateUnicodeStringFromAsciiz(&sourceW, source);
2173 RtlCreateUnicodeStringFromAsciiz(&destW, dest);
2175 ret = CopyFileW(sourceW.Buffer, destW.Buffer, fail_if_exists);
2177 RtlFreeUnicodeString(&sourceW);
2178 RtlFreeUnicodeString(&destW);
2179 return ret;
2183 /**************************************************************************
2184 * CopyFileExW (KERNEL32.@)
2186 * This implementation ignores most of the extra parameters passed-in into
2187 * the "ex" version of the method and calls the CopyFile method.
2188 * It will have to be fixed eventually.
2190 BOOL WINAPI CopyFileExW(LPCWSTR sourceFilename, LPCWSTR destFilename,
2191 LPPROGRESS_ROUTINE progressRoutine, LPVOID appData,
2192 LPBOOL cancelFlagPointer, DWORD copyFlags)
2195 * Interpret the only flag that CopyFile can interpret.
2197 return CopyFileW(sourceFilename, destFilename, (copyFlags & COPY_FILE_FAIL_IF_EXISTS) != 0);
2201 /**************************************************************************
2202 * CopyFileExA (KERNEL32.@)
2204 BOOL WINAPI CopyFileExA(LPCSTR sourceFilename, LPCSTR destFilename,
2205 LPPROGRESS_ROUTINE progressRoutine, LPVOID appData,
2206 LPBOOL cancelFlagPointer, DWORD copyFlags)
2208 UNICODE_STRING sourceW, destW;
2209 BOOL ret;
2211 if (!sourceFilename || !destFilename)
2213 SetLastError(ERROR_INVALID_PARAMETER);
2214 return FALSE;
2217 RtlCreateUnicodeStringFromAsciiz(&sourceW, sourceFilename);
2218 RtlCreateUnicodeStringFromAsciiz(&destW, destFilename);
2220 ret = CopyFileExW(sourceW.Buffer, destW.Buffer, progressRoutine, appData,
2221 cancelFlagPointer, copyFlags);
2223 RtlFreeUnicodeString(&sourceW);
2224 RtlFreeUnicodeString(&destW);
2225 return ret;
2229 /***********************************************************************
2230 * SetFileTime (KERNEL32.@)
2232 BOOL WINAPI SetFileTime( HANDLE hFile,
2233 const FILETIME *lpCreationTime,
2234 const FILETIME *lpLastAccessTime,
2235 const FILETIME *lpLastWriteTime )
2237 BOOL ret;
2238 SERVER_START_REQ( set_file_time )
2240 req->handle = hFile;
2241 if (lpLastAccessTime)
2242 RtlTimeToSecondsSince1970( (PLARGE_INTEGER) lpLastAccessTime, (DWORD *)&req->access_time );
2243 else
2244 req->access_time = 0; /* FIXME */
2245 if (lpLastWriteTime)
2246 RtlTimeToSecondsSince1970( (PLARGE_INTEGER) lpLastWriteTime, (DWORD *)&req->write_time );
2247 else
2248 req->write_time = 0; /* FIXME */
2249 ret = !wine_server_call_err( req );
2251 SERVER_END_REQ;
2252 return ret;
2256 /**************************************************************************
2257 * GetFileAttributesExW (KERNEL32.@)
2259 BOOL WINAPI GetFileAttributesExW(
2260 LPCWSTR lpFileName, GET_FILEEX_INFO_LEVELS fInfoLevelId,
2261 LPVOID lpFileInformation)
2263 DOS_FULL_NAME full_name;
2264 BY_HANDLE_FILE_INFORMATION info;
2266 if (!lpFileName || !lpFileInformation)
2268 SetLastError(ERROR_INVALID_PARAMETER);
2269 return FALSE;
2272 if (fInfoLevelId == GetFileExInfoStandard) {
2273 LPWIN32_FILE_ATTRIBUTE_DATA lpFad =
2274 (LPWIN32_FILE_ATTRIBUTE_DATA) lpFileInformation;
2275 if (!DOSFS_GetFullName( lpFileName, TRUE, &full_name )) return FALSE;
2276 if (!FILE_Stat( full_name.long_name, &info, NULL )) return FALSE;
2278 lpFad->dwFileAttributes = info.dwFileAttributes;
2279 lpFad->ftCreationTime = info.ftCreationTime;
2280 lpFad->ftLastAccessTime = info.ftLastAccessTime;
2281 lpFad->ftLastWriteTime = info.ftLastWriteTime;
2282 lpFad->nFileSizeHigh = info.nFileSizeHigh;
2283 lpFad->nFileSizeLow = info.nFileSizeLow;
2285 else {
2286 FIXME("invalid info level %d!\n", fInfoLevelId);
2287 return FALSE;
2290 return TRUE;
2294 /**************************************************************************
2295 * GetFileAttributesExA (KERNEL32.@)
2297 BOOL WINAPI GetFileAttributesExA(
2298 LPCSTR filename, GET_FILEEX_INFO_LEVELS fInfoLevelId,
2299 LPVOID lpFileInformation)
2301 UNICODE_STRING filenameW;
2302 BOOL ret = FALSE;
2304 if (!filename || !lpFileInformation)
2306 SetLastError(ERROR_INVALID_PARAMETER);
2307 return FALSE;
2310 if (RtlCreateUnicodeStringFromAsciiz(&filenameW, filename))
2312 ret = GetFileAttributesExW(filenameW.Buffer, fInfoLevelId, lpFileInformation);
2313 RtlFreeUnicodeString(&filenameW);
2315 else
2316 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
2317 return ret;