Split OpenFile implementation in separate 16- and 32-bit versions, and
[wine/multimedia.git] / files / file.c
blobb293d67a846555f687a845a03cd9a12866a1719f
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 "file.h"
71 #include "wincon.h"
72 #include "kernel_private.h"
74 #include "smb.h"
75 #include "wine/unicode.h"
76 #include "wine/debug.h"
78 WINE_DEFAULT_DEBUG_CHANNEL(file);
80 #if defined(MAP_ANONYMOUS) && !defined(MAP_ANON)
81 #define MAP_ANON MAP_ANONYMOUS
82 #endif
84 #define IS_OPTION_TRUE(ch) ((ch) == 'y' || (ch) == 'Y' || (ch) == 't' || (ch) == 'T' || (ch) == '1')
86 mode_t FILE_umask;
88 /***********************************************************************
89 * FILE_ConvertOFMode
91 * Convert OF_* mode into flags for CreateFile.
93 void FILE_ConvertOFMode( INT mode, DWORD *access, DWORD *sharing )
95 switch(mode & 0x03)
97 case OF_READ: *access = GENERIC_READ; break;
98 case OF_WRITE: *access = GENERIC_WRITE; break;
99 case OF_READWRITE: *access = GENERIC_READ | GENERIC_WRITE; break;
100 default: *access = 0; break;
102 switch(mode & 0x70)
104 case OF_SHARE_EXCLUSIVE: *sharing = 0; break;
105 case OF_SHARE_DENY_WRITE: *sharing = FILE_SHARE_READ; break;
106 case OF_SHARE_DENY_READ: *sharing = FILE_SHARE_WRITE; break;
107 case OF_SHARE_DENY_NONE:
108 case OF_SHARE_COMPAT:
109 default: *sharing = FILE_SHARE_READ | FILE_SHARE_WRITE; break;
114 /***********************************************************************
115 * FILE_SetDosError
117 * Set the DOS error code from errno.
119 void FILE_SetDosError(void)
121 int save_errno = errno; /* errno gets overwritten by printf */
123 TRACE("errno = %d %s\n", errno, strerror(errno));
124 switch (save_errno)
126 case EAGAIN:
127 SetLastError( ERROR_SHARING_VIOLATION );
128 break;
129 case EBADF:
130 SetLastError( ERROR_INVALID_HANDLE );
131 break;
132 case ENOSPC:
133 SetLastError( ERROR_HANDLE_DISK_FULL );
134 break;
135 case EACCES:
136 case EPERM:
137 case EROFS:
138 SetLastError( ERROR_ACCESS_DENIED );
139 break;
140 case EBUSY:
141 SetLastError( ERROR_LOCK_VIOLATION );
142 break;
143 case ENOENT:
144 SetLastError( ERROR_FILE_NOT_FOUND );
145 break;
146 case EISDIR:
147 SetLastError( ERROR_CANNOT_MAKE );
148 break;
149 case ENFILE:
150 case EMFILE:
151 SetLastError( ERROR_NO_MORE_FILES );
152 break;
153 case EEXIST:
154 SetLastError( ERROR_FILE_EXISTS );
155 break;
156 case EINVAL:
157 case ESPIPE:
158 SetLastError( ERROR_SEEK );
159 break;
160 case ENOTEMPTY:
161 SetLastError( ERROR_DIR_NOT_EMPTY );
162 break;
163 case ENOEXEC:
164 SetLastError( ERROR_BAD_FORMAT );
165 break;
166 default:
167 WARN("unknown file error: %s\n", strerror(save_errno) );
168 SetLastError( ERROR_GEN_FAILURE );
169 break;
171 errno = save_errno;
175 /***********************************************************************
176 * FILE_CreateFile
178 * Implementation of CreateFile. Takes a Unix path name.
179 * Returns 0 on failure.
181 HANDLE FILE_CreateFile( LPCSTR filename, DWORD access, DWORD sharing,
182 LPSECURITY_ATTRIBUTES sa, DWORD creation,
183 DWORD attributes, HANDLE template, BOOL fail_read_only,
184 UINT drive_type )
186 unsigned int err;
187 UINT disp, options;
188 HANDLE ret;
190 switch (creation)
192 case CREATE_ALWAYS: disp = FILE_OVERWRITE_IF; break;
193 case CREATE_NEW: disp = FILE_CREATE; break;
194 case OPEN_ALWAYS: disp = FILE_OPEN_IF; break;
195 case OPEN_EXISTING: disp = FILE_OPEN; break;
196 case TRUNCATE_EXISTING: disp = FILE_OVERWRITE; break;
197 default:
198 SetLastError( ERROR_INVALID_PARAMETER );
199 return 0;
202 options = 0;
203 if (attributes & FILE_FLAG_BACKUP_SEMANTICS)
204 options |= FILE_OPEN_FOR_BACKUP_INTENT;
205 if (attributes & FILE_FLAG_DELETE_ON_CLOSE)
206 options |= FILE_DELETE_ON_CLOSE;
207 if (!(attributes & FILE_FLAG_OVERLAPPED))
208 options |= FILE_SYNCHRONOUS_IO_ALERT;
209 if (attributes & FILE_FLAG_RANDOM_ACCESS)
210 options |= FILE_RANDOM_ACCESS;
211 attributes &= FILE_ATTRIBUTE_VALID_FLAGS;
213 for (;;)
215 SERVER_START_REQ( create_file )
217 req->access = access;
218 req->inherit = (sa && (sa->nLength>=sizeof(*sa)) && sa->bInheritHandle);
219 req->sharing = sharing;
220 req->create = disp;
221 req->options = options;
222 req->attrs = attributes;
223 req->removable = (drive_type == DRIVE_REMOVABLE || drive_type == DRIVE_CDROM);
224 wine_server_add_data( req, filename, strlen(filename) );
225 SetLastError(0);
226 err = wine_server_call( req );
227 ret = reply->handle;
229 SERVER_END_REQ;
231 /* If write access failed, retry without GENERIC_WRITE */
233 if (!ret && !fail_read_only && (access & GENERIC_WRITE))
235 if ((err == STATUS_MEDIA_WRITE_PROTECTED) || (err == STATUS_ACCESS_DENIED))
237 TRACE("Write access failed for file '%s', trying without "
238 "write access\n", filename);
239 access &= ~GENERIC_WRITE;
240 continue;
244 if (err)
246 /* In the case file creation was rejected due to CREATE_NEW flag
247 * was specified and file with that name already exists, correct
248 * last error is ERROR_FILE_EXISTS and not ERROR_ALREADY_EXISTS.
249 * Note: RtlNtStatusToDosError is not the subject to blame here.
251 if (err == STATUS_OBJECT_NAME_COLLISION)
252 SetLastError( ERROR_FILE_EXISTS );
253 else
254 SetLastError( RtlNtStatusToDosError(err) );
257 if (!ret) WARN("Unable to create file '%s' (GLE %ld)\n", filename, GetLastError());
258 return ret;
263 static HANDLE FILE_OpenPipe(LPCWSTR name, DWORD access, LPSECURITY_ATTRIBUTES sa )
265 HANDLE ret;
266 DWORD len = 0;
268 if (name && (len = strlenW(name)) > MAX_PATH)
270 SetLastError( ERROR_FILENAME_EXCED_RANGE );
271 return 0;
273 SERVER_START_REQ( open_named_pipe )
275 req->access = access;
276 req->inherit = (sa && (sa->nLength>=sizeof(*sa)) && sa->bInheritHandle);
277 SetLastError(0);
278 wine_server_add_data( req, name, len * sizeof(WCHAR) );
279 wine_server_call_err( req );
280 ret = reply->handle;
282 SERVER_END_REQ;
283 TRACE("Returned %p\n",ret);
284 return ret;
287 /*************************************************************************
288 * CreateFileW [KERNEL32.@] Creates or opens a file or other object
290 * Creates or opens an object, and returns a handle that can be used to
291 * access that object.
293 * PARAMS
295 * filename [in] pointer to filename to be accessed
296 * access [in] access mode requested
297 * sharing [in] share mode
298 * sa [in] pointer to security attributes
299 * creation [in] how to create the file
300 * attributes [in] attributes for newly created file
301 * template [in] handle to file with extended attributes to copy
303 * RETURNS
304 * Success: Open handle to specified file
305 * Failure: INVALID_HANDLE_VALUE
307 * NOTES
308 * Should call SetLastError() on failure.
310 * BUGS
312 * Doesn't support character devices, template files, or a
313 * lot of the 'attributes' flags yet.
315 HANDLE WINAPI CreateFileW( LPCWSTR filename, DWORD access, DWORD sharing,
316 LPSECURITY_ATTRIBUTES sa, DWORD creation,
317 DWORD attributes, HANDLE template )
319 DOS_FULL_NAME full_name;
320 HANDLE ret;
321 DWORD dosdev;
322 static const WCHAR bkslashes_with_question_markW[] = {'\\','\\','?','\\',0};
323 static const WCHAR bkslashes_with_dotW[] = {'\\','\\','.','\\',0};
324 static const WCHAR bkslashesW[] = {'\\','\\',0};
325 static const WCHAR coninW[] = {'C','O','N','I','N','$',0};
326 static const WCHAR conoutW[] = {'C','O','N','O','U','T','$',0};
328 if (!filename)
330 SetLastError( ERROR_INVALID_PARAMETER );
331 return INVALID_HANDLE_VALUE;
333 TRACE("%s %s%s%s%s%s%s%s attributes 0x%lx\n", debugstr_w(filename),
334 ((access & GENERIC_READ)==GENERIC_READ)?"GENERIC_READ ":"",
335 ((access & GENERIC_WRITE)==GENERIC_WRITE)?"GENERIC_WRITE ":"",
336 (!access)?"QUERY_ACCESS ":"",
337 ((sharing & FILE_SHARE_READ)==FILE_SHARE_READ)?"FILE_SHARE_READ ":"",
338 ((sharing & FILE_SHARE_WRITE)==FILE_SHARE_WRITE)?"FILE_SHARE_WRITE ":"",
339 ((sharing & FILE_SHARE_DELETE)==FILE_SHARE_DELETE)?"FILE_SHARE_DELETE ":"",
340 (creation ==CREATE_NEW)?"CREATE_NEW":
341 (creation ==CREATE_ALWAYS)?"CREATE_ALWAYS ":
342 (creation ==OPEN_EXISTING)?"OPEN_EXISTING ":
343 (creation ==OPEN_ALWAYS)?"OPEN_ALWAYS ":
344 (creation ==TRUNCATE_EXISTING)?"TRUNCATE_EXISTING ":"", attributes);
346 /* Open a console for CONIN$ or CONOUT$ */
347 if (!strcmpiW(filename, coninW) || !strcmpiW(filename, conoutW))
349 ret = OpenConsoleW(filename, access, (sa && sa->bInheritHandle), creation);
350 goto done;
353 /* If the name starts with '\\?\', ignore the first 4 chars. */
354 if (!strncmpW(filename, bkslashes_with_question_markW, 4))
356 static const WCHAR uncW[] = {'U','N','C','\\',0};
357 filename += 4;
358 if (!strncmpiW(filename, uncW, 4))
360 FIXME("UNC name (%s) not supported.\n", debugstr_w(filename) );
361 SetLastError( ERROR_PATH_NOT_FOUND );
362 return INVALID_HANDLE_VALUE;
366 if (!strncmpW(filename, bkslashes_with_dotW, 4))
368 static const WCHAR pipeW[] = {'P','I','P','E','\\',0};
369 if(!strncmpiW(filename + 4, pipeW, 5))
371 TRACE("Opening a pipe: %s\n", debugstr_w(filename));
372 ret = FILE_OpenPipe( filename, access, sa );
373 goto done;
375 else if (isalphaW(filename[4]) && filename[5] == ':' && filename[6] == '\0')
377 const char *device = DRIVE_GetDevice( toupperW(filename[4]) - 'A' );
378 if (device)
380 ret = FILE_CreateFile( device, access, sharing, sa, creation,
381 attributes, template, TRUE, DRIVE_FIXED );
383 else
385 SetLastError( ERROR_ACCESS_DENIED );
386 ret = INVALID_HANDLE_VALUE;
388 goto done;
390 else if ((dosdev = RtlIsDosDeviceName_U( filename + 4 )))
392 dosdev += MAKELONG( 0, 4*sizeof(WCHAR) ); /* adjust position to start of filename */
394 else
396 ret = VXD_Open( filename+4, access, sa );
397 goto done;
400 else dosdev = RtlIsDosDeviceName_U( filename );
402 if (dosdev)
404 static const WCHAR conW[] = {'C','O','N',0};
405 WCHAR dev[5];
407 memcpy( dev, filename + HIWORD(dosdev)/sizeof(WCHAR), LOWORD(dosdev) );
408 dev[LOWORD(dosdev)/sizeof(WCHAR)] = 0;
410 TRACE("opening device %s\n", debugstr_w(dev) );
412 if (!strcmpiW( dev, conW ))
414 switch (access & (GENERIC_READ|GENERIC_WRITE))
416 case GENERIC_READ:
417 ret = OpenConsoleW(coninW, access, (sa && sa->bInheritHandle), creation);
418 goto done;
419 case GENERIC_WRITE:
420 ret = OpenConsoleW(conoutW, access, (sa && sa->bInheritHandle), creation);
421 goto done;
422 default:
423 FIXME("can't open CON read/write\n");
424 SetLastError( ERROR_FILE_NOT_FOUND );
425 return INVALID_HANDLE_VALUE;
429 ret = VOLUME_OpenDevice( dev, access, sharing, sa, attributes );
430 goto done;
433 /* If the name still starts with '\\', it's a UNC name. */
434 if (!strncmpW(filename, bkslashesW, 2))
436 ret = SMB_CreateFileW(filename, access, sharing, sa, creation, attributes, template );
437 goto done;
440 /* If the name contains a DOS wild card (* or ?), do no create a file */
441 if(strchrW(filename, '*') || strchrW(filename, '?'))
443 SetLastError(ERROR_BAD_PATHNAME);
444 return INVALID_HANDLE_VALUE;
447 /* check for filename, don't check for last entry if creating */
448 if (!DOSFS_GetFullName( filename,
449 (creation == OPEN_EXISTING) ||
450 (creation == TRUNCATE_EXISTING),
451 &full_name )) {
452 WARN("Unable to get full filename from %s (GLE %ld)\n",
453 debugstr_w(filename), GetLastError());
454 return INVALID_HANDLE_VALUE;
457 ret = FILE_CreateFile( full_name.long_name, access, sharing,
458 sa, creation, attributes, template,
459 DRIVE_GetFlags(full_name.drive) & DRIVE_FAIL_READ_ONLY,
460 GetDriveTypeW( full_name.short_name ) );
461 done:
462 if (!ret) ret = INVALID_HANDLE_VALUE;
463 TRACE("returning %p\n", ret);
464 return ret;
469 /*************************************************************************
470 * CreateFileA (KERNEL32.@)
472 HANDLE WINAPI CreateFileA( LPCSTR filename, DWORD access, DWORD sharing,
473 LPSECURITY_ATTRIBUTES sa, DWORD creation,
474 DWORD attributes, HANDLE template)
476 UNICODE_STRING filenameW;
477 HANDLE ret = INVALID_HANDLE_VALUE;
479 if (!filename)
481 SetLastError( ERROR_INVALID_PARAMETER );
482 return INVALID_HANDLE_VALUE;
485 if (RtlCreateUnicodeStringFromAsciiz(&filenameW, filename))
487 ret = CreateFileW(filenameW.Buffer, access, sharing, sa, creation,
488 attributes, template);
489 RtlFreeUnicodeString(&filenameW);
491 else
492 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
493 return ret;
497 /***********************************************************************
498 * FILE_FillInfo
500 * Fill a file information from a struct stat.
502 static void FILE_FillInfo( struct stat *st, BY_HANDLE_FILE_INFORMATION *info )
504 if (S_ISDIR(st->st_mode))
505 info->dwFileAttributes = FILE_ATTRIBUTE_DIRECTORY;
506 else
507 info->dwFileAttributes = FILE_ATTRIBUTE_ARCHIVE;
508 if (!(st->st_mode & S_IWUSR))
509 info->dwFileAttributes |= FILE_ATTRIBUTE_READONLY;
511 RtlSecondsSince1970ToTime( st->st_mtime, (LARGE_INTEGER *)&info->ftCreationTime );
512 RtlSecondsSince1970ToTime( st->st_mtime, (LARGE_INTEGER *)&info->ftLastWriteTime );
513 RtlSecondsSince1970ToTime( st->st_atime, (LARGE_INTEGER *)&info->ftLastAccessTime );
515 info->dwVolumeSerialNumber = 0; /* FIXME */
516 info->nFileSizeHigh = 0;
517 info->nFileSizeLow = 0;
518 if (!S_ISDIR(st->st_mode)) {
519 info->nFileSizeHigh = st->st_size >> 32;
520 info->nFileSizeLow = st->st_size & 0xffffffff;
522 info->nNumberOfLinks = st->st_nlink;
523 info->nFileIndexHigh = 0;
524 info->nFileIndexLow = st->st_ino;
528 /***********************************************************************
529 * get_show_dot_files_option
531 static BOOL get_show_dot_files_option(void)
533 static const WCHAR WineW[] = {'M','a','c','h','i','n','e','\\',
534 'S','o','f','t','w','a','r','e','\\',
535 'W','i','n','e','\\','W','i','n','e','\\',
536 'C','o','n','f','i','g','\\','W','i','n','e',0};
537 static const WCHAR ShowDotFilesW[] = {'S','h','o','w','D','o','t','F','i','l','e','s',0};
539 char tmp[80];
540 HKEY hkey;
541 DWORD dummy;
542 OBJECT_ATTRIBUTES attr;
543 UNICODE_STRING nameW;
544 BOOL ret = FALSE;
546 attr.Length = sizeof(attr);
547 attr.RootDirectory = 0;
548 attr.ObjectName = &nameW;
549 attr.Attributes = 0;
550 attr.SecurityDescriptor = NULL;
551 attr.SecurityQualityOfService = NULL;
552 RtlInitUnicodeString( &nameW, WineW );
554 if (!NtOpenKey( &hkey, KEY_ALL_ACCESS, &attr ))
556 RtlInitUnicodeString( &nameW, ShowDotFilesW );
557 if (!NtQueryValueKey( hkey, &nameW, KeyValuePartialInformation, tmp, sizeof(tmp), &dummy ))
559 WCHAR *str = (WCHAR *)((KEY_VALUE_PARTIAL_INFORMATION *)tmp)->Data;
560 ret = IS_OPTION_TRUE( str[0] );
562 NtClose( hkey );
564 return ret;
568 /***********************************************************************
569 * FILE_Stat
571 * Stat a Unix path name. Return TRUE if OK.
573 BOOL FILE_Stat( LPCSTR unixName, BY_HANDLE_FILE_INFORMATION *info, BOOL *is_symlink_ptr )
575 struct stat st;
576 int is_symlink;
577 LPCSTR p;
579 if (lstat( unixName, &st ) == -1)
581 FILE_SetDosError();
582 return FALSE;
584 is_symlink = S_ISLNK(st.st_mode);
585 if (is_symlink)
587 /* do a "real" stat to find out
588 about the type of the symlink destination */
589 if (stat( unixName, &st ) == -1)
591 FILE_SetDosError();
592 return FALSE;
596 /* fill in the information we gathered so far */
597 FILE_FillInfo( &st, info );
599 /* and now see if this is a hidden file, based on the name */
600 p = strrchr( unixName, '/');
601 p = p ? p + 1 : unixName;
602 if (*p == '.' && *(p+1) && (*(p+1) != '.' || *(p+2)))
604 static int show_dot_files = -1;
605 if (show_dot_files == -1)
606 show_dot_files = get_show_dot_files_option();
607 if (!show_dot_files)
608 info->dwFileAttributes |= FILE_ATTRIBUTE_HIDDEN;
610 if (is_symlink_ptr) *is_symlink_ptr = is_symlink;
611 return TRUE;
615 /***********************************************************************
616 * GetFileInformationByHandle (KERNEL32.@)
618 DWORD WINAPI GetFileInformationByHandle( HANDLE hFile,
619 BY_HANDLE_FILE_INFORMATION *info )
621 DWORD ret;
622 if (!info) return 0;
624 TRACE("%p\n", hFile);
626 SERVER_START_REQ( get_file_info )
628 req->handle = hFile;
629 if ((ret = !wine_server_call_err( req )))
631 /* FIXME: which file types are supported ?
632 * Serial ports (FILE_TYPE_CHAR) are not,
633 * and MSDN also says that pipes are not supported.
634 * FILE_TYPE_REMOTE seems to be supported according to
635 * MSDN q234741.txt */
636 if ((reply->type == FILE_TYPE_DISK) || (reply->type == FILE_TYPE_REMOTE))
638 RtlSecondsSince1970ToTime( reply->write_time, (LARGE_INTEGER *)&info->ftCreationTime );
639 RtlSecondsSince1970ToTime( reply->write_time, (LARGE_INTEGER *)&info->ftLastWriteTime );
640 RtlSecondsSince1970ToTime( reply->access_time, (LARGE_INTEGER *)&info->ftLastAccessTime );
641 info->dwFileAttributes = reply->attr;
642 info->dwVolumeSerialNumber = reply->serial;
643 info->nFileSizeHigh = reply->size_high;
644 info->nFileSizeLow = reply->size_low;
645 info->nNumberOfLinks = reply->links;
646 info->nFileIndexHigh = reply->index_high;
647 info->nFileIndexLow = reply->index_low;
649 else
651 SetLastError(ERROR_NOT_SUPPORTED);
652 ret = 0;
656 SERVER_END_REQ;
657 return ret;
661 /**************************************************************************
662 * GetFileAttributesW (KERNEL32.@)
664 DWORD WINAPI GetFileAttributesW( LPCWSTR name )
666 DOS_FULL_NAME full_name;
667 BY_HANDLE_FILE_INFORMATION info;
669 if (name == NULL)
671 SetLastError( ERROR_INVALID_PARAMETER );
672 return INVALID_FILE_ATTRIBUTES;
674 if (!DOSFS_GetFullName( name, TRUE, &full_name) )
675 return INVALID_FILE_ATTRIBUTES;
676 if (!FILE_Stat( full_name.long_name, &info, NULL ))
677 return INVALID_FILE_ATTRIBUTES;
678 return info.dwFileAttributes;
682 /**************************************************************************
683 * GetFileAttributesA (KERNEL32.@)
685 DWORD WINAPI GetFileAttributesA( LPCSTR name )
687 UNICODE_STRING nameW;
688 DWORD ret = INVALID_FILE_ATTRIBUTES;
690 if (!name)
692 SetLastError( ERROR_INVALID_PARAMETER );
693 return INVALID_FILE_ATTRIBUTES;
696 if (RtlCreateUnicodeStringFromAsciiz(&nameW, name))
698 ret = GetFileAttributesW(nameW.Buffer);
699 RtlFreeUnicodeString(&nameW);
701 else
702 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
703 return ret;
707 /**************************************************************************
708 * SetFileAttributesW (KERNEL32.@)
710 BOOL WINAPI SetFileAttributesW(LPCWSTR lpFileName, DWORD attributes)
712 struct stat buf;
713 DOS_FULL_NAME full_name;
715 if (!lpFileName)
717 SetLastError( ERROR_INVALID_PARAMETER );
718 return FALSE;
721 TRACE("(%s,%lx)\n", debugstr_w(lpFileName), attributes);
723 if (!DOSFS_GetFullName( lpFileName, TRUE, &full_name ))
724 return FALSE;
726 if(stat(full_name.long_name,&buf)==-1)
728 FILE_SetDosError();
729 return FALSE;
731 if (attributes & FILE_ATTRIBUTE_READONLY)
733 if(S_ISDIR(buf.st_mode))
734 /* FIXME */
735 WARN("FILE_ATTRIBUTE_READONLY ignored for directory.\n");
736 else
737 buf.st_mode &= ~0222; /* octal!, clear write permission bits */
738 attributes &= ~FILE_ATTRIBUTE_READONLY;
740 else
742 /* add write permission */
743 buf.st_mode |= (0600 | ((buf.st_mode & 044) >> 1)) & (~FILE_umask);
745 if (attributes & FILE_ATTRIBUTE_DIRECTORY)
747 if (!S_ISDIR(buf.st_mode))
748 FIXME("SetFileAttributes expected the file %s to be a directory\n",
749 debugstr_w(lpFileName));
750 attributes &= ~FILE_ATTRIBUTE_DIRECTORY;
752 attributes &= ~(FILE_ATTRIBUTE_NORMAL|FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_HIDDEN|
753 FILE_ATTRIBUTE_SYSTEM|FILE_ATTRIBUTE_TEMPORARY);
754 if (attributes)
755 FIXME("(%s):%lx attribute(s) not implemented.\n", debugstr_w(lpFileName), attributes);
756 if (-1==chmod(full_name.long_name,buf.st_mode))
758 if (GetDriveTypeW(lpFileName) == DRIVE_CDROM)
760 SetLastError( ERROR_ACCESS_DENIED );
761 return FALSE;
765 * FIXME: We don't return FALSE here because of differences between
766 * Linux and Windows privileges. Under Linux only the owner of
767 * the file is allowed to change file attributes. Under Windows,
768 * applications expect that if you can write to a file, you can also
769 * change its attributes (see GENERIC_WRITE). We could try to be
770 * clever here but that would break multi-user installations where
771 * users share read-only DLLs. This is because some installers like
772 * to change attributes of already installed DLLs.
774 FIXME("Couldn't set file attributes for existing file \"%s\".\n"
775 "Check permissions or set VFAT \"quiet\" mount flag\n", full_name.long_name);
777 return TRUE;
781 /**************************************************************************
782 * SetFileAttributesA (KERNEL32.@)
784 BOOL WINAPI SetFileAttributesA(LPCSTR lpFileName, DWORD attributes)
786 UNICODE_STRING filenameW;
787 BOOL ret = FALSE;
789 if (!lpFileName)
791 SetLastError( ERROR_INVALID_PARAMETER );
792 return FALSE;
795 if (RtlCreateUnicodeStringFromAsciiz(&filenameW, lpFileName))
797 ret = SetFileAttributesW(filenameW.Buffer, attributes);
798 RtlFreeUnicodeString(&filenameW);
800 else
801 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
802 return ret;
806 /******************************************************************************
807 * GetCompressedFileSizeA [KERNEL32.@]
809 DWORD WINAPI GetCompressedFileSizeA(
810 LPCSTR lpFileName,
811 LPDWORD lpFileSizeHigh)
813 UNICODE_STRING filenameW;
814 DWORD ret;
816 if (RtlCreateUnicodeStringFromAsciiz(&filenameW, lpFileName))
818 ret = GetCompressedFileSizeW(filenameW.Buffer, lpFileSizeHigh);
819 RtlFreeUnicodeString(&filenameW);
821 else
823 ret = INVALID_FILE_SIZE;
824 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
826 return ret;
830 /******************************************************************************
831 * GetCompressedFileSizeW [KERNEL32.@]
833 * RETURNS
834 * Success: Low-order doubleword of number of bytes
835 * Failure: INVALID_FILE_SIZE
837 DWORD WINAPI GetCompressedFileSizeW(
838 LPCWSTR lpFileName, /* [in] Pointer to name of file */
839 LPDWORD lpFileSizeHigh) /* [out] Receives high-order doubleword of size */
841 DOS_FULL_NAME full_name;
842 struct stat st;
843 DWORD low;
845 TRACE("(%s,%p)\n",debugstr_w(lpFileName),lpFileSizeHigh);
847 if (!DOSFS_GetFullName( lpFileName, TRUE, &full_name )) return INVALID_FILE_SIZE;
848 if (stat(full_name.long_name, &st) != 0)
850 FILE_SetDosError();
851 return INVALID_FILE_SIZE;
853 #if HAVE_STRUCT_STAT_ST_BLOCKS
854 /* blocks are 512 bytes long */
855 if (lpFileSizeHigh) *lpFileSizeHigh = (st.st_blocks >> 23);
856 low = (DWORD)(st.st_blocks << 9);
857 #else
858 if (lpFileSizeHigh) *lpFileSizeHigh = (st.st_size >> 32);
859 low = (DWORD)st.st_size;
860 #endif
861 return low;
865 /***********************************************************************
866 * GetFileTime (KERNEL32.@)
868 BOOL WINAPI GetFileTime( HANDLE hFile, FILETIME *lpCreationTime,
869 FILETIME *lpLastAccessTime,
870 FILETIME *lpLastWriteTime )
872 BY_HANDLE_FILE_INFORMATION info;
873 if (!GetFileInformationByHandle( hFile, &info )) return FALSE;
874 if (lpCreationTime) *lpCreationTime = info.ftCreationTime;
875 if (lpLastAccessTime) *lpLastAccessTime = info.ftLastAccessTime;
876 if (lpLastWriteTime) *lpLastWriteTime = info.ftLastWriteTime;
877 return TRUE;
881 /***********************************************************************
882 * GetTempFileNameA (KERNEL32.@)
884 UINT WINAPI GetTempFileNameA( LPCSTR path, LPCSTR prefix, UINT unique,
885 LPSTR buffer)
887 UNICODE_STRING pathW, prefixW;
888 WCHAR bufferW[MAX_PATH];
889 UINT ret;
891 if ( !path || !prefix || !buffer )
893 SetLastError( ERROR_INVALID_PARAMETER );
894 return 0;
897 RtlCreateUnicodeStringFromAsciiz(&pathW, path);
898 RtlCreateUnicodeStringFromAsciiz(&prefixW, prefix);
900 ret = GetTempFileNameW(pathW.Buffer, prefixW.Buffer, unique, bufferW);
901 if (ret)
902 WideCharToMultiByte(CP_ACP, 0, bufferW, -1, buffer, MAX_PATH, NULL, NULL);
904 RtlFreeUnicodeString(&pathW);
905 RtlFreeUnicodeString(&prefixW);
906 return ret;
909 /***********************************************************************
910 * GetTempFileNameW (KERNEL32.@)
912 UINT WINAPI GetTempFileNameW( LPCWSTR path, LPCWSTR prefix, UINT unique,
913 LPWSTR buffer )
915 static const WCHAR formatW[] = {'%','x','.','t','m','p',0};
917 DOS_FULL_NAME full_name;
918 int i;
919 LPWSTR p;
921 if ( !path || !prefix || !buffer )
923 SetLastError( ERROR_INVALID_PARAMETER );
924 return 0;
927 strcpyW( buffer, path );
928 p = buffer + strlenW(buffer);
930 /* add a \, if there isn't one */
931 if ((p == buffer) || (p[-1] != '\\')) *p++ = '\\';
933 for (i = 3; (i > 0) && (*prefix); i--) *p++ = *prefix++;
935 unique &= 0xffff;
937 if (unique) sprintfW( p, formatW, unique );
938 else
940 /* get a "random" unique number and try to create the file */
941 HANDLE handle;
942 UINT num = GetTickCount() & 0xffff;
944 if (!num) num = 1;
945 unique = num;
948 sprintfW( p, formatW, unique );
949 handle = CreateFileW( buffer, GENERIC_WRITE, 0, NULL,
950 CREATE_NEW, FILE_ATTRIBUTE_NORMAL, 0 );
951 if (handle != INVALID_HANDLE_VALUE)
952 { /* We created it */
953 TRACE("created %s\n", debugstr_w(buffer) );
954 CloseHandle( handle );
955 break;
957 if (GetLastError() != ERROR_FILE_EXISTS &&
958 GetLastError() != ERROR_SHARING_VIOLATION)
959 break; /* No need to go on */
960 if (!(++unique & 0xffff)) unique = 1;
961 } while (unique != num);
964 /* Get the full path name */
966 if (DOSFS_GetFullName( buffer, FALSE, &full_name ))
968 char *slash;
969 /* Check if we have write access in the directory */
970 if ((slash = strrchr( full_name.long_name, '/' ))) *slash = '\0';
971 if (access( full_name.long_name, W_OK ) == -1)
972 WARN("returns %s, which doesn't seem to be writeable.\n",
973 debugstr_w(buffer) );
975 TRACE("returning %s\n", debugstr_w(buffer) );
976 return unique;
980 /******************************************************************
981 * FILE_ReadWriteApc (internal)
985 static void WINAPI FILE_ReadWriteApc(void* apc_user, PIO_STATUS_BLOCK io_status, ULONG len)
987 LPOVERLAPPED_COMPLETION_ROUTINE cr = (LPOVERLAPPED_COMPLETION_ROUTINE)apc_user;
989 cr(RtlNtStatusToDosError(io_status->u.Status), len, (LPOVERLAPPED)io_status);
992 /***********************************************************************
993 * ReadFileEx (KERNEL32.@)
995 BOOL WINAPI ReadFileEx(HANDLE hFile, LPVOID buffer, DWORD bytesToRead,
996 LPOVERLAPPED overlapped,
997 LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine)
999 LARGE_INTEGER offset;
1000 NTSTATUS status;
1001 PIO_STATUS_BLOCK io_status;
1003 if (!overlapped)
1005 SetLastError(ERROR_INVALID_PARAMETER);
1006 return FALSE;
1009 offset.u.LowPart = overlapped->Offset;
1010 offset.u.HighPart = overlapped->OffsetHigh;
1011 io_status = (PIO_STATUS_BLOCK)overlapped;
1012 io_status->u.Status = STATUS_PENDING;
1014 status = NtReadFile(hFile, NULL, FILE_ReadWriteApc, lpCompletionRoutine,
1015 io_status, buffer, bytesToRead, &offset, NULL);
1017 if (status)
1019 SetLastError( RtlNtStatusToDosError(status) );
1020 return FALSE;
1022 return TRUE;
1025 /***********************************************************************
1026 * ReadFile (KERNEL32.@)
1028 BOOL WINAPI ReadFile( HANDLE hFile, LPVOID buffer, DWORD bytesToRead,
1029 LPDWORD bytesRead, LPOVERLAPPED overlapped )
1031 LARGE_INTEGER offset;
1032 PLARGE_INTEGER poffset = NULL;
1033 IO_STATUS_BLOCK iosb;
1034 PIO_STATUS_BLOCK io_status = &iosb;
1035 HANDLE hEvent = 0;
1036 NTSTATUS status;
1038 TRACE("%p %p %ld %p %p\n", hFile, buffer, bytesToRead,
1039 bytesRead, overlapped );
1041 if (bytesRead) *bytesRead = 0; /* Do this before anything else */
1042 if (!bytesToRead) return TRUE;
1044 if (IsBadReadPtr(buffer, bytesToRead))
1046 SetLastError(ERROR_WRITE_FAULT); /* FIXME */
1047 return FALSE;
1049 if (is_console_handle(hFile))
1050 return ReadConsoleA(hFile, buffer, bytesToRead, bytesRead, NULL);
1052 if (overlapped != NULL)
1054 offset.u.LowPart = overlapped->Offset;
1055 offset.u.HighPart = overlapped->OffsetHigh;
1056 poffset = &offset;
1057 hEvent = overlapped->hEvent;
1058 io_status = (PIO_STATUS_BLOCK)overlapped;
1060 io_status->u.Status = STATUS_PENDING;
1061 io_status->Information = 0;
1063 status = NtReadFile(hFile, hEvent, NULL, NULL, io_status, buffer, bytesToRead, poffset, NULL);
1065 if (status != STATUS_PENDING && bytesRead)
1066 *bytesRead = io_status->Information;
1068 if (status && status != STATUS_END_OF_FILE)
1070 SetLastError( RtlNtStatusToDosError(status) );
1071 return FALSE;
1073 return TRUE;
1077 /***********************************************************************
1078 * WriteFileEx (KERNEL32.@)
1080 BOOL WINAPI WriteFileEx(HANDLE hFile, LPCVOID buffer, DWORD bytesToWrite,
1081 LPOVERLAPPED overlapped,
1082 LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine)
1084 LARGE_INTEGER offset;
1085 NTSTATUS status;
1086 PIO_STATUS_BLOCK io_status;
1088 TRACE("%p %p %ld %p %p\n",
1089 hFile, buffer, bytesToWrite, overlapped, lpCompletionRoutine);
1091 if (overlapped == NULL)
1093 SetLastError(ERROR_INVALID_PARAMETER);
1094 return FALSE;
1096 offset.u.LowPart = overlapped->Offset;
1097 offset.u.HighPart = overlapped->OffsetHigh;
1099 io_status = (PIO_STATUS_BLOCK)overlapped;
1100 io_status->u.Status = STATUS_PENDING;
1102 status = NtWriteFile(hFile, NULL, FILE_ReadWriteApc, lpCompletionRoutine,
1103 io_status, buffer, bytesToWrite, &offset, NULL);
1105 if (status) SetLastError( RtlNtStatusToDosError(status) );
1106 return !status;
1109 /***********************************************************************
1110 * WriteFile (KERNEL32.@)
1112 BOOL WINAPI WriteFile( HANDLE hFile, LPCVOID buffer, DWORD bytesToWrite,
1113 LPDWORD bytesWritten, LPOVERLAPPED overlapped )
1115 HANDLE hEvent = NULL;
1116 LARGE_INTEGER offset;
1117 PLARGE_INTEGER poffset = NULL;
1118 NTSTATUS status;
1119 IO_STATUS_BLOCK iosb;
1120 PIO_STATUS_BLOCK piosb = &iosb;
1122 TRACE("%p %p %ld %p %p\n",
1123 hFile, buffer, bytesToWrite, bytesWritten, overlapped );
1125 if (is_console_handle(hFile))
1126 return WriteConsoleA(hFile, buffer, bytesToWrite, bytesWritten, NULL);
1128 if (IsBadReadPtr(buffer, bytesToWrite))
1130 SetLastError(ERROR_READ_FAULT); /* FIXME */
1131 return FALSE;
1134 if (overlapped)
1136 offset.u.LowPart = overlapped->Offset;
1137 offset.u.HighPart = overlapped->OffsetHigh;
1138 poffset = &offset;
1139 hEvent = overlapped->hEvent;
1140 piosb = (PIO_STATUS_BLOCK)overlapped;
1142 piosb->u.Status = STATUS_PENDING;
1143 piosb->Information = 0;
1145 status = NtWriteFile(hFile, hEvent, NULL, NULL, piosb,
1146 buffer, bytesToWrite, poffset, NULL);
1147 if (status)
1149 SetLastError( RtlNtStatusToDosError(status) );
1150 return FALSE;
1152 if (bytesWritten) *bytesWritten = piosb->Information;
1154 return TRUE;
1158 /***********************************************************************
1159 * SetFilePointer (KERNEL32.@)
1161 DWORD WINAPI SetFilePointer( HANDLE hFile, LONG distance, LONG *highword,
1162 DWORD method )
1164 DWORD ret = INVALID_SET_FILE_POINTER;
1166 TRACE("handle %p offset %ld high %ld origin %ld\n",
1167 hFile, distance, highword?*highword:0, method );
1169 SERVER_START_REQ( set_file_pointer )
1171 req->handle = hFile;
1172 req->low = distance;
1173 req->high = highword ? *highword : (distance >= 0) ? 0 : -1;
1174 /* FIXME: assumes 1:1 mapping between Windows and Unix seek constants */
1175 req->whence = method;
1176 SetLastError( 0 );
1177 if (!wine_server_call_err( req ))
1179 ret = reply->new_low;
1180 if (highword) *highword = reply->new_high;
1183 SERVER_END_REQ;
1184 return ret;
1188 /*************************************************************************
1189 * SetHandleCount (KERNEL32.@)
1191 UINT WINAPI SetHandleCount( UINT count )
1193 return min( 256, count );
1197 /**************************************************************************
1198 * SetEndOfFile (KERNEL32.@)
1200 BOOL WINAPI SetEndOfFile( HANDLE hFile )
1202 BOOL ret;
1203 SERVER_START_REQ( truncate_file )
1205 req->handle = hFile;
1206 ret = !wine_server_call_err( req );
1208 SERVER_END_REQ;
1209 return ret;
1213 /***********************************************************************
1214 * DeleteFileW (KERNEL32.@)
1216 BOOL WINAPI DeleteFileW( LPCWSTR path )
1218 DOS_FULL_NAME full_name;
1219 HANDLE hFile;
1221 TRACE("%s\n", debugstr_w(path) );
1222 if (!path || !*path)
1224 SetLastError(ERROR_PATH_NOT_FOUND);
1225 return FALSE;
1227 if (RtlIsDosDeviceName_U( path ))
1229 WARN("cannot remove DOS device %s!\n", debugstr_w(path));
1230 SetLastError( ERROR_FILE_NOT_FOUND );
1231 return FALSE;
1234 if (!DOSFS_GetFullName( path, TRUE, &full_name )) return FALSE;
1236 /* check if we are allowed to delete the source */
1237 hFile = FILE_CreateFile( full_name.long_name, GENERIC_READ|GENERIC_WRITE, 0,
1238 NULL, OPEN_EXISTING, 0, 0, TRUE,
1239 GetDriveTypeW( full_name.short_name ) );
1240 if (!hFile) return FALSE;
1242 if (unlink( full_name.long_name ) == -1)
1244 FILE_SetDosError();
1245 CloseHandle(hFile);
1246 return FALSE;
1248 CloseHandle(hFile);
1249 return TRUE;
1253 /***********************************************************************
1254 * DeleteFileA (KERNEL32.@)
1256 BOOL WINAPI DeleteFileA( LPCSTR path )
1258 UNICODE_STRING pathW;
1259 BOOL ret = FALSE;
1261 if (!path)
1263 SetLastError(ERROR_INVALID_PARAMETER);
1264 return FALSE;
1267 if (RtlCreateUnicodeStringFromAsciiz(&pathW, path))
1269 ret = DeleteFileW(pathW.Buffer);
1270 RtlFreeUnicodeString(&pathW);
1272 else
1273 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1274 return ret;
1278 /***********************************************************************
1279 * GetFileType (KERNEL32.@)
1281 DWORD WINAPI GetFileType( HANDLE hFile )
1283 DWORD ret = FILE_TYPE_UNKNOWN;
1285 if (is_console_handle( hFile ))
1286 return FILE_TYPE_CHAR;
1288 SERVER_START_REQ( get_file_info )
1290 req->handle = hFile;
1291 if (!wine_server_call_err( req )) ret = reply->type;
1293 SERVER_END_REQ;
1294 return ret;
1298 /* check if a file name is for an executable file (.exe or .com) */
1299 inline static BOOL is_executable( const char *name )
1301 int len = strlen(name);
1303 if (len < 4) return FALSE;
1304 return (!strcasecmp( name + len - 4, ".exe" ) ||
1305 !strcasecmp( name + len - 4, ".com" ));
1309 /***********************************************************************
1310 * FILE_AddBootRenameEntry
1312 * Adds an entry to the registry that is loaded when windows boots and
1313 * checks if there are some files to be removed or renamed/moved.
1314 * <fn1> has to be valid and <fn2> may be NULL. If both pointers are
1315 * non-NULL then the file is moved, otherwise it is deleted. The
1316 * entry of the registrykey is always appended with two zero
1317 * terminated strings. If <fn2> is NULL then the second entry is
1318 * simply a single 0-byte. Otherwise the second filename goes
1319 * there. The entries are prepended with \??\ before the path and the
1320 * second filename gets also a '!' as the first character if
1321 * MOVEFILE_REPLACE_EXISTING is set. After the final string another
1322 * 0-byte follows to indicate the end of the strings.
1323 * i.e.:
1324 * \??\D:\test\file1[0]
1325 * !\??\D:\test\file1_renamed[0]
1326 * \??\D:\Test|delete[0]
1327 * [0] <- file is to be deleted, second string empty
1328 * \??\D:\test\file2[0]
1329 * !\??\D:\test\file2_renamed[0]
1330 * [0] <- indicates end of strings
1332 * or:
1333 * \??\D:\test\file1[0]
1334 * !\??\D:\test\file1_renamed[0]
1335 * \??\D:\Test|delete[0]
1336 * [0] <- file is to be deleted, second string empty
1337 * [0] <- indicates end of strings
1340 static BOOL FILE_AddBootRenameEntry( LPCWSTR fn1, LPCWSTR fn2, DWORD flags )
1342 static const WCHAR PreString[] = {'\\','?','?','\\',0};
1343 static const WCHAR ValueName[] = {'P','e','n','d','i','n','g',
1344 'F','i','l','e','R','e','n','a','m','e',
1345 'O','p','e','r','a','t','i','o','n','s',0};
1346 static const WCHAR SessionW[] = {'M','a','c','h','i','n','e','\\',
1347 'S','y','s','t','e','m','\\',
1348 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
1349 'C','o','n','t','r','o','l','\\',
1350 'S','e','s','s','i','o','n',' ','M','a','n','a','g','e','r',0};
1351 static const int info_size = FIELD_OFFSET( KEY_VALUE_PARTIAL_INFORMATION, Data );
1353 OBJECT_ATTRIBUTES attr;
1354 UNICODE_STRING nameW;
1355 KEY_VALUE_PARTIAL_INFORMATION *info;
1356 BOOL rc = FALSE;
1357 HKEY Reboot = 0;
1358 DWORD len0, len1, len2;
1359 DWORD DataSize = 0;
1360 BYTE *Buffer = NULL;
1361 WCHAR *p;
1363 attr.Length = sizeof(attr);
1364 attr.RootDirectory = 0;
1365 attr.ObjectName = &nameW;
1366 attr.Attributes = 0;
1367 attr.SecurityDescriptor = NULL;
1368 attr.SecurityQualityOfService = NULL;
1369 RtlInitUnicodeString( &nameW, SessionW );
1371 if (NtCreateKey( &Reboot, KEY_ALL_ACCESS, &attr, 0, NULL, 0, NULL ) != STATUS_SUCCESS)
1373 WARN("Error creating key for reboot managment [%s]\n",
1374 "SYSTEM\\CurrentControlSet\\Control\\Session Manager");
1375 return FALSE;
1378 len0 = strlenW(PreString);
1379 len1 = strlenW(fn1) + len0 + 1;
1380 if (fn2)
1382 len2 = strlenW(fn2) + len0 + 1;
1383 if (flags & MOVEFILE_REPLACE_EXISTING) len2++; /* Plus 1 because of the leading '!' */
1385 else len2 = 1; /* minimum is the 0 characters for the empty second string */
1387 /* convert characters to bytes */
1388 len0 *= sizeof(WCHAR);
1389 len1 *= sizeof(WCHAR);
1390 len2 *= sizeof(WCHAR);
1392 RtlInitUnicodeString( &nameW, ValueName );
1394 /* First we check if the key exists and if so how many bytes it already contains. */
1395 if (NtQueryValueKey( Reboot, &nameW, KeyValuePartialInformation,
1396 NULL, 0, &DataSize ) == STATUS_BUFFER_OVERFLOW)
1398 if (!(Buffer = HeapAlloc( GetProcessHeap(), 0, DataSize + len1 + len2 + sizeof(WCHAR) )))
1399 goto Quit;
1400 if (NtQueryValueKey( Reboot, &nameW, KeyValuePartialInformation,
1401 Buffer, DataSize, &DataSize )) goto Quit;
1402 info = (KEY_VALUE_PARTIAL_INFORMATION *)Buffer;
1403 if (info->Type != REG_MULTI_SZ) goto Quit;
1404 if (DataSize > sizeof(info)) DataSize -= sizeof(WCHAR); /* remove terminating null (will be added back later) */
1406 else
1408 DataSize = info_size;
1409 if (!(Buffer = HeapAlloc( GetProcessHeap(), 0, DataSize + len1 + len2 + sizeof(WCHAR) )))
1410 goto Quit;
1413 p = (WCHAR *)(Buffer + DataSize);
1414 strcpyW( p, PreString );
1415 strcatW( p, fn1 );
1416 DataSize += len1;
1417 if (fn2)
1419 p = (WCHAR *)(Buffer + DataSize);
1420 if (flags & MOVEFILE_REPLACE_EXISTING)
1421 *p++ = '!';
1422 strcpyW( p, PreString );
1423 strcatW( p, fn2 );
1424 DataSize += len2;
1426 else
1428 p = (WCHAR *)(Buffer + DataSize);
1429 *p = 0;
1430 DataSize += sizeof(WCHAR);
1433 /* add final null */
1434 p = (WCHAR *)(Buffer + DataSize);
1435 *p = 0;
1436 DataSize += sizeof(WCHAR);
1438 rc = !NtSetValueKey(Reboot, &nameW, 0, REG_MULTI_SZ, Buffer + info_size, DataSize - info_size);
1440 Quit:
1441 if (Reboot) NtClose(Reboot);
1442 if (Buffer) HeapFree( GetProcessHeap(), 0, Buffer );
1443 return(rc);
1447 /**************************************************************************
1448 * MoveFileExW (KERNEL32.@)
1450 BOOL WINAPI MoveFileExW( LPCWSTR fn1, LPCWSTR fn2, DWORD flag )
1452 DOS_FULL_NAME full_name1, full_name2;
1453 HANDLE hFile;
1454 DWORD attr = INVALID_FILE_ATTRIBUTES;
1456 TRACE("(%s,%s,%04lx)\n", debugstr_w(fn1), debugstr_w(fn2), flag);
1458 /* FIXME: <Gerhard W. Gruber>sparhawk@gmx.at
1459 In case of W9x and lesser this function should return 120 (ERROR_CALL_NOT_IMPLEMENTED)
1460 to be really compatible. Most programs won't have any problems though. In case
1461 you encounter one, this is what you should return here. I don't know what's up
1462 with NT 3.5. Is this function available there or not?
1463 Does anybody really care about 3.5? :)
1466 /* Filename1 has to be always set to a valid path. Filename2 may be NULL
1467 if the source file has to be deleted.
1469 if (!fn1) {
1470 SetLastError(ERROR_INVALID_PARAMETER);
1471 return FALSE;
1474 /* This function has to be run through in order to process the name properly.
1475 If the BOOTDELAY flag is set, the file doesn't need to exist though. At least
1476 that is the behaviour on NT 4.0. The operation accepts the filenames as
1477 they are given but it can't reply with a reasonable returncode. Success
1478 means in that case success for entering the values into the registry.
1480 if(!DOSFS_GetFullName( fn1, TRUE, &full_name1 ))
1482 if(!(flag & MOVEFILE_DELAY_UNTIL_REBOOT))
1483 return FALSE;
1486 if (fn2) /* !fn2 means delete fn1 */
1488 if (DOSFS_GetFullName( fn2, TRUE, &full_name2 ))
1490 if(!(flag & MOVEFILE_DELAY_UNTIL_REBOOT))
1492 /* target exists, check if we may overwrite */
1493 if (!(flag & MOVEFILE_REPLACE_EXISTING))
1495 SetLastError( ERROR_ALREADY_EXISTS );
1496 return FALSE;
1500 else
1502 if (!DOSFS_GetFullName( fn2, FALSE, &full_name2 ))
1504 if(!(flag & MOVEFILE_DELAY_UNTIL_REBOOT))
1505 return FALSE;
1509 /* Source name and target path are valid */
1511 if (flag & MOVEFILE_DELAY_UNTIL_REBOOT)
1513 return FILE_AddBootRenameEntry( fn1, fn2, flag );
1516 attr = GetFileAttributesW( fn1 );
1517 if ( attr == INVALID_FILE_ATTRIBUTES ) return FALSE;
1519 /* check if we are allowed to rename the source */
1520 hFile = FILE_CreateFile( full_name1.long_name, 0, 0,
1521 NULL, OPEN_EXISTING, 0, 0, TRUE,
1522 GetDriveTypeW( full_name1.short_name ) );
1523 if (!hFile)
1525 if (GetLastError() != ERROR_ACCESS_DENIED) return FALSE;
1526 if ( !(attr & FILE_ATTRIBUTE_DIRECTORY) ) return FALSE;
1527 /* if it's a directory we can continue */
1529 else CloseHandle(hFile);
1531 /* check, if we are allowed to delete the destination,
1532 ** (but the file not being there is fine) */
1533 hFile = FILE_CreateFile( full_name2.long_name, GENERIC_READ|GENERIC_WRITE, 0,
1534 NULL, OPEN_EXISTING, 0, 0, TRUE,
1535 GetDriveTypeW( full_name2.short_name ) );
1536 if(!hFile && GetLastError() != ERROR_FILE_NOT_FOUND) return FALSE;
1537 CloseHandle(hFile);
1539 if (full_name1.drive != full_name2.drive)
1541 if (!(flag & MOVEFILE_COPY_ALLOWED))
1543 SetLastError( ERROR_NOT_SAME_DEVICE );
1544 return FALSE;
1546 else if ( attr & FILE_ATTRIBUTE_DIRECTORY )
1548 /* Strange, but that's what Windows returns */
1549 SetLastError ( ERROR_ACCESS_DENIED );
1550 return FALSE;
1553 if (rename( full_name1.long_name, full_name2.long_name ) == -1)
1554 /* Try copy/delete unless it's a directory. */
1555 /* FIXME: This does not handle the (unlikely) case that the two locations
1556 are on the same Wine drive, but on different Unix file systems. */
1558 if ( attr & FILE_ATTRIBUTE_DIRECTORY )
1560 FILE_SetDosError();
1561 return FALSE;
1563 else
1565 if ( ! CopyFileW( fn1, fn2, !(flag & MOVEFILE_REPLACE_EXISTING) ))
1566 return FALSE;
1567 if ( ! DeleteFileW ( fn1 ) )
1568 return FALSE;
1571 if (is_executable( full_name1.long_name ) != is_executable( full_name2.long_name ))
1573 struct stat fstat;
1574 if (stat( full_name2.long_name, &fstat ) != -1)
1576 if (is_executable( full_name2.long_name ))
1577 /* set executable bit where read bit is set */
1578 fstat.st_mode |= (fstat.st_mode & 0444) >> 2;
1579 else
1580 fstat.st_mode &= ~0111;
1581 chmod( full_name2.long_name, fstat.st_mode );
1584 return TRUE;
1586 else /* fn2 == NULL means delete source */
1588 if (flag & MOVEFILE_DELAY_UNTIL_REBOOT)
1590 if (flag & MOVEFILE_COPY_ALLOWED) {
1591 WARN("Illegal flag\n");
1592 SetLastError( ERROR_GEN_FAILURE );
1593 return FALSE;
1596 return FILE_AddBootRenameEntry( fn1, NULL, flag );
1599 if (unlink( full_name1.long_name ) == -1)
1601 FILE_SetDosError();
1602 return FALSE;
1604 return TRUE; /* successfully deleted */
1608 /**************************************************************************
1609 * MoveFileExA (KERNEL32.@)
1611 BOOL WINAPI MoveFileExA( LPCSTR fn1, LPCSTR fn2, DWORD flag )
1613 UNICODE_STRING fn1W, fn2W;
1614 BOOL ret;
1616 if (!fn1)
1618 SetLastError(ERROR_INVALID_PARAMETER);
1619 return FALSE;
1622 RtlCreateUnicodeStringFromAsciiz(&fn1W, fn1);
1623 if (fn2) RtlCreateUnicodeStringFromAsciiz(&fn2W, fn2);
1624 else fn2W.Buffer = NULL;
1626 ret = MoveFileExW( fn1W.Buffer, fn2W.Buffer, flag );
1628 RtlFreeUnicodeString(&fn1W);
1629 RtlFreeUnicodeString(&fn2W);
1630 return ret;
1634 /**************************************************************************
1635 * MoveFileW (KERNEL32.@)
1637 * Move file or directory
1639 BOOL WINAPI MoveFileW( LPCWSTR fn1, LPCWSTR fn2 )
1641 return MoveFileExW( fn1, fn2, MOVEFILE_COPY_ALLOWED );
1645 /**************************************************************************
1646 * MoveFileA (KERNEL32.@)
1648 BOOL WINAPI MoveFileA( LPCSTR fn1, LPCSTR fn2 )
1650 return MoveFileExA( fn1, fn2, MOVEFILE_COPY_ALLOWED );
1654 /**************************************************************************
1655 * CopyFileW (KERNEL32.@)
1657 BOOL WINAPI CopyFileW( LPCWSTR source, LPCWSTR dest, BOOL fail_if_exists )
1659 HANDLE h1, h2;
1660 BY_HANDLE_FILE_INFORMATION info;
1661 DWORD count;
1662 BOOL ret = FALSE;
1663 char buffer[2048];
1665 if (!source || !dest)
1667 SetLastError(ERROR_INVALID_PARAMETER);
1668 return FALSE;
1671 TRACE("%s -> %s\n", debugstr_w(source), debugstr_w(dest));
1673 if ((h1 = CreateFileW(source, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE,
1674 NULL, OPEN_EXISTING, 0, 0)) == INVALID_HANDLE_VALUE)
1676 WARN("Unable to open source %s\n", debugstr_w(source));
1677 return FALSE;
1680 if (!GetFileInformationByHandle( h1, &info ))
1682 WARN("GetFileInformationByHandle returned error for %s\n", debugstr_w(source));
1683 CloseHandle( h1 );
1684 return FALSE;
1687 if ((h2 = CreateFileW( dest, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
1688 fail_if_exists ? CREATE_NEW : CREATE_ALWAYS,
1689 info.dwFileAttributes, h1 )) == INVALID_HANDLE_VALUE)
1691 WARN("Unable to open dest %s\n", debugstr_w(dest));
1692 CloseHandle( h1 );
1693 return FALSE;
1696 while (ReadFile( h1, buffer, sizeof(buffer), &count, NULL ) && count)
1698 char *p = buffer;
1699 while (count != 0)
1701 DWORD res;
1702 if (!WriteFile( h2, p, count, &res, NULL ) || !res) goto done;
1703 p += res;
1704 count -= res;
1707 ret = TRUE;
1708 done:
1709 CloseHandle( h1 );
1710 CloseHandle( h2 );
1711 return ret;
1715 /**************************************************************************
1716 * CopyFileA (KERNEL32.@)
1718 BOOL WINAPI CopyFileA( LPCSTR source, LPCSTR dest, BOOL fail_if_exists)
1720 UNICODE_STRING sourceW, destW;
1721 BOOL ret;
1723 if (!source || !dest)
1725 SetLastError(ERROR_INVALID_PARAMETER);
1726 return FALSE;
1729 RtlCreateUnicodeStringFromAsciiz(&sourceW, source);
1730 RtlCreateUnicodeStringFromAsciiz(&destW, dest);
1732 ret = CopyFileW(sourceW.Buffer, destW.Buffer, fail_if_exists);
1734 RtlFreeUnicodeString(&sourceW);
1735 RtlFreeUnicodeString(&destW);
1736 return ret;
1740 /**************************************************************************
1741 * CopyFileExW (KERNEL32.@)
1743 * This implementation ignores most of the extra parameters passed-in into
1744 * the "ex" version of the method and calls the CopyFile method.
1745 * It will have to be fixed eventually.
1747 BOOL WINAPI CopyFileExW(LPCWSTR sourceFilename, LPCWSTR destFilename,
1748 LPPROGRESS_ROUTINE progressRoutine, LPVOID appData,
1749 LPBOOL cancelFlagPointer, DWORD copyFlags)
1752 * Interpret the only flag that CopyFile can interpret.
1754 return CopyFileW(sourceFilename, destFilename, (copyFlags & COPY_FILE_FAIL_IF_EXISTS) != 0);
1758 /**************************************************************************
1759 * CopyFileExA (KERNEL32.@)
1761 BOOL WINAPI CopyFileExA(LPCSTR sourceFilename, LPCSTR destFilename,
1762 LPPROGRESS_ROUTINE progressRoutine, LPVOID appData,
1763 LPBOOL cancelFlagPointer, DWORD copyFlags)
1765 UNICODE_STRING sourceW, destW;
1766 BOOL ret;
1768 if (!sourceFilename || !destFilename)
1770 SetLastError(ERROR_INVALID_PARAMETER);
1771 return FALSE;
1774 RtlCreateUnicodeStringFromAsciiz(&sourceW, sourceFilename);
1775 RtlCreateUnicodeStringFromAsciiz(&destW, destFilename);
1777 ret = CopyFileExW(sourceW.Buffer, destW.Buffer, progressRoutine, appData,
1778 cancelFlagPointer, copyFlags);
1780 RtlFreeUnicodeString(&sourceW);
1781 RtlFreeUnicodeString(&destW);
1782 return ret;
1786 /***********************************************************************
1787 * SetFileTime (KERNEL32.@)
1789 BOOL WINAPI SetFileTime( HANDLE hFile,
1790 const FILETIME *lpCreationTime,
1791 const FILETIME *lpLastAccessTime,
1792 const FILETIME *lpLastWriteTime )
1794 BOOL ret;
1795 SERVER_START_REQ( set_file_time )
1797 req->handle = hFile;
1798 if (lpLastAccessTime)
1799 RtlTimeToSecondsSince1970( (PLARGE_INTEGER) lpLastAccessTime, (DWORD *)&req->access_time );
1800 else
1801 req->access_time = 0; /* FIXME */
1802 if (lpLastWriteTime)
1803 RtlTimeToSecondsSince1970( (PLARGE_INTEGER) lpLastWriteTime, (DWORD *)&req->write_time );
1804 else
1805 req->write_time = 0; /* FIXME */
1806 ret = !wine_server_call_err( req );
1808 SERVER_END_REQ;
1809 return ret;
1813 /**************************************************************************
1814 * GetFileAttributesExW (KERNEL32.@)
1816 BOOL WINAPI GetFileAttributesExW(
1817 LPCWSTR lpFileName, GET_FILEEX_INFO_LEVELS fInfoLevelId,
1818 LPVOID lpFileInformation)
1820 DOS_FULL_NAME full_name;
1821 BY_HANDLE_FILE_INFORMATION info;
1823 if (!lpFileName || !lpFileInformation)
1825 SetLastError(ERROR_INVALID_PARAMETER);
1826 return FALSE;
1829 if (fInfoLevelId == GetFileExInfoStandard) {
1830 LPWIN32_FILE_ATTRIBUTE_DATA lpFad =
1831 (LPWIN32_FILE_ATTRIBUTE_DATA) lpFileInformation;
1832 if (!DOSFS_GetFullName( lpFileName, TRUE, &full_name )) return FALSE;
1833 if (!FILE_Stat( full_name.long_name, &info, NULL )) return FALSE;
1835 lpFad->dwFileAttributes = info.dwFileAttributes;
1836 lpFad->ftCreationTime = info.ftCreationTime;
1837 lpFad->ftLastAccessTime = info.ftLastAccessTime;
1838 lpFad->ftLastWriteTime = info.ftLastWriteTime;
1839 lpFad->nFileSizeHigh = info.nFileSizeHigh;
1840 lpFad->nFileSizeLow = info.nFileSizeLow;
1842 else {
1843 FIXME("invalid info level %d!\n", fInfoLevelId);
1844 return FALSE;
1847 return TRUE;
1851 /**************************************************************************
1852 * GetFileAttributesExA (KERNEL32.@)
1854 BOOL WINAPI GetFileAttributesExA(
1855 LPCSTR filename, GET_FILEEX_INFO_LEVELS fInfoLevelId,
1856 LPVOID lpFileInformation)
1858 UNICODE_STRING filenameW;
1859 BOOL ret = FALSE;
1861 if (!filename || !lpFileInformation)
1863 SetLastError(ERROR_INVALID_PARAMETER);
1864 return FALSE;
1867 if (RtlCreateUnicodeStringFromAsciiz(&filenameW, filename))
1869 ret = GetFileAttributesExW(filenameW.Buffer, fInfoLevelId, lpFileInformation);
1870 RtlFreeUnicodeString(&filenameW);
1872 else
1873 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1874 return ret;