Check file sharing permissions based on the file inode instead of the
[wine/multimedia.git] / files / file.c
blob7b90a7fe5f34472cb3d56caaaff7703f9908df51
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 #define SECSPERDAY 86400
87 #define SECS_1601_TO_1970 ((369 * 365 + 89) * (ULONGLONG)SECSPERDAY)
89 mode_t FILE_umask;
91 /***********************************************************************
92 * FILE_ConvertOFMode
94 * Convert OF_* mode into flags for CreateFile.
96 void FILE_ConvertOFMode( INT mode, DWORD *access, DWORD *sharing )
98 switch(mode & 0x03)
100 case OF_READ: *access = GENERIC_READ; break;
101 case OF_WRITE: *access = GENERIC_WRITE; break;
102 case OF_READWRITE: *access = GENERIC_READ | GENERIC_WRITE; break;
103 default: *access = 0; break;
105 switch(mode & 0x70)
107 case OF_SHARE_EXCLUSIVE: *sharing = 0; break;
108 case OF_SHARE_DENY_WRITE: *sharing = FILE_SHARE_READ; break;
109 case OF_SHARE_DENY_READ: *sharing = FILE_SHARE_WRITE; break;
110 case OF_SHARE_DENY_NONE:
111 case OF_SHARE_COMPAT:
112 default: *sharing = FILE_SHARE_READ | FILE_SHARE_WRITE; break;
117 /***********************************************************************
118 * FILE_SetDosError
120 * Set the DOS error code from errno.
122 void FILE_SetDosError(void)
124 int save_errno = errno; /* errno gets overwritten by printf */
126 TRACE("errno = %d %s\n", errno, strerror(errno));
127 switch (save_errno)
129 case EAGAIN:
130 SetLastError( ERROR_SHARING_VIOLATION );
131 break;
132 case EBADF:
133 SetLastError( ERROR_INVALID_HANDLE );
134 break;
135 case ENOSPC:
136 SetLastError( ERROR_HANDLE_DISK_FULL );
137 break;
138 case EACCES:
139 case EPERM:
140 case EROFS:
141 SetLastError( ERROR_ACCESS_DENIED );
142 break;
143 case EBUSY:
144 SetLastError( ERROR_LOCK_VIOLATION );
145 break;
146 case ENOENT:
147 SetLastError( ERROR_FILE_NOT_FOUND );
148 break;
149 case EISDIR:
150 SetLastError( ERROR_CANNOT_MAKE );
151 break;
152 case ENFILE:
153 case EMFILE:
154 SetLastError( ERROR_NO_MORE_FILES );
155 break;
156 case EEXIST:
157 SetLastError( ERROR_FILE_EXISTS );
158 break;
159 case EINVAL:
160 case ESPIPE:
161 SetLastError( ERROR_SEEK );
162 break;
163 case ENOTEMPTY:
164 SetLastError( ERROR_DIR_NOT_EMPTY );
165 break;
166 case ENOEXEC:
167 SetLastError( ERROR_BAD_FORMAT );
168 break;
169 default:
170 WARN("unknown file error: %s\n", strerror(save_errno) );
171 SetLastError( ERROR_GEN_FAILURE );
172 break;
174 errno = save_errno;
178 /***********************************************************************
179 * FILE_CreateFile
181 * Implementation of CreateFile. Takes a Unix path name.
182 * Returns 0 on failure.
184 HANDLE FILE_CreateFile( LPCSTR filename, DWORD access, DWORD sharing,
185 LPSECURITY_ATTRIBUTES sa, DWORD creation,
186 DWORD attributes, HANDLE template, BOOL fail_read_only,
187 UINT drive_type )
189 unsigned int err;
190 UINT disp, options;
191 HANDLE ret;
193 switch (creation)
195 case CREATE_ALWAYS: disp = FILE_OVERWRITE_IF; break;
196 case CREATE_NEW: disp = FILE_CREATE; break;
197 case OPEN_ALWAYS: disp = FILE_OPEN_IF; break;
198 case OPEN_EXISTING: disp = FILE_OPEN; break;
199 case TRUNCATE_EXISTING: disp = FILE_OVERWRITE; break;
200 default:
201 SetLastError( ERROR_INVALID_PARAMETER );
202 return 0;
205 options = 0;
206 if (attributes & FILE_FLAG_BACKUP_SEMANTICS)
207 options |= FILE_OPEN_FOR_BACKUP_INTENT;
208 if (attributes & FILE_FLAG_DELETE_ON_CLOSE)
209 options |= FILE_DELETE_ON_CLOSE;
210 if (!(attributes & FILE_FLAG_OVERLAPPED))
211 options |= FILE_SYNCHRONOUS_IO_ALERT;
212 if (attributes & FILE_FLAG_RANDOM_ACCESS)
213 options |= FILE_RANDOM_ACCESS;
214 attributes &= FILE_ATTRIBUTE_VALID_FLAGS;
216 for (;;)
218 SERVER_START_REQ( create_file )
220 req->access = access;
221 req->inherit = (sa && (sa->nLength>=sizeof(*sa)) && sa->bInheritHandle);
222 req->sharing = sharing;
223 req->create = disp;
224 req->options = options;
225 req->attrs = attributes;
226 req->removable = (drive_type == DRIVE_REMOVABLE || drive_type == DRIVE_CDROM);
227 wine_server_add_data( req, filename, strlen(filename) );
228 SetLastError(0);
229 err = wine_server_call( req );
230 ret = reply->handle;
232 SERVER_END_REQ;
234 /* If write access failed, retry without GENERIC_WRITE */
236 if (!ret && !fail_read_only && (access & GENERIC_WRITE))
238 if ((err == STATUS_MEDIA_WRITE_PROTECTED) || (err == STATUS_ACCESS_DENIED))
240 TRACE("Write access failed for file '%s', trying without "
241 "write access\n", filename);
242 access &= ~GENERIC_WRITE;
243 continue;
247 if (err)
249 /* In the case file creation was rejected due to CREATE_NEW flag
250 * was specified and file with that name already exists, correct
251 * last error is ERROR_FILE_EXISTS and not ERROR_ALREADY_EXISTS.
252 * Note: RtlNtStatusToDosError is not the subject to blame here.
254 if (err == STATUS_OBJECT_NAME_COLLISION)
255 SetLastError( ERROR_FILE_EXISTS );
256 else
257 SetLastError( RtlNtStatusToDosError(err) );
260 if (!ret) WARN("Unable to create file '%s' (GLE %ld)\n", filename, GetLastError());
261 return ret;
266 static HANDLE FILE_OpenPipe(LPCWSTR name, DWORD access, LPSECURITY_ATTRIBUTES sa )
268 HANDLE ret;
269 DWORD len = 0;
271 if (name && (len = strlenW(name)) > MAX_PATH)
273 SetLastError( ERROR_FILENAME_EXCED_RANGE );
274 return 0;
276 SERVER_START_REQ( open_named_pipe )
278 req->access = access;
279 req->inherit = (sa && (sa->nLength>=sizeof(*sa)) && sa->bInheritHandle);
280 SetLastError(0);
281 wine_server_add_data( req, name, len * sizeof(WCHAR) );
282 wine_server_call_err( req );
283 ret = reply->handle;
285 SERVER_END_REQ;
286 TRACE("Returned %p\n",ret);
287 return ret;
290 /*************************************************************************
291 * CreateFileW [KERNEL32.@] Creates or opens a file or other object
293 * Creates or opens an object, and returns a handle that can be used to
294 * access that object.
296 * PARAMS
298 * filename [in] pointer to filename to be accessed
299 * access [in] access mode requested
300 * sharing [in] share mode
301 * sa [in] pointer to security attributes
302 * creation [in] how to create the file
303 * attributes [in] attributes for newly created file
304 * template [in] handle to file with extended attributes to copy
306 * RETURNS
307 * Success: Open handle to specified file
308 * Failure: INVALID_HANDLE_VALUE
310 * NOTES
311 * Should call SetLastError() on failure.
313 * BUGS
315 * Doesn't support character devices, template files, or a
316 * lot of the 'attributes' flags yet.
318 HANDLE WINAPI CreateFileW( LPCWSTR filename, DWORD access, DWORD sharing,
319 LPSECURITY_ATTRIBUTES sa, DWORD creation,
320 DWORD attributes, HANDLE template )
322 DOS_FULL_NAME full_name;
323 HANDLE ret;
324 DWORD dosdev;
325 static const WCHAR bkslashes_with_question_markW[] = {'\\','\\','?','\\',0};
326 static const WCHAR bkslashes_with_dotW[] = {'\\','\\','.','\\',0};
327 static const WCHAR bkslashesW[] = {'\\','\\',0};
328 static const WCHAR coninW[] = {'C','O','N','I','N','$',0};
329 static const WCHAR conoutW[] = {'C','O','N','O','U','T','$',0};
331 if (!filename)
333 SetLastError( ERROR_INVALID_PARAMETER );
334 return INVALID_HANDLE_VALUE;
336 TRACE("%s %s%s%s%s%s%s%s attributes 0x%lx\n", debugstr_w(filename),
337 ((access & GENERIC_READ)==GENERIC_READ)?"GENERIC_READ ":"",
338 ((access & GENERIC_WRITE)==GENERIC_WRITE)?"GENERIC_WRITE ":"",
339 (!access)?"QUERY_ACCESS ":"",
340 ((sharing & FILE_SHARE_READ)==FILE_SHARE_READ)?"FILE_SHARE_READ ":"",
341 ((sharing & FILE_SHARE_WRITE)==FILE_SHARE_WRITE)?"FILE_SHARE_WRITE ":"",
342 ((sharing & FILE_SHARE_DELETE)==FILE_SHARE_DELETE)?"FILE_SHARE_DELETE ":"",
343 (creation ==CREATE_NEW)?"CREATE_NEW":
344 (creation ==CREATE_ALWAYS)?"CREATE_ALWAYS ":
345 (creation ==OPEN_EXISTING)?"OPEN_EXISTING ":
346 (creation ==OPEN_ALWAYS)?"OPEN_ALWAYS ":
347 (creation ==TRUNCATE_EXISTING)?"TRUNCATE_EXISTING ":"", attributes);
349 /* Open a console for CONIN$ or CONOUT$ */
350 if (!strcmpiW(filename, coninW) || !strcmpiW(filename, conoutW))
352 ret = OpenConsoleW(filename, access, (sa && sa->bInheritHandle), creation);
353 goto done;
356 /* If the name starts with '\\?\', ignore the first 4 chars. */
357 if (!strncmpW(filename, bkslashes_with_question_markW, 4))
359 static const WCHAR uncW[] = {'U','N','C','\\',0};
360 filename += 4;
361 if (!strncmpiW(filename, uncW, 4))
363 FIXME("UNC name (%s) not supported.\n", debugstr_w(filename) );
364 SetLastError( ERROR_PATH_NOT_FOUND );
365 return INVALID_HANDLE_VALUE;
369 if (!strncmpW(filename, bkslashes_with_dotW, 4))
371 static const WCHAR pipeW[] = {'P','I','P','E','\\',0};
372 if(!strncmpiW(filename + 4, pipeW, 5))
374 TRACE("Opening a pipe: %s\n", debugstr_w(filename));
375 ret = FILE_OpenPipe( filename, access, sa );
376 goto done;
378 else if (isalphaW(filename[4]) && filename[5] == ':' && filename[6] == '\0')
380 const char *device = DRIVE_GetDevice( toupperW(filename[4]) - 'A' );
381 if (device)
383 ret = FILE_CreateFile( device, access, sharing, sa, creation,
384 attributes, template, TRUE, DRIVE_FIXED );
386 else
388 SetLastError( ERROR_ACCESS_DENIED );
389 ret = INVALID_HANDLE_VALUE;
391 goto done;
393 else if ((dosdev = RtlIsDosDeviceName_U( filename + 4 )))
395 dosdev += MAKELONG( 0, 4*sizeof(WCHAR) ); /* adjust position to start of filename */
397 else
399 ret = VXD_Open( filename+4, access, sa );
400 goto done;
403 else dosdev = RtlIsDosDeviceName_U( filename );
405 if (dosdev)
407 static const WCHAR conW[] = {'C','O','N',0};
408 WCHAR dev[5];
410 memcpy( dev, filename + HIWORD(dosdev)/sizeof(WCHAR), LOWORD(dosdev) );
411 dev[LOWORD(dosdev)/sizeof(WCHAR)] = 0;
413 TRACE("opening device %s\n", debugstr_w(dev) );
415 if (!strcmpiW( dev, conW ))
417 switch (access & (GENERIC_READ|GENERIC_WRITE))
419 case GENERIC_READ:
420 ret = OpenConsoleW(coninW, access, (sa && sa->bInheritHandle), creation);
421 goto done;
422 case GENERIC_WRITE:
423 ret = OpenConsoleW(conoutW, access, (sa && sa->bInheritHandle), creation);
424 goto done;
425 default:
426 FIXME("can't open CON read/write\n");
427 SetLastError( ERROR_FILE_NOT_FOUND );
428 return INVALID_HANDLE_VALUE;
432 ret = VOLUME_OpenDevice( dev, access, sharing, sa, attributes );
433 goto done;
436 /* If the name still starts with '\\', it's a UNC name. */
437 if (!strncmpW(filename, bkslashesW, 2))
439 ret = SMB_CreateFileW(filename, access, sharing, sa, creation, attributes, template );
440 goto done;
443 /* If the name contains a DOS wild card (* or ?), do no create a file */
444 if(strchrW(filename, '*') || strchrW(filename, '?'))
446 SetLastError(ERROR_BAD_PATHNAME);
447 return INVALID_HANDLE_VALUE;
450 /* check for filename, don't check for last entry if creating */
451 if (!DOSFS_GetFullName( filename,
452 (creation == OPEN_EXISTING) ||
453 (creation == TRUNCATE_EXISTING),
454 &full_name )) {
455 WARN("Unable to get full filename from %s (GLE %ld)\n",
456 debugstr_w(filename), GetLastError());
457 return INVALID_HANDLE_VALUE;
460 ret = FILE_CreateFile( full_name.long_name, access, sharing,
461 sa, creation, attributes, template,
462 DRIVE_GetFlags(full_name.drive) & DRIVE_FAIL_READ_ONLY,
463 GetDriveTypeW( full_name.short_name ) );
464 done:
465 if (!ret) ret = INVALID_HANDLE_VALUE;
466 TRACE("returning %p\n", ret);
467 return ret;
472 /*************************************************************************
473 * CreateFileA (KERNEL32.@)
475 HANDLE WINAPI CreateFileA( LPCSTR filename, DWORD access, DWORD sharing,
476 LPSECURITY_ATTRIBUTES sa, DWORD creation,
477 DWORD attributes, HANDLE template)
479 UNICODE_STRING filenameW;
480 HANDLE ret = INVALID_HANDLE_VALUE;
482 if (!filename)
484 SetLastError( ERROR_INVALID_PARAMETER );
485 return INVALID_HANDLE_VALUE;
488 if (RtlCreateUnicodeStringFromAsciiz(&filenameW, filename))
490 ret = CreateFileW(filenameW.Buffer, access, sharing, sa, creation,
491 attributes, template);
492 RtlFreeUnicodeString(&filenameW);
494 else
495 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
496 return ret;
500 /***********************************************************************
501 * FILE_FillInfo
503 * Fill a file information from a struct stat.
505 static void FILE_FillInfo( struct stat *st, BY_HANDLE_FILE_INFORMATION *info )
507 if (S_ISDIR(st->st_mode))
508 info->dwFileAttributes = FILE_ATTRIBUTE_DIRECTORY;
509 else
510 info->dwFileAttributes = FILE_ATTRIBUTE_ARCHIVE;
511 if (!(st->st_mode & S_IWUSR))
512 info->dwFileAttributes |= FILE_ATTRIBUTE_READONLY;
514 RtlSecondsSince1970ToTime( st->st_mtime, (LARGE_INTEGER *)&info->ftCreationTime );
515 RtlSecondsSince1970ToTime( st->st_mtime, (LARGE_INTEGER *)&info->ftLastWriteTime );
516 RtlSecondsSince1970ToTime( st->st_atime, (LARGE_INTEGER *)&info->ftLastAccessTime );
518 info->dwVolumeSerialNumber = 0; /* FIXME */
519 info->nFileSizeHigh = 0;
520 info->nFileSizeLow = 0;
521 if (!S_ISDIR(st->st_mode)) {
522 info->nFileSizeHigh = st->st_size >> 32;
523 info->nFileSizeLow = st->st_size & 0xffffffff;
525 info->nNumberOfLinks = st->st_nlink;
526 info->nFileIndexHigh = 0;
527 info->nFileIndexLow = st->st_ino;
531 /***********************************************************************
532 * get_show_dot_files_option
534 static BOOL get_show_dot_files_option(void)
536 static const WCHAR WineW[] = {'M','a','c','h','i','n','e','\\',
537 'S','o','f','t','w','a','r','e','\\',
538 'W','i','n','e','\\','W','i','n','e','\\',
539 'C','o','n','f','i','g','\\','W','i','n','e',0};
540 static const WCHAR ShowDotFilesW[] = {'S','h','o','w','D','o','t','F','i','l','e','s',0};
542 char tmp[80];
543 HKEY hkey;
544 DWORD dummy;
545 OBJECT_ATTRIBUTES attr;
546 UNICODE_STRING nameW;
547 BOOL ret = FALSE;
549 attr.Length = sizeof(attr);
550 attr.RootDirectory = 0;
551 attr.ObjectName = &nameW;
552 attr.Attributes = 0;
553 attr.SecurityDescriptor = NULL;
554 attr.SecurityQualityOfService = NULL;
555 RtlInitUnicodeString( &nameW, WineW );
557 if (!NtOpenKey( &hkey, KEY_ALL_ACCESS, &attr ))
559 RtlInitUnicodeString( &nameW, ShowDotFilesW );
560 if (!NtQueryValueKey( hkey, &nameW, KeyValuePartialInformation, tmp, sizeof(tmp), &dummy ))
562 WCHAR *str = (WCHAR *)((KEY_VALUE_PARTIAL_INFORMATION *)tmp)->Data;
563 ret = IS_OPTION_TRUE( str[0] );
565 NtClose( hkey );
567 return ret;
571 /***********************************************************************
572 * FILE_Stat
574 * Stat a Unix path name. Return TRUE if OK.
576 BOOL FILE_Stat( LPCSTR unixName, BY_HANDLE_FILE_INFORMATION *info, BOOL *is_symlink_ptr )
578 struct stat st;
579 int is_symlink;
580 LPCSTR p;
582 if (lstat( unixName, &st ) == -1)
584 FILE_SetDosError();
585 return FALSE;
587 is_symlink = S_ISLNK(st.st_mode);
588 if (is_symlink)
590 /* do a "real" stat to find out
591 about the type of the symlink destination */
592 if (stat( unixName, &st ) == -1)
594 FILE_SetDosError();
595 return FALSE;
599 /* fill in the information we gathered so far */
600 FILE_FillInfo( &st, info );
602 /* and now see if this is a hidden file, based on the name */
603 p = strrchr( unixName, '/');
604 p = p ? p + 1 : unixName;
605 if (*p == '.' && *(p+1) && (*(p+1) != '.' || *(p+2)))
607 static int show_dot_files = -1;
608 if (show_dot_files == -1)
609 show_dot_files = get_show_dot_files_option();
610 if (!show_dot_files)
611 info->dwFileAttributes |= FILE_ATTRIBUTE_HIDDEN;
613 if (is_symlink_ptr) *is_symlink_ptr = is_symlink;
614 return TRUE;
618 /***********************************************************************
619 * GetFileInformationByHandle (KERNEL32.@)
621 DWORD WINAPI GetFileInformationByHandle( HANDLE hFile,
622 BY_HANDLE_FILE_INFORMATION *info )
624 DWORD ret;
625 if (!info) return 0;
627 TRACE("%p\n", hFile);
629 SERVER_START_REQ( get_file_info )
631 req->handle = hFile;
632 if ((ret = !wine_server_call_err( req )))
634 /* FIXME: which file types are supported ?
635 * Serial ports (FILE_TYPE_CHAR) are not,
636 * and MSDN also says that pipes are not supported.
637 * FILE_TYPE_REMOTE seems to be supported according to
638 * MSDN q234741.txt */
639 if ((reply->type == FILE_TYPE_DISK) || (reply->type == FILE_TYPE_REMOTE))
641 RtlSecondsSince1970ToTime( reply->write_time, (LARGE_INTEGER *)&info->ftCreationTime );
642 RtlSecondsSince1970ToTime( reply->write_time, (LARGE_INTEGER *)&info->ftLastWriteTime );
643 RtlSecondsSince1970ToTime( reply->access_time, (LARGE_INTEGER *)&info->ftLastAccessTime );
644 info->dwFileAttributes = reply->attr;
645 info->dwVolumeSerialNumber = reply->serial;
646 info->nFileSizeHigh = reply->size_high;
647 info->nFileSizeLow = reply->size_low;
648 info->nNumberOfLinks = reply->links;
649 info->nFileIndexHigh = reply->index_high;
650 info->nFileIndexLow = reply->index_low;
652 else
654 SetLastError(ERROR_NOT_SUPPORTED);
655 ret = 0;
659 SERVER_END_REQ;
660 return ret;
664 /**************************************************************************
665 * GetFileAttributesW (KERNEL32.@)
667 DWORD WINAPI GetFileAttributesW( LPCWSTR name )
669 DOS_FULL_NAME full_name;
670 BY_HANDLE_FILE_INFORMATION info;
672 if (name == NULL)
674 SetLastError( ERROR_INVALID_PARAMETER );
675 return INVALID_FILE_ATTRIBUTES;
677 if (!DOSFS_GetFullName( name, TRUE, &full_name) )
678 return INVALID_FILE_ATTRIBUTES;
679 if (!FILE_Stat( full_name.long_name, &info, NULL ))
680 return INVALID_FILE_ATTRIBUTES;
681 return info.dwFileAttributes;
685 /**************************************************************************
686 * GetFileAttributesA (KERNEL32.@)
688 DWORD WINAPI GetFileAttributesA( LPCSTR name )
690 UNICODE_STRING nameW;
691 DWORD ret = INVALID_FILE_ATTRIBUTES;
693 if (!name)
695 SetLastError( ERROR_INVALID_PARAMETER );
696 return INVALID_FILE_ATTRIBUTES;
699 if (RtlCreateUnicodeStringFromAsciiz(&nameW, name))
701 ret = GetFileAttributesW(nameW.Buffer);
702 RtlFreeUnicodeString(&nameW);
704 else
705 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
706 return ret;
710 /**************************************************************************
711 * SetFileAttributesW (KERNEL32.@)
713 BOOL WINAPI SetFileAttributesW(LPCWSTR lpFileName, DWORD attributes)
715 struct stat buf;
716 DOS_FULL_NAME full_name;
718 if (!lpFileName)
720 SetLastError( ERROR_INVALID_PARAMETER );
721 return FALSE;
724 TRACE("(%s,%lx)\n", debugstr_w(lpFileName), attributes);
726 if (!DOSFS_GetFullName( lpFileName, TRUE, &full_name ))
727 return FALSE;
729 if(stat(full_name.long_name,&buf)==-1)
731 FILE_SetDosError();
732 return FALSE;
734 if (attributes & FILE_ATTRIBUTE_READONLY)
736 if(S_ISDIR(buf.st_mode))
737 /* FIXME */
738 WARN("FILE_ATTRIBUTE_READONLY ignored for directory.\n");
739 else
740 buf.st_mode &= ~0222; /* octal!, clear write permission bits */
741 attributes &= ~FILE_ATTRIBUTE_READONLY;
743 else
745 /* add write permission */
746 buf.st_mode |= (0600 | ((buf.st_mode & 044) >> 1)) & (~FILE_umask);
748 if (attributes & FILE_ATTRIBUTE_DIRECTORY)
750 if (!S_ISDIR(buf.st_mode))
751 FIXME("SetFileAttributes expected the file %s to be a directory\n",
752 debugstr_w(lpFileName));
753 attributes &= ~FILE_ATTRIBUTE_DIRECTORY;
755 attributes &= ~(FILE_ATTRIBUTE_NORMAL|FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_HIDDEN|
756 FILE_ATTRIBUTE_SYSTEM|FILE_ATTRIBUTE_TEMPORARY);
757 if (attributes)
758 FIXME("(%s):%lx attribute(s) not implemented.\n", debugstr_w(lpFileName), attributes);
759 if (-1==chmod(full_name.long_name,buf.st_mode))
761 if (GetDriveTypeW(lpFileName) == DRIVE_CDROM)
763 SetLastError( ERROR_ACCESS_DENIED );
764 return FALSE;
768 * FIXME: We don't return FALSE here because of differences between
769 * Linux and Windows privileges. Under Linux only the owner of
770 * the file is allowed to change file attributes. Under Windows,
771 * applications expect that if you can write to a file, you can also
772 * change its attributes (see GENERIC_WRITE). We could try to be
773 * clever here but that would break multi-user installations where
774 * users share read-only DLLs. This is because some installers like
775 * to change attributes of already installed DLLs.
777 FIXME("Couldn't set file attributes for existing file \"%s\".\n"
778 "Check permissions or set VFAT \"quiet\" mount flag\n", full_name.long_name);
780 return TRUE;
784 /**************************************************************************
785 * SetFileAttributesA (KERNEL32.@)
787 BOOL WINAPI SetFileAttributesA(LPCSTR lpFileName, DWORD attributes)
789 UNICODE_STRING filenameW;
790 BOOL ret = FALSE;
792 if (!lpFileName)
794 SetLastError( ERROR_INVALID_PARAMETER );
795 return FALSE;
798 if (RtlCreateUnicodeStringFromAsciiz(&filenameW, lpFileName))
800 ret = SetFileAttributesW(filenameW.Buffer, attributes);
801 RtlFreeUnicodeString(&filenameW);
803 else
804 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
805 return ret;
809 /******************************************************************************
810 * GetCompressedFileSizeA [KERNEL32.@]
812 DWORD WINAPI GetCompressedFileSizeA(
813 LPCSTR lpFileName,
814 LPDWORD lpFileSizeHigh)
816 UNICODE_STRING filenameW;
817 DWORD ret;
819 if (RtlCreateUnicodeStringFromAsciiz(&filenameW, lpFileName))
821 ret = GetCompressedFileSizeW(filenameW.Buffer, lpFileSizeHigh);
822 RtlFreeUnicodeString(&filenameW);
824 else
826 ret = INVALID_FILE_SIZE;
827 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
829 return ret;
833 /******************************************************************************
834 * GetCompressedFileSizeW [KERNEL32.@]
836 * RETURNS
837 * Success: Low-order doubleword of number of bytes
838 * Failure: INVALID_FILE_SIZE
840 DWORD WINAPI GetCompressedFileSizeW(
841 LPCWSTR lpFileName, /* [in] Pointer to name of file */
842 LPDWORD lpFileSizeHigh) /* [out] Receives high-order doubleword of size */
844 DOS_FULL_NAME full_name;
845 struct stat st;
846 DWORD low;
848 TRACE("(%s,%p)\n",debugstr_w(lpFileName),lpFileSizeHigh);
850 if (!DOSFS_GetFullName( lpFileName, TRUE, &full_name )) return INVALID_FILE_SIZE;
851 if (stat(full_name.long_name, &st) != 0)
853 FILE_SetDosError();
854 return INVALID_FILE_SIZE;
856 #if HAVE_STRUCT_STAT_ST_BLOCKS
857 /* blocks are 512 bytes long */
858 if (lpFileSizeHigh) *lpFileSizeHigh = (st.st_blocks >> 23);
859 low = (DWORD)(st.st_blocks << 9);
860 #else
861 if (lpFileSizeHigh) *lpFileSizeHigh = (st.st_size >> 32);
862 low = (DWORD)st.st_size;
863 #endif
864 return low;
868 /***********************************************************************
869 * GetFileTime (KERNEL32.@)
871 BOOL WINAPI GetFileTime( HANDLE hFile, FILETIME *lpCreationTime,
872 FILETIME *lpLastAccessTime,
873 FILETIME *lpLastWriteTime )
875 BY_HANDLE_FILE_INFORMATION info;
876 if (!GetFileInformationByHandle( hFile, &info )) return FALSE;
877 if (lpCreationTime) *lpCreationTime = info.ftCreationTime;
878 if (lpLastAccessTime) *lpLastAccessTime = info.ftLastAccessTime;
879 if (lpLastWriteTime) *lpLastWriteTime = info.ftLastWriteTime;
880 return TRUE;
884 /***********************************************************************
885 * GetTempFileNameA (KERNEL32.@)
887 UINT WINAPI GetTempFileNameA( LPCSTR path, LPCSTR prefix, UINT unique,
888 LPSTR buffer)
890 UNICODE_STRING pathW, prefixW;
891 WCHAR bufferW[MAX_PATH];
892 UINT ret;
894 if ( !path || !prefix || !buffer )
896 SetLastError( ERROR_INVALID_PARAMETER );
897 return 0;
900 RtlCreateUnicodeStringFromAsciiz(&pathW, path);
901 RtlCreateUnicodeStringFromAsciiz(&prefixW, prefix);
903 ret = GetTempFileNameW(pathW.Buffer, prefixW.Buffer, unique, bufferW);
904 if (ret)
905 WideCharToMultiByte(CP_ACP, 0, bufferW, -1, buffer, MAX_PATH, NULL, NULL);
907 RtlFreeUnicodeString(&pathW);
908 RtlFreeUnicodeString(&prefixW);
909 return ret;
912 /***********************************************************************
913 * GetTempFileNameW (KERNEL32.@)
915 UINT WINAPI GetTempFileNameW( LPCWSTR path, LPCWSTR prefix, UINT unique,
916 LPWSTR buffer )
918 static const WCHAR formatW[] = {'%','x','.','t','m','p',0};
920 DOS_FULL_NAME full_name;
921 int i;
922 LPWSTR p;
924 if ( !path || !prefix || !buffer )
926 SetLastError( ERROR_INVALID_PARAMETER );
927 return 0;
930 strcpyW( buffer, path );
931 p = buffer + strlenW(buffer);
933 /* add a \, if there isn't one */
934 if ((p == buffer) || (p[-1] != '\\')) *p++ = '\\';
936 for (i = 3; (i > 0) && (*prefix); i--) *p++ = *prefix++;
938 unique &= 0xffff;
940 if (unique) sprintfW( p, formatW, unique );
941 else
943 /* get a "random" unique number and try to create the file */
944 HANDLE handle;
945 UINT num = GetTickCount() & 0xffff;
947 if (!num) num = 1;
948 unique = num;
951 sprintfW( p, formatW, unique );
952 handle = CreateFileW( buffer, GENERIC_WRITE, 0, NULL,
953 CREATE_NEW, FILE_ATTRIBUTE_NORMAL, 0 );
954 if (handle != INVALID_HANDLE_VALUE)
955 { /* We created it */
956 TRACE("created %s\n", debugstr_w(buffer) );
957 CloseHandle( handle );
958 break;
960 if (GetLastError() != ERROR_FILE_EXISTS &&
961 GetLastError() != ERROR_SHARING_VIOLATION)
962 break; /* No need to go on */
963 if (!(++unique & 0xffff)) unique = 1;
964 } while (unique != num);
967 /* Get the full path name */
969 if (DOSFS_GetFullName( buffer, FALSE, &full_name ))
971 char *slash;
972 /* Check if we have write access in the directory */
973 if ((slash = strrchr( full_name.long_name, '/' ))) *slash = '\0';
974 if (access( full_name.long_name, W_OK ) == -1)
975 WARN("returns %s, which doesn't seem to be writeable.\n",
976 debugstr_w(buffer) );
978 TRACE("returning %s\n", debugstr_w(buffer) );
979 return unique;
983 /******************************************************************
984 * FILE_ReadWriteApc (internal)
988 static void WINAPI FILE_ReadWriteApc(void* apc_user, PIO_STATUS_BLOCK io_status, ULONG len)
990 LPOVERLAPPED_COMPLETION_ROUTINE cr = (LPOVERLAPPED_COMPLETION_ROUTINE)apc_user;
992 cr(RtlNtStatusToDosError(io_status->u.Status), len, (LPOVERLAPPED)io_status);
995 /***********************************************************************
996 * ReadFileEx (KERNEL32.@)
998 BOOL WINAPI ReadFileEx(HANDLE hFile, LPVOID buffer, DWORD bytesToRead,
999 LPOVERLAPPED overlapped,
1000 LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine)
1002 LARGE_INTEGER offset;
1003 NTSTATUS status;
1004 PIO_STATUS_BLOCK io_status;
1006 if (!overlapped)
1008 SetLastError(ERROR_INVALID_PARAMETER);
1009 return FALSE;
1012 offset.u.LowPart = overlapped->Offset;
1013 offset.u.HighPart = overlapped->OffsetHigh;
1014 io_status = (PIO_STATUS_BLOCK)overlapped;
1015 io_status->u.Status = STATUS_PENDING;
1017 status = NtReadFile(hFile, NULL, FILE_ReadWriteApc, lpCompletionRoutine,
1018 io_status, buffer, bytesToRead, &offset, NULL);
1020 if (status)
1022 SetLastError( RtlNtStatusToDosError(status) );
1023 return FALSE;
1025 return TRUE;
1028 /***********************************************************************
1029 * ReadFile (KERNEL32.@)
1031 BOOL WINAPI ReadFile( HANDLE hFile, LPVOID buffer, DWORD bytesToRead,
1032 LPDWORD bytesRead, LPOVERLAPPED overlapped )
1034 LARGE_INTEGER offset;
1035 PLARGE_INTEGER poffset = NULL;
1036 IO_STATUS_BLOCK iosb;
1037 PIO_STATUS_BLOCK io_status = &iosb;
1038 HANDLE hEvent = 0;
1039 NTSTATUS status;
1041 TRACE("%p %p %ld %p %p\n", hFile, buffer, bytesToRead,
1042 bytesRead, overlapped );
1044 if (bytesRead) *bytesRead = 0; /* Do this before anything else */
1045 if (!bytesToRead) return TRUE;
1047 if (IsBadReadPtr(buffer, bytesToRead))
1049 SetLastError(ERROR_WRITE_FAULT); /* FIXME */
1050 return FALSE;
1052 if (is_console_handle(hFile))
1053 return ReadConsoleA(hFile, buffer, bytesToRead, bytesRead, NULL);
1055 if (overlapped != NULL)
1057 offset.u.LowPart = overlapped->Offset;
1058 offset.u.HighPart = overlapped->OffsetHigh;
1059 poffset = &offset;
1060 hEvent = overlapped->hEvent;
1061 io_status = (PIO_STATUS_BLOCK)overlapped;
1063 io_status->u.Status = STATUS_PENDING;
1064 io_status->Information = 0;
1066 status = NtReadFile(hFile, hEvent, NULL, NULL, io_status, buffer, bytesToRead, poffset, NULL);
1068 if (status != STATUS_PENDING && bytesRead)
1069 *bytesRead = io_status->Information;
1071 if (status && status != STATUS_END_OF_FILE)
1073 SetLastError( RtlNtStatusToDosError(status) );
1074 return FALSE;
1076 return TRUE;
1080 /***********************************************************************
1081 * WriteFileEx (KERNEL32.@)
1083 BOOL WINAPI WriteFileEx(HANDLE hFile, LPCVOID buffer, DWORD bytesToWrite,
1084 LPOVERLAPPED overlapped,
1085 LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine)
1087 LARGE_INTEGER offset;
1088 NTSTATUS status;
1089 PIO_STATUS_BLOCK io_status;
1091 TRACE("%p %p %ld %p %p\n",
1092 hFile, buffer, bytesToWrite, overlapped, lpCompletionRoutine);
1094 if (overlapped == NULL)
1096 SetLastError(ERROR_INVALID_PARAMETER);
1097 return FALSE;
1099 offset.u.LowPart = overlapped->Offset;
1100 offset.u.HighPart = overlapped->OffsetHigh;
1102 io_status = (PIO_STATUS_BLOCK)overlapped;
1103 io_status->u.Status = STATUS_PENDING;
1105 status = NtWriteFile(hFile, NULL, FILE_ReadWriteApc, lpCompletionRoutine,
1106 io_status, buffer, bytesToWrite, &offset, NULL);
1108 if (status) SetLastError( RtlNtStatusToDosError(status) );
1109 return !status;
1112 /***********************************************************************
1113 * WriteFile (KERNEL32.@)
1115 BOOL WINAPI WriteFile( HANDLE hFile, LPCVOID buffer, DWORD bytesToWrite,
1116 LPDWORD bytesWritten, LPOVERLAPPED overlapped )
1118 HANDLE hEvent = NULL;
1119 LARGE_INTEGER offset;
1120 PLARGE_INTEGER poffset = NULL;
1121 NTSTATUS status;
1122 IO_STATUS_BLOCK iosb;
1123 PIO_STATUS_BLOCK piosb = &iosb;
1125 TRACE("%p %p %ld %p %p\n",
1126 hFile, buffer, bytesToWrite, bytesWritten, overlapped );
1128 if (is_console_handle(hFile))
1129 return WriteConsoleA(hFile, buffer, bytesToWrite, bytesWritten, NULL);
1131 if (IsBadReadPtr(buffer, bytesToWrite))
1133 SetLastError(ERROR_READ_FAULT); /* FIXME */
1134 return FALSE;
1137 if (overlapped)
1139 offset.u.LowPart = overlapped->Offset;
1140 offset.u.HighPart = overlapped->OffsetHigh;
1141 poffset = &offset;
1142 hEvent = overlapped->hEvent;
1143 piosb = (PIO_STATUS_BLOCK)overlapped;
1145 piosb->u.Status = STATUS_PENDING;
1146 piosb->Information = 0;
1148 status = NtWriteFile(hFile, hEvent, NULL, NULL, piosb,
1149 buffer, bytesToWrite, poffset, NULL);
1150 if (status)
1152 SetLastError( RtlNtStatusToDosError(status) );
1153 return FALSE;
1155 if (bytesWritten) *bytesWritten = piosb->Information;
1157 return TRUE;
1161 /***********************************************************************
1162 * SetFilePointer (KERNEL32.@)
1164 DWORD WINAPI SetFilePointer( HANDLE hFile, LONG distance, LONG *highword,
1165 DWORD method )
1167 DWORD ret = INVALID_SET_FILE_POINTER;
1169 TRACE("handle %p offset %ld high %ld origin %ld\n",
1170 hFile, distance, highword?*highword:0, method );
1172 SERVER_START_REQ( set_file_pointer )
1174 req->handle = hFile;
1175 req->low = distance;
1176 req->high = highword ? *highword : (distance >= 0) ? 0 : -1;
1177 /* FIXME: assumes 1:1 mapping between Windows and Unix seek constants */
1178 req->whence = method;
1179 SetLastError( 0 );
1180 if (!wine_server_call_err( req ))
1182 ret = reply->new_low;
1183 if (highword) *highword = reply->new_high;
1186 SERVER_END_REQ;
1187 return ret;
1191 /*************************************************************************
1192 * SetHandleCount (KERNEL32.@)
1194 UINT WINAPI SetHandleCount( UINT count )
1196 return min( 256, count );
1200 /**************************************************************************
1201 * SetEndOfFile (KERNEL32.@)
1203 BOOL WINAPI SetEndOfFile( HANDLE hFile )
1205 BOOL ret;
1206 SERVER_START_REQ( truncate_file )
1208 req->handle = hFile;
1209 ret = !wine_server_call_err( req );
1211 SERVER_END_REQ;
1212 return ret;
1216 /***********************************************************************
1217 * DeleteFileW (KERNEL32.@)
1219 BOOL WINAPI DeleteFileW( LPCWSTR path )
1221 DOS_FULL_NAME full_name;
1222 HANDLE hFile;
1224 TRACE("%s\n", debugstr_w(path) );
1225 if (!path || !*path)
1227 SetLastError(ERROR_PATH_NOT_FOUND);
1228 return FALSE;
1230 if (RtlIsDosDeviceName_U( path ))
1232 WARN("cannot remove DOS device %s!\n", debugstr_w(path));
1233 SetLastError( ERROR_FILE_NOT_FOUND );
1234 return FALSE;
1237 if (!DOSFS_GetFullName( path, TRUE, &full_name )) return FALSE;
1239 /* check if we are allowed to delete the source */
1240 hFile = FILE_CreateFile( full_name.long_name, GENERIC_READ|GENERIC_WRITE, 0,
1241 NULL, OPEN_EXISTING, 0, 0, TRUE,
1242 GetDriveTypeW( full_name.short_name ) );
1243 if (!hFile) return FALSE;
1245 if (unlink( full_name.long_name ) == -1)
1247 FILE_SetDosError();
1248 CloseHandle(hFile);
1249 return FALSE;
1251 CloseHandle(hFile);
1252 return TRUE;
1256 /***********************************************************************
1257 * DeleteFileA (KERNEL32.@)
1259 BOOL WINAPI DeleteFileA( LPCSTR path )
1261 UNICODE_STRING pathW;
1262 BOOL ret = FALSE;
1264 if (!path)
1266 SetLastError(ERROR_INVALID_PARAMETER);
1267 return FALSE;
1270 if (RtlCreateUnicodeStringFromAsciiz(&pathW, path))
1272 ret = DeleteFileW(pathW.Buffer);
1273 RtlFreeUnicodeString(&pathW);
1275 else
1276 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1277 return ret;
1281 /***********************************************************************
1282 * GetFileType (KERNEL32.@)
1284 DWORD WINAPI GetFileType( HANDLE hFile )
1286 DWORD ret = FILE_TYPE_UNKNOWN;
1288 if (is_console_handle( hFile ))
1289 return FILE_TYPE_CHAR;
1291 SERVER_START_REQ( get_file_info )
1293 req->handle = hFile;
1294 if (!wine_server_call_err( req )) ret = reply->type;
1296 SERVER_END_REQ;
1297 return ret;
1301 /* check if a file name is for an executable file (.exe or .com) */
1302 inline static BOOL is_executable( const char *name )
1304 int len = strlen(name);
1306 if (len < 4) return FALSE;
1307 return (!strcasecmp( name + len - 4, ".exe" ) ||
1308 !strcasecmp( name + len - 4, ".com" ));
1312 /***********************************************************************
1313 * FILE_AddBootRenameEntry
1315 * Adds an entry to the registry that is loaded when windows boots and
1316 * checks if there are some files to be removed or renamed/moved.
1317 * <fn1> has to be valid and <fn2> may be NULL. If both pointers are
1318 * non-NULL then the file is moved, otherwise it is deleted. The
1319 * entry of the registrykey is always appended with two zero
1320 * terminated strings. If <fn2> is NULL then the second entry is
1321 * simply a single 0-byte. Otherwise the second filename goes
1322 * there. The entries are prepended with \??\ before the path and the
1323 * second filename gets also a '!' as the first character if
1324 * MOVEFILE_REPLACE_EXISTING is set. After the final string another
1325 * 0-byte follows to indicate the end of the strings.
1326 * i.e.:
1327 * \??\D:\test\file1[0]
1328 * !\??\D:\test\file1_renamed[0]
1329 * \??\D:\Test|delete[0]
1330 * [0] <- file is to be deleted, second string empty
1331 * \??\D:\test\file2[0]
1332 * !\??\D:\test\file2_renamed[0]
1333 * [0] <- indicates end of strings
1335 * or:
1336 * \??\D:\test\file1[0]
1337 * !\??\D:\test\file1_renamed[0]
1338 * \??\D:\Test|delete[0]
1339 * [0] <- file is to be deleted, second string empty
1340 * [0] <- indicates end of strings
1343 static BOOL FILE_AddBootRenameEntry( LPCWSTR fn1, LPCWSTR fn2, DWORD flags )
1345 static const WCHAR PreString[] = {'\\','?','?','\\',0};
1346 static const WCHAR ValueName[] = {'P','e','n','d','i','n','g',
1347 'F','i','l','e','R','e','n','a','m','e',
1348 'O','p','e','r','a','t','i','o','n','s',0};
1349 static const WCHAR SessionW[] = {'M','a','c','h','i','n','e','\\',
1350 'S','y','s','t','e','m','\\',
1351 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
1352 'C','o','n','t','r','o','l','\\',
1353 'S','e','s','s','i','o','n',' ','M','a','n','a','g','e','r',0};
1354 static const int info_size = FIELD_OFFSET( KEY_VALUE_PARTIAL_INFORMATION, Data );
1356 OBJECT_ATTRIBUTES attr;
1357 UNICODE_STRING nameW;
1358 KEY_VALUE_PARTIAL_INFORMATION *info;
1359 BOOL rc = FALSE;
1360 HKEY Reboot = 0;
1361 DWORD len0, len1, len2;
1362 DWORD DataSize = 0;
1363 BYTE *Buffer = NULL;
1364 WCHAR *p;
1366 attr.Length = sizeof(attr);
1367 attr.RootDirectory = 0;
1368 attr.ObjectName = &nameW;
1369 attr.Attributes = 0;
1370 attr.SecurityDescriptor = NULL;
1371 attr.SecurityQualityOfService = NULL;
1372 RtlInitUnicodeString( &nameW, SessionW );
1374 if (NtCreateKey( &Reboot, KEY_ALL_ACCESS, &attr, 0, NULL, 0, NULL ) != STATUS_SUCCESS)
1376 WARN("Error creating key for reboot managment [%s]\n",
1377 "SYSTEM\\CurrentControlSet\\Control\\Session Manager");
1378 return FALSE;
1381 len0 = strlenW(PreString);
1382 len1 = strlenW(fn1) + len0 + 1;
1383 if (fn2)
1385 len2 = strlenW(fn2) + len0 + 1;
1386 if (flags & MOVEFILE_REPLACE_EXISTING) len2++; /* Plus 1 because of the leading '!' */
1388 else len2 = 1; /* minimum is the 0 characters for the empty second string */
1390 /* convert characters to bytes */
1391 len0 *= sizeof(WCHAR);
1392 len1 *= sizeof(WCHAR);
1393 len2 *= sizeof(WCHAR);
1395 RtlInitUnicodeString( &nameW, ValueName );
1397 /* First we check if the key exists and if so how many bytes it already contains. */
1398 if (NtQueryValueKey( Reboot, &nameW, KeyValuePartialInformation,
1399 NULL, 0, &DataSize ) == STATUS_BUFFER_OVERFLOW)
1401 if (!(Buffer = HeapAlloc( GetProcessHeap(), 0, DataSize + len1 + len2 + sizeof(WCHAR) )))
1402 goto Quit;
1403 if (NtQueryValueKey( Reboot, &nameW, KeyValuePartialInformation,
1404 Buffer, DataSize, &DataSize )) goto Quit;
1405 info = (KEY_VALUE_PARTIAL_INFORMATION *)Buffer;
1406 if (info->Type != REG_MULTI_SZ) goto Quit;
1407 if (DataSize > sizeof(info)) DataSize -= sizeof(WCHAR); /* remove terminating null (will be added back later) */
1409 else
1411 DataSize = info_size;
1412 if (!(Buffer = HeapAlloc( GetProcessHeap(), 0, DataSize + len1 + len2 + sizeof(WCHAR) )))
1413 goto Quit;
1416 p = (WCHAR *)(Buffer + DataSize);
1417 strcpyW( p, PreString );
1418 strcatW( p, fn1 );
1419 DataSize += len1;
1420 if (fn2)
1422 p = (WCHAR *)(Buffer + DataSize);
1423 if (flags & MOVEFILE_REPLACE_EXISTING)
1424 *p++ = '!';
1425 strcpyW( p, PreString );
1426 strcatW( p, fn2 );
1427 DataSize += len2;
1429 else
1431 p = (WCHAR *)(Buffer + DataSize);
1432 *p = 0;
1433 DataSize += sizeof(WCHAR);
1436 /* add final null */
1437 p = (WCHAR *)(Buffer + DataSize);
1438 *p = 0;
1439 DataSize += sizeof(WCHAR);
1441 rc = !NtSetValueKey(Reboot, &nameW, 0, REG_MULTI_SZ, Buffer + info_size, DataSize - info_size);
1443 Quit:
1444 if (Reboot) NtClose(Reboot);
1445 if (Buffer) HeapFree( GetProcessHeap(), 0, Buffer );
1446 return(rc);
1450 /**************************************************************************
1451 * MoveFileExW (KERNEL32.@)
1453 BOOL WINAPI MoveFileExW( LPCWSTR fn1, LPCWSTR fn2, DWORD flag )
1455 DOS_FULL_NAME full_name1, full_name2;
1456 HANDLE hFile;
1457 DWORD attr = INVALID_FILE_ATTRIBUTES;
1459 TRACE("(%s,%s,%04lx)\n", debugstr_w(fn1), debugstr_w(fn2), flag);
1461 /* FIXME: <Gerhard W. Gruber>sparhawk@gmx.at
1462 In case of W9x and lesser this function should return 120 (ERROR_CALL_NOT_IMPLEMENTED)
1463 to be really compatible. Most programs won't have any problems though. In case
1464 you encounter one, this is what you should return here. I don't know what's up
1465 with NT 3.5. Is this function available there or not?
1466 Does anybody really care about 3.5? :)
1469 /* Filename1 has to be always set to a valid path. Filename2 may be NULL
1470 if the source file has to be deleted.
1472 if (!fn1) {
1473 SetLastError(ERROR_INVALID_PARAMETER);
1474 return FALSE;
1477 /* This function has to be run through in order to process the name properly.
1478 If the BOOTDELAY flag is set, the file doesn't need to exist though. At least
1479 that is the behaviour on NT 4.0. The operation accepts the filenames as
1480 they are given but it can't reply with a reasonable returncode. Success
1481 means in that case success for entering the values into the registry.
1483 if(!DOSFS_GetFullName( fn1, TRUE, &full_name1 ))
1485 if(!(flag & MOVEFILE_DELAY_UNTIL_REBOOT))
1486 return FALSE;
1489 if (fn2) /* !fn2 means delete fn1 */
1491 if (DOSFS_GetFullName( fn2, TRUE, &full_name2 ))
1493 if(!(flag & MOVEFILE_DELAY_UNTIL_REBOOT))
1495 /* target exists, check if we may overwrite */
1496 if (!(flag & MOVEFILE_REPLACE_EXISTING))
1498 SetLastError( ERROR_ALREADY_EXISTS );
1499 return FALSE;
1503 else
1505 if (!DOSFS_GetFullName( fn2, FALSE, &full_name2 ))
1507 if(!(flag & MOVEFILE_DELAY_UNTIL_REBOOT))
1508 return FALSE;
1512 /* Source name and target path are valid */
1514 if (flag & MOVEFILE_DELAY_UNTIL_REBOOT)
1516 return FILE_AddBootRenameEntry( fn1, fn2, flag );
1519 attr = GetFileAttributesW( fn1 );
1520 if ( attr == INVALID_FILE_ATTRIBUTES ) return FALSE;
1522 /* check if we are allowed to rename the source */
1523 hFile = FILE_CreateFile( full_name1.long_name, 0, 0,
1524 NULL, OPEN_EXISTING, 0, 0, TRUE,
1525 GetDriveTypeW( full_name1.short_name ) );
1526 if (!hFile)
1528 if (GetLastError() != ERROR_ACCESS_DENIED) return FALSE;
1529 if ( !(attr & FILE_ATTRIBUTE_DIRECTORY) ) return FALSE;
1530 /* if it's a directory we can continue */
1532 else CloseHandle(hFile);
1534 /* check, if we are allowed to delete the destination,
1535 ** (but the file not being there is fine) */
1536 hFile = FILE_CreateFile( full_name2.long_name, GENERIC_READ|GENERIC_WRITE, 0,
1537 NULL, OPEN_EXISTING, 0, 0, TRUE,
1538 GetDriveTypeW( full_name2.short_name ) );
1539 if(!hFile && GetLastError() != ERROR_FILE_NOT_FOUND) return FALSE;
1540 CloseHandle(hFile);
1542 if (full_name1.drive != full_name2.drive)
1544 if (!(flag & MOVEFILE_COPY_ALLOWED))
1546 SetLastError( ERROR_NOT_SAME_DEVICE );
1547 return FALSE;
1549 else if ( attr & FILE_ATTRIBUTE_DIRECTORY )
1551 /* Strange, but that's what Windows returns */
1552 SetLastError ( ERROR_ACCESS_DENIED );
1553 return FALSE;
1556 if (rename( full_name1.long_name, full_name2.long_name ) == -1)
1557 /* Try copy/delete unless it's a directory. */
1558 /* FIXME: This does not handle the (unlikely) case that the two locations
1559 are on the same Wine drive, but on different Unix file systems. */
1561 if ( attr & FILE_ATTRIBUTE_DIRECTORY )
1563 FILE_SetDosError();
1564 return FALSE;
1566 else
1568 if ( ! CopyFileW( fn1, fn2, !(flag & MOVEFILE_REPLACE_EXISTING) ))
1569 return FALSE;
1570 if ( ! DeleteFileW ( fn1 ) )
1571 return FALSE;
1574 if (is_executable( full_name1.long_name ) != is_executable( full_name2.long_name ))
1576 struct stat fstat;
1577 if (stat( full_name2.long_name, &fstat ) != -1)
1579 if (is_executable( full_name2.long_name ))
1580 /* set executable bit where read bit is set */
1581 fstat.st_mode |= (fstat.st_mode & 0444) >> 2;
1582 else
1583 fstat.st_mode &= ~0111;
1584 chmod( full_name2.long_name, fstat.st_mode );
1587 return TRUE;
1589 else /* fn2 == NULL means delete source */
1591 if (flag & MOVEFILE_DELAY_UNTIL_REBOOT)
1593 if (flag & MOVEFILE_COPY_ALLOWED) {
1594 WARN("Illegal flag\n");
1595 SetLastError( ERROR_GEN_FAILURE );
1596 return FALSE;
1599 return FILE_AddBootRenameEntry( fn1, NULL, flag );
1602 if (unlink( full_name1.long_name ) == -1)
1604 FILE_SetDosError();
1605 return FALSE;
1607 return TRUE; /* successfully deleted */
1611 /**************************************************************************
1612 * MoveFileExA (KERNEL32.@)
1614 BOOL WINAPI MoveFileExA( LPCSTR fn1, LPCSTR fn2, DWORD flag )
1616 UNICODE_STRING fn1W, fn2W;
1617 BOOL ret;
1619 if (!fn1)
1621 SetLastError(ERROR_INVALID_PARAMETER);
1622 return FALSE;
1625 RtlCreateUnicodeStringFromAsciiz(&fn1W, fn1);
1626 if (fn2) RtlCreateUnicodeStringFromAsciiz(&fn2W, fn2);
1627 else fn2W.Buffer = NULL;
1629 ret = MoveFileExW( fn1W.Buffer, fn2W.Buffer, flag );
1631 RtlFreeUnicodeString(&fn1W);
1632 RtlFreeUnicodeString(&fn2W);
1633 return ret;
1637 /**************************************************************************
1638 * MoveFileW (KERNEL32.@)
1640 * Move file or directory
1642 BOOL WINAPI MoveFileW( LPCWSTR fn1, LPCWSTR fn2 )
1644 return MoveFileExW( fn1, fn2, MOVEFILE_COPY_ALLOWED );
1648 /**************************************************************************
1649 * MoveFileA (KERNEL32.@)
1651 BOOL WINAPI MoveFileA( LPCSTR fn1, LPCSTR fn2 )
1653 return MoveFileExA( fn1, fn2, MOVEFILE_COPY_ALLOWED );
1657 /**************************************************************************
1658 * CopyFileW (KERNEL32.@)
1660 BOOL WINAPI CopyFileW( LPCWSTR source, LPCWSTR dest, BOOL fail_if_exists )
1662 HANDLE h1, h2;
1663 BY_HANDLE_FILE_INFORMATION info;
1664 DWORD count;
1665 BOOL ret = FALSE;
1666 char buffer[2048];
1668 if (!source || !dest)
1670 SetLastError(ERROR_INVALID_PARAMETER);
1671 return FALSE;
1674 TRACE("%s -> %s\n", debugstr_w(source), debugstr_w(dest));
1676 if ((h1 = CreateFileW(source, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE,
1677 NULL, OPEN_EXISTING, 0, 0)) == INVALID_HANDLE_VALUE)
1679 WARN("Unable to open source %s\n", debugstr_w(source));
1680 return FALSE;
1683 if (!GetFileInformationByHandle( h1, &info ))
1685 WARN("GetFileInformationByHandle returned error for %s\n", debugstr_w(source));
1686 CloseHandle( h1 );
1687 return FALSE;
1690 if ((h2 = CreateFileW( dest, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
1691 fail_if_exists ? CREATE_NEW : CREATE_ALWAYS,
1692 info.dwFileAttributes, h1 )) == INVALID_HANDLE_VALUE)
1694 WARN("Unable to open dest %s\n", debugstr_w(dest));
1695 CloseHandle( h1 );
1696 return FALSE;
1699 while (ReadFile( h1, buffer, sizeof(buffer), &count, NULL ) && count)
1701 char *p = buffer;
1702 while (count != 0)
1704 DWORD res;
1705 if (!WriteFile( h2, p, count, &res, NULL ) || !res) goto done;
1706 p += res;
1707 count -= res;
1710 ret = TRUE;
1711 done:
1712 CloseHandle( h1 );
1713 CloseHandle( h2 );
1714 return ret;
1718 /**************************************************************************
1719 * CopyFileA (KERNEL32.@)
1721 BOOL WINAPI CopyFileA( LPCSTR source, LPCSTR dest, BOOL fail_if_exists)
1723 UNICODE_STRING sourceW, destW;
1724 BOOL ret;
1726 if (!source || !dest)
1728 SetLastError(ERROR_INVALID_PARAMETER);
1729 return FALSE;
1732 RtlCreateUnicodeStringFromAsciiz(&sourceW, source);
1733 RtlCreateUnicodeStringFromAsciiz(&destW, dest);
1735 ret = CopyFileW(sourceW.Buffer, destW.Buffer, fail_if_exists);
1737 RtlFreeUnicodeString(&sourceW);
1738 RtlFreeUnicodeString(&destW);
1739 return ret;
1743 /**************************************************************************
1744 * CopyFileExW (KERNEL32.@)
1746 * This implementation ignores most of the extra parameters passed-in into
1747 * the "ex" version of the method and calls the CopyFile method.
1748 * It will have to be fixed eventually.
1750 BOOL WINAPI CopyFileExW(LPCWSTR sourceFilename, LPCWSTR destFilename,
1751 LPPROGRESS_ROUTINE progressRoutine, LPVOID appData,
1752 LPBOOL cancelFlagPointer, DWORD copyFlags)
1755 * Interpret the only flag that CopyFile can interpret.
1757 return CopyFileW(sourceFilename, destFilename, (copyFlags & COPY_FILE_FAIL_IF_EXISTS) != 0);
1761 /**************************************************************************
1762 * CopyFileExA (KERNEL32.@)
1764 BOOL WINAPI CopyFileExA(LPCSTR sourceFilename, LPCSTR destFilename,
1765 LPPROGRESS_ROUTINE progressRoutine, LPVOID appData,
1766 LPBOOL cancelFlagPointer, DWORD copyFlags)
1768 UNICODE_STRING sourceW, destW;
1769 BOOL ret;
1771 if (!sourceFilename || !destFilename)
1773 SetLastError(ERROR_INVALID_PARAMETER);
1774 return FALSE;
1777 RtlCreateUnicodeStringFromAsciiz(&sourceW, sourceFilename);
1778 RtlCreateUnicodeStringFromAsciiz(&destW, destFilename);
1780 ret = CopyFileExW(sourceW.Buffer, destW.Buffer, progressRoutine, appData,
1781 cancelFlagPointer, copyFlags);
1783 RtlFreeUnicodeString(&sourceW);
1784 RtlFreeUnicodeString(&destW);
1785 return ret;
1789 /***********************************************************************
1790 * SetFileTime (KERNEL32.@)
1792 BOOL WINAPI SetFileTime( HANDLE hFile,
1793 const FILETIME *ctime,
1794 const FILETIME *atime,
1795 const FILETIME *mtime )
1797 #ifdef HAVE_FUTIMES
1798 BOOL ret = FALSE;
1799 NTSTATUS status;
1800 int fd;
1801 ULONGLONG sec, nsec;
1803 if (!(status = wine_server_handle_to_fd( hFile, GENERIC_WRITE, &fd, NULL, NULL )))
1805 struct timeval tv[2];
1807 if (!atime || !mtime)
1809 struct stat st;
1811 tv[0].tv_sec = tv[0].tv_usec = 0;
1812 tv[1].tv_sec = tv[1].tv_usec = 0;
1813 if (!fstat( fd, &st ))
1815 tv[0].tv_sec = st.st_atime;
1816 tv[1].tv_sec = st.st_mtime;
1819 if (atime)
1821 sec = ((ULONGLONG)atime->dwHighDateTime << 32) | atime->dwLowDateTime;
1822 sec = RtlLargeIntegerDivide( sec, 10000000, &nsec );
1823 tv[0].tv_sec = sec - SECS_1601_TO_1970;
1824 tv[0].tv_usec = (UINT)nsec / 10;
1826 if (mtime)
1828 sec = ((ULONGLONG)mtime->dwHighDateTime << 32) | mtime->dwLowDateTime;
1829 sec = RtlLargeIntegerDivide( sec, 10000000, &nsec );
1830 tv[1].tv_sec = sec - SECS_1601_TO_1970;
1831 tv[1].tv_usec = (UINT)nsec / 10;
1834 if (!futimes( fd, tv )) ret = TRUE;
1835 else FILE_SetDosError();
1836 wine_server_release_fd( hFile, fd );
1838 else SetLastError( RtlNtStatusToDosError(status) );
1839 return ret;
1840 #else
1841 SetLastError( ERROR_CALL_NOT_IMPLEMENTED );
1842 return FALSE;
1843 #endif /* HAVE_FUTIMES */
1847 /**************************************************************************
1848 * GetFileAttributesExW (KERNEL32.@)
1850 BOOL WINAPI GetFileAttributesExW(
1851 LPCWSTR lpFileName, GET_FILEEX_INFO_LEVELS fInfoLevelId,
1852 LPVOID lpFileInformation)
1854 DOS_FULL_NAME full_name;
1855 BY_HANDLE_FILE_INFORMATION info;
1857 if (!lpFileName || !lpFileInformation)
1859 SetLastError(ERROR_INVALID_PARAMETER);
1860 return FALSE;
1863 if (fInfoLevelId == GetFileExInfoStandard) {
1864 LPWIN32_FILE_ATTRIBUTE_DATA lpFad =
1865 (LPWIN32_FILE_ATTRIBUTE_DATA) lpFileInformation;
1866 if (!DOSFS_GetFullName( lpFileName, TRUE, &full_name )) return FALSE;
1867 if (!FILE_Stat( full_name.long_name, &info, NULL )) return FALSE;
1869 lpFad->dwFileAttributes = info.dwFileAttributes;
1870 lpFad->ftCreationTime = info.ftCreationTime;
1871 lpFad->ftLastAccessTime = info.ftLastAccessTime;
1872 lpFad->ftLastWriteTime = info.ftLastWriteTime;
1873 lpFad->nFileSizeHigh = info.nFileSizeHigh;
1874 lpFad->nFileSizeLow = info.nFileSizeLow;
1876 else {
1877 FIXME("invalid info level %d!\n", fInfoLevelId);
1878 return FALSE;
1881 return TRUE;
1885 /**************************************************************************
1886 * GetFileAttributesExA (KERNEL32.@)
1888 BOOL WINAPI GetFileAttributesExA(
1889 LPCSTR filename, GET_FILEEX_INFO_LEVELS fInfoLevelId,
1890 LPVOID lpFileInformation)
1892 UNICODE_STRING filenameW;
1893 BOOL ret = FALSE;
1895 if (!filename || !lpFileInformation)
1897 SetLastError(ERROR_INVALID_PARAMETER);
1898 return FALSE;
1901 if (RtlCreateUnicodeStringFromAsciiz(&filenameW, filename))
1903 ret = GetFileAttributesExW(filenameW.Buffer, fInfoLevelId, lpFileInformation);
1904 RtlFreeUnicodeString(&filenameW);
1906 else
1907 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1908 return ret;