Convert app description field to unicode and use CP_UNIXCP when
[wine.git] / files / file.c
blobbb344def6f8a7aaa1c8584060dad0c30189692d8
1 /*
2 * File handling functions
4 * Copyright 1993 John Burton
5 * Copyright 1996 Alexandre Julliard
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 * TODO:
22 * Fix the CopyFileEx methods to implement the "extended" functionality.
23 * Right now, they simply call the CopyFile method.
26 #include "config.h"
27 #include "wine/port.h"
29 #include <assert.h>
30 #include <ctype.h>
31 #include <errno.h>
32 #include <fcntl.h>
33 #include <stdlib.h>
34 #include <stdarg.h>
35 #include <stdio.h>
36 #include <string.h>
37 #ifdef HAVE_SYS_ERRNO_H
38 #include <sys/errno.h>
39 #endif
40 #include <sys/types.h>
41 #include <sys/stat.h>
42 #ifdef HAVE_SYS_MMAN_H
43 #include <sys/mman.h>
44 #endif
45 #ifdef HAVE_SYS_TIME_H
46 # include <sys/time.h>
47 #endif
48 #ifdef HAVE_SYS_POLL_H
49 # include <sys/poll.h>
50 #endif
51 #include <time.h>
52 #ifdef HAVE_UNISTD_H
53 # include <unistd.h>
54 #endif
55 #ifdef HAVE_UTIME_H
56 # include <utime.h>
57 #endif
59 #define NONAMELESSUNION
60 #define NONAMELESSSTRUCT
61 #include "winerror.h"
62 #include "ntstatus.h"
63 #include "windef.h"
64 #include "winbase.h"
65 #include "winreg.h"
66 #include "winternl.h"
67 #include "wine/winbase16.h"
68 #include "wine/server.h"
70 #include "drive.h"
71 #include "file.h"
72 #include "wincon.h"
73 #include "kernel_private.h"
75 #include "smb.h"
76 #include "wine/unicode.h"
77 #include "wine/debug.h"
79 WINE_DEFAULT_DEBUG_CHANNEL(file);
81 #if defined(MAP_ANONYMOUS) && !defined(MAP_ANON)
82 #define MAP_ANON MAP_ANONYMOUS
83 #endif
85 #define IS_OPTION_TRUE(ch) ((ch) == 'y' || (ch) == 'Y' || (ch) == 't' || (ch) == 'T' || (ch) == '1')
87 mode_t FILE_umask;
89 /***********************************************************************
90 * FILE_ConvertOFMode
92 * Convert OF_* mode into flags for CreateFile.
94 void FILE_ConvertOFMode( INT mode, DWORD *access, DWORD *sharing )
96 switch(mode & 0x03)
98 case OF_READ: *access = GENERIC_READ; break;
99 case OF_WRITE: *access = GENERIC_WRITE; break;
100 case OF_READWRITE: *access = GENERIC_READ | GENERIC_WRITE; break;
101 default: *access = 0; break;
103 switch(mode & 0x70)
105 case OF_SHARE_EXCLUSIVE: *sharing = 0; break;
106 case OF_SHARE_DENY_WRITE: *sharing = FILE_SHARE_READ; break;
107 case OF_SHARE_DENY_READ: *sharing = FILE_SHARE_WRITE; break;
108 case OF_SHARE_DENY_NONE:
109 case OF_SHARE_COMPAT:
110 default: *sharing = FILE_SHARE_READ | FILE_SHARE_WRITE; break;
115 /***********************************************************************
116 * FILE_strcasecmp
118 * locale-independent case conversion for file I/O
120 int FILE_strcasecmp( const char *str1, const char *str2 )
122 int ret = 0;
123 for ( ; ; str1++, str2++)
124 if ((ret = FILE_toupper(*str1) - FILE_toupper(*str2)) || !*str1) break;
125 return ret;
129 /***********************************************************************
130 * FILE_strncasecmp
132 * locale-independent case conversion for file I/O
134 int FILE_strncasecmp( const char *str1, const char *str2, int len )
136 int ret = 0;
137 for ( ; len > 0; len--, str1++, str2++)
138 if ((ret = FILE_toupper(*str1) - FILE_toupper(*str2)) || !*str1) break;
139 return ret;
143 /***********************************************************************
144 * FILE_SetDosError
146 * Set the DOS error code from errno.
148 void FILE_SetDosError(void)
150 int save_errno = errno; /* errno gets overwritten by printf */
152 TRACE("errno = %d %s\n", errno, strerror(errno));
153 switch (save_errno)
155 case EAGAIN:
156 SetLastError( ERROR_SHARING_VIOLATION );
157 break;
158 case EBADF:
159 SetLastError( ERROR_INVALID_HANDLE );
160 break;
161 case ENOSPC:
162 SetLastError( ERROR_HANDLE_DISK_FULL );
163 break;
164 case EACCES:
165 case EPERM:
166 case EROFS:
167 SetLastError( ERROR_ACCESS_DENIED );
168 break;
169 case EBUSY:
170 SetLastError( ERROR_LOCK_VIOLATION );
171 break;
172 case ENOENT:
173 SetLastError( ERROR_FILE_NOT_FOUND );
174 break;
175 case EISDIR:
176 SetLastError( ERROR_CANNOT_MAKE );
177 break;
178 case ENFILE:
179 case EMFILE:
180 SetLastError( ERROR_NO_MORE_FILES );
181 break;
182 case EEXIST:
183 SetLastError( ERROR_FILE_EXISTS );
184 break;
185 case EINVAL:
186 case ESPIPE:
187 SetLastError( ERROR_SEEK );
188 break;
189 case ENOTEMPTY:
190 SetLastError( ERROR_DIR_NOT_EMPTY );
191 break;
192 case ENOEXEC:
193 SetLastError( ERROR_BAD_FORMAT );
194 break;
195 default:
196 WARN("unknown file error: %s\n", strerror(save_errno) );
197 SetLastError( ERROR_GEN_FAILURE );
198 break;
200 errno = save_errno;
204 /***********************************************************************
205 * FILE_CreateFile
207 * Implementation of CreateFile. Takes a Unix path name.
208 * Returns 0 on failure.
210 HANDLE FILE_CreateFile( LPCSTR filename, DWORD access, DWORD sharing,
211 LPSECURITY_ATTRIBUTES sa, DWORD creation,
212 DWORD attributes, HANDLE template, BOOL fail_read_only,
213 UINT drive_type )
215 unsigned int err;
216 HANDLE ret;
218 for (;;)
220 SERVER_START_REQ( create_file )
222 req->access = access;
223 req->inherit = (sa && (sa->nLength>=sizeof(*sa)) && sa->bInheritHandle);
224 req->sharing = sharing;
225 req->create = creation;
226 req->attrs = attributes;
227 req->removable = (drive_type == DRIVE_REMOVABLE || drive_type == DRIVE_CDROM);
228 wine_server_add_data( req, filename, strlen(filename) );
229 SetLastError(0);
230 err = wine_server_call( req );
231 ret = reply->handle;
233 SERVER_END_REQ;
235 /* If write access failed, retry without GENERIC_WRITE */
237 if (!ret && !fail_read_only && (access & GENERIC_WRITE))
239 if ((err == STATUS_MEDIA_WRITE_PROTECTED) || (err == STATUS_ACCESS_DENIED))
241 TRACE("Write access failed for file '%s', trying without "
242 "write access\n", filename);
243 access &= ~GENERIC_WRITE;
244 continue;
248 if (err)
250 /* In the case file creation was rejected due to CREATE_NEW flag
251 * was specified and file with that name already exists, correct
252 * last error is ERROR_FILE_EXISTS and not ERROR_ALREADY_EXISTS.
253 * Note: RtlNtStatusToDosError is not the subject to blame here.
255 if (err == STATUS_OBJECT_NAME_COLLISION)
256 SetLastError( ERROR_FILE_EXISTS );
257 else
258 SetLastError( RtlNtStatusToDosError(err) );
261 if (!ret) WARN("Unable to create file '%s' (GLE %ld)\n", filename, GetLastError());
262 return ret;
267 /***********************************************************************
268 * FILE_CreateDevice
270 * Same as FILE_CreateFile but for a device
271 * Returns 0 on failure.
273 HANDLE FILE_CreateDevice( int client_id, DWORD access, LPSECURITY_ATTRIBUTES sa )
275 HANDLE ret;
276 SERVER_START_REQ( create_device )
278 req->access = access;
279 req->inherit = (sa && (sa->nLength>=sizeof(*sa)) && sa->bInheritHandle);
280 req->id = client_id;
281 SetLastError(0);
282 wine_server_call_err( req );
283 ret = reply->handle;
285 SERVER_END_REQ;
286 return ret;
289 static HANDLE FILE_OpenPipe(LPCWSTR name, DWORD access, LPSECURITY_ATTRIBUTES sa )
291 HANDLE ret;
292 DWORD len = 0;
294 if (name && (len = strlenW(name)) > MAX_PATH)
296 SetLastError( ERROR_FILENAME_EXCED_RANGE );
297 return 0;
299 SERVER_START_REQ( open_named_pipe )
301 req->access = access;
302 req->inherit = (sa && (sa->nLength>=sizeof(*sa)) && sa->bInheritHandle);
303 SetLastError(0);
304 wine_server_add_data( req, name, len * sizeof(WCHAR) );
305 wine_server_call_err( req );
306 ret = reply->handle;
308 SERVER_END_REQ;
309 TRACE("Returned %p\n",ret);
310 return ret;
313 /*************************************************************************
314 * CreateFileW [KERNEL32.@] Creates or opens a file or other object
316 * Creates or opens an object, and returns a handle that can be used to
317 * access that object.
319 * PARAMS
321 * filename [in] pointer to filename to be accessed
322 * access [in] access mode requested
323 * sharing [in] share mode
324 * sa [in] pointer to security attributes
325 * creation [in] how to create the file
326 * attributes [in] attributes for newly created file
327 * template [in] handle to file with extended attributes to copy
329 * RETURNS
330 * Success: Open handle to specified file
331 * Failure: INVALID_HANDLE_VALUE
333 * NOTES
334 * Should call SetLastError() on failure.
336 * BUGS
338 * Doesn't support character devices, template files, or a
339 * lot of the 'attributes' flags yet.
341 HANDLE WINAPI CreateFileW( LPCWSTR filename, DWORD access, DWORD sharing,
342 LPSECURITY_ATTRIBUTES sa, DWORD creation,
343 DWORD attributes, HANDLE template )
345 DOS_FULL_NAME full_name;
346 HANDLE ret;
347 static const WCHAR bkslashes_with_question_markW[] = {'\\','\\','?','\\',0};
348 static const WCHAR bkslashes_with_dotW[] = {'\\','\\','.','\\',0};
349 static const WCHAR bkslashesW[] = {'\\','\\',0};
350 static const WCHAR coninW[] = {'C','O','N','I','N','$',0};
351 static const WCHAR conoutW[] = {'C','O','N','O','U','T','$',0};
353 if (!filename)
355 SetLastError( ERROR_INVALID_PARAMETER );
356 return INVALID_HANDLE_VALUE;
358 TRACE("%s %s%s%s%s%s%s%s attributes 0x%lx\n", debugstr_w(filename),
359 ((access & GENERIC_READ)==GENERIC_READ)?"GENERIC_READ ":"",
360 ((access & GENERIC_WRITE)==GENERIC_WRITE)?"GENERIC_WRITE ":"",
361 (!access)?"QUERY_ACCESS ":"",
362 ((sharing & FILE_SHARE_READ)==FILE_SHARE_READ)?"FILE_SHARE_READ ":"",
363 ((sharing & FILE_SHARE_WRITE)==FILE_SHARE_WRITE)?"FILE_SHARE_WRITE ":"",
364 ((sharing & FILE_SHARE_DELETE)==FILE_SHARE_DELETE)?"FILE_SHARE_DELETE ":"",
365 (creation ==CREATE_NEW)?"CREATE_NEW":
366 (creation ==CREATE_ALWAYS)?"CREATE_ALWAYS ":
367 (creation ==OPEN_EXISTING)?"OPEN_EXISTING ":
368 (creation ==OPEN_ALWAYS)?"OPEN_ALWAYS ":
369 (creation ==TRUNCATE_EXISTING)?"TRUNCATE_EXISTING ":"", attributes);
371 /* If the name starts with '\\?\', ignore the first 4 chars. */
372 if (!strncmpW(filename, bkslashes_with_question_markW, 4))
374 static const WCHAR uncW[] = {'U','N','C','\\',0};
375 filename += 4;
376 if (!strncmpiW(filename, uncW, 4))
378 FIXME("UNC name (%s) not supported.\n", debugstr_w(filename) );
379 SetLastError( ERROR_PATH_NOT_FOUND );
380 return INVALID_HANDLE_VALUE;
384 if (!strncmpW(filename, bkslashes_with_dotW, 4))
386 static const WCHAR pipeW[] = {'P','I','P','E','\\',0};
387 if(!strncmpiW(filename + 4, pipeW, 5))
389 TRACE("Opening a pipe: %s\n", debugstr_w(filename));
390 ret = FILE_OpenPipe( filename, access, sa );
391 goto done;
393 else if (isalphaW(filename[4]) && filename[5] == ':' && filename[6] == '\0')
395 ret = FILE_CreateDevice( (toupperW(filename[4]) - 'A') | 0x20000, access, sa );
396 goto done;
398 else if (!DOSFS_GetDevice( filename ))
400 ret = VXD_Open( filename+4, access, sa );
401 goto done;
403 else
404 filename+=4; /* fall into DOSFS_Device case below */
407 /* If the name still starts with '\\', it's a UNC name. */
408 if (!strncmpW(filename, bkslashesW, 2))
410 ret = SMB_CreateFileW(filename, access, sharing, sa, creation, attributes, template );
411 goto done;
414 /* If the name contains a DOS wild card (* or ?), do no create a file */
415 if(strchrW(filename, '*') || strchrW(filename, '?'))
417 SetLastError(ERROR_BAD_PATHNAME);
418 return INVALID_HANDLE_VALUE;
421 /* Open a console for CONIN$ or CONOUT$ */
422 if (!strcmpiW(filename, coninW) || !strcmpiW(filename, conoutW))
424 ret = OpenConsoleW(filename, access, sa, creation);
425 goto done;
428 if (DOSFS_GetDevice( filename ))
430 TRACE("opening device %s\n", debugstr_w(filename) );
432 if (!(ret = DOSFS_OpenDevice( filename, access, attributes, sa )))
434 /* Do not silence this please. It is a critical error. -MM */
435 ERR("Couldn't open device %s!\n", debugstr_w(filename));
436 SetLastError( ERROR_FILE_NOT_FOUND );
438 goto done;
441 /* check for filename, don't check for last entry if creating */
442 if (!DOSFS_GetFullName( filename,
443 (creation == OPEN_EXISTING) ||
444 (creation == TRUNCATE_EXISTING),
445 &full_name )) {
446 WARN("Unable to get full filename from %s (GLE %ld)\n",
447 debugstr_w(filename), GetLastError());
448 return INVALID_HANDLE_VALUE;
451 ret = FILE_CreateFile( full_name.long_name, access, sharing,
452 sa, creation, attributes, template,
453 DRIVE_GetFlags(full_name.drive) & DRIVE_FAIL_READ_ONLY,
454 GetDriveTypeW( full_name.short_name ) );
455 done:
456 if (!ret) ret = INVALID_HANDLE_VALUE;
457 TRACE("returning %p\n", ret);
458 return ret;
463 /*************************************************************************
464 * CreateFileA (KERNEL32.@)
466 HANDLE WINAPI CreateFileA( LPCSTR filename, DWORD access, DWORD sharing,
467 LPSECURITY_ATTRIBUTES sa, DWORD creation,
468 DWORD attributes, HANDLE template)
470 UNICODE_STRING filenameW;
471 HANDLE ret = INVALID_HANDLE_VALUE;
473 if (!filename)
475 SetLastError( ERROR_INVALID_PARAMETER );
476 return INVALID_HANDLE_VALUE;
479 if (RtlCreateUnicodeStringFromAsciiz(&filenameW, filename))
481 ret = CreateFileW(filenameW.Buffer, access, sharing, sa, creation,
482 attributes, template);
483 RtlFreeUnicodeString(&filenameW);
485 else
486 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
487 return ret;
491 /***********************************************************************
492 * FILE_FillInfo
494 * Fill a file information from a struct stat.
496 static void FILE_FillInfo( struct stat *st, BY_HANDLE_FILE_INFORMATION *info )
498 if (S_ISDIR(st->st_mode))
499 info->dwFileAttributes = FILE_ATTRIBUTE_DIRECTORY;
500 else
501 info->dwFileAttributes = FILE_ATTRIBUTE_ARCHIVE;
502 if (!(st->st_mode & S_IWUSR))
503 info->dwFileAttributes |= FILE_ATTRIBUTE_READONLY;
505 RtlSecondsSince1970ToTime( st->st_mtime, (LARGE_INTEGER *)&info->ftCreationTime );
506 RtlSecondsSince1970ToTime( st->st_mtime, (LARGE_INTEGER *)&info->ftLastWriteTime );
507 RtlSecondsSince1970ToTime( st->st_atime, (LARGE_INTEGER *)&info->ftLastAccessTime );
509 info->dwVolumeSerialNumber = 0; /* FIXME */
510 info->nFileSizeHigh = 0;
511 info->nFileSizeLow = 0;
512 if (!S_ISDIR(st->st_mode)) {
513 info->nFileSizeHigh = st->st_size >> 32;
514 info->nFileSizeLow = st->st_size & 0xffffffff;
516 info->nNumberOfLinks = st->st_nlink;
517 info->nFileIndexHigh = 0;
518 info->nFileIndexLow = st->st_ino;
522 /***********************************************************************
523 * get_show_dot_files_option
525 static BOOL get_show_dot_files_option(void)
527 static const WCHAR WineW[] = {'M','a','c','h','i','n','e','\\',
528 'S','o','f','t','w','a','r','e','\\',
529 'W','i','n','e','\\','W','i','n','e','\\',
530 'C','o','n','f','i','g','\\','W','i','n','e',0};
531 static const WCHAR ShowDotFilesW[] = {'S','h','o','w','D','o','t','F','i','l','e','s',0};
533 char tmp[80];
534 HKEY hkey;
535 DWORD dummy;
536 OBJECT_ATTRIBUTES attr;
537 UNICODE_STRING nameW;
538 BOOL ret = FALSE;
540 attr.Length = sizeof(attr);
541 attr.RootDirectory = 0;
542 attr.ObjectName = &nameW;
543 attr.Attributes = 0;
544 attr.SecurityDescriptor = NULL;
545 attr.SecurityQualityOfService = NULL;
546 RtlInitUnicodeString( &nameW, WineW );
548 if (!NtOpenKey( &hkey, KEY_ALL_ACCESS, &attr ))
550 RtlInitUnicodeString( &nameW, ShowDotFilesW );
551 if (!NtQueryValueKey( hkey, &nameW, KeyValuePartialInformation, tmp, sizeof(tmp), &dummy ))
553 WCHAR *str = (WCHAR *)((KEY_VALUE_PARTIAL_INFORMATION *)tmp)->Data;
554 ret = IS_OPTION_TRUE( str[0] );
556 NtClose( hkey );
558 return ret;
562 /***********************************************************************
563 * FILE_Stat
565 * Stat a Unix path name. Return TRUE if OK.
567 BOOL FILE_Stat( LPCSTR unixName, BY_HANDLE_FILE_INFORMATION *info, BOOL *is_symlink_ptr )
569 struct stat st;
570 int is_symlink;
571 LPCSTR p;
573 if (lstat( unixName, &st ) == -1)
575 FILE_SetDosError();
576 return FALSE;
578 is_symlink = S_ISLNK(st.st_mode);
579 if (is_symlink)
581 /* do a "real" stat to find out
582 about the type of the symlink destination */
583 if (stat( unixName, &st ) == -1)
585 FILE_SetDosError();
586 return FALSE;
590 /* fill in the information we gathered so far */
591 FILE_FillInfo( &st, info );
593 /* and now see if this is a hidden file, based on the name */
594 p = strrchr( unixName, '/');
595 p = p ? p + 1 : unixName;
596 if (*p == '.' && *(p+1) && (*(p+1) != '.' || *(p+2)))
598 static int show_dot_files = -1;
599 if (show_dot_files == -1)
600 show_dot_files = get_show_dot_files_option();
601 if (!show_dot_files)
602 info->dwFileAttributes |= FILE_ATTRIBUTE_HIDDEN;
604 if (is_symlink_ptr) *is_symlink_ptr = is_symlink;
605 return TRUE;
609 /***********************************************************************
610 * GetFileInformationByHandle (KERNEL32.@)
612 DWORD WINAPI GetFileInformationByHandle( HANDLE hFile,
613 BY_HANDLE_FILE_INFORMATION *info )
615 DWORD ret;
616 if (!info) return 0;
618 TRACE("%p\n", hFile);
620 SERVER_START_REQ( get_file_info )
622 req->handle = hFile;
623 if ((ret = !wine_server_call_err( req )))
625 /* FIXME: which file types are supported ?
626 * Serial ports (FILE_TYPE_CHAR) are not,
627 * and MSDN also says that pipes are not supported.
628 * FILE_TYPE_REMOTE seems to be supported according to
629 * MSDN q234741.txt */
630 if ((reply->type == FILE_TYPE_DISK) || (reply->type == FILE_TYPE_REMOTE))
632 RtlSecondsSince1970ToTime( reply->write_time, (LARGE_INTEGER *)&info->ftCreationTime );
633 RtlSecondsSince1970ToTime( reply->write_time, (LARGE_INTEGER *)&info->ftLastWriteTime );
634 RtlSecondsSince1970ToTime( reply->access_time, (LARGE_INTEGER *)&info->ftLastAccessTime );
635 info->dwFileAttributes = reply->attr;
636 info->dwVolumeSerialNumber = reply->serial;
637 info->nFileSizeHigh = reply->size_high;
638 info->nFileSizeLow = reply->size_low;
639 info->nNumberOfLinks = reply->links;
640 info->nFileIndexHigh = reply->index_high;
641 info->nFileIndexLow = reply->index_low;
643 else
645 SetLastError(ERROR_NOT_SUPPORTED);
646 ret = 0;
650 SERVER_END_REQ;
651 return ret;
655 /**************************************************************************
656 * GetFileAttributesW (KERNEL32.@)
658 DWORD WINAPI GetFileAttributesW( LPCWSTR name )
660 DOS_FULL_NAME full_name;
661 BY_HANDLE_FILE_INFORMATION info;
663 if (name == NULL)
665 SetLastError( ERROR_INVALID_PARAMETER );
666 return INVALID_FILE_ATTRIBUTES;
668 if (!DOSFS_GetFullName( name, TRUE, &full_name) )
669 return INVALID_FILE_ATTRIBUTES;
670 if (!FILE_Stat( full_name.long_name, &info, NULL ))
671 return INVALID_FILE_ATTRIBUTES;
672 return info.dwFileAttributes;
676 /**************************************************************************
677 * GetFileAttributesA (KERNEL32.@)
679 DWORD WINAPI GetFileAttributesA( LPCSTR name )
681 UNICODE_STRING nameW;
682 DWORD ret = INVALID_FILE_ATTRIBUTES;
684 if (!name)
686 SetLastError( ERROR_INVALID_PARAMETER );
687 return INVALID_FILE_ATTRIBUTES;
690 if (RtlCreateUnicodeStringFromAsciiz(&nameW, name))
692 ret = GetFileAttributesW(nameW.Buffer);
693 RtlFreeUnicodeString(&nameW);
695 else
696 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
697 return ret;
701 /**************************************************************************
702 * SetFileAttributesW (KERNEL32.@)
704 BOOL WINAPI SetFileAttributesW(LPCWSTR lpFileName, DWORD attributes)
706 struct stat buf;
707 DOS_FULL_NAME full_name;
709 if (!lpFileName)
711 SetLastError( ERROR_INVALID_PARAMETER );
712 return FALSE;
715 TRACE("(%s,%lx)\n", debugstr_w(lpFileName), attributes);
717 if (!DOSFS_GetFullName( lpFileName, TRUE, &full_name ))
718 return FALSE;
720 if(stat(full_name.long_name,&buf)==-1)
722 FILE_SetDosError();
723 return FALSE;
725 if (attributes & FILE_ATTRIBUTE_READONLY)
727 if(S_ISDIR(buf.st_mode))
728 /* FIXME */
729 WARN("FILE_ATTRIBUTE_READONLY ignored for directory.\n");
730 else
731 buf.st_mode &= ~0222; /* octal!, clear write permission bits */
732 attributes &= ~FILE_ATTRIBUTE_READONLY;
734 else
736 /* add write permission */
737 buf.st_mode |= (0600 | ((buf.st_mode & 044) >> 1)) & (~FILE_umask);
739 if (attributes & FILE_ATTRIBUTE_DIRECTORY)
741 if (!S_ISDIR(buf.st_mode))
742 FIXME("SetFileAttributes expected the file %s to be a directory\n",
743 debugstr_w(lpFileName));
744 attributes &= ~FILE_ATTRIBUTE_DIRECTORY;
746 attributes &= ~(FILE_ATTRIBUTE_NORMAL|FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_HIDDEN|
747 FILE_ATTRIBUTE_SYSTEM|FILE_ATTRIBUTE_TEMPORARY);
748 if (attributes)
749 FIXME("(%s):%lx attribute(s) not implemented.\n", debugstr_w(lpFileName), attributes);
750 if (-1==chmod(full_name.long_name,buf.st_mode))
752 if (GetDriveTypeW(lpFileName) == DRIVE_CDROM)
754 SetLastError( ERROR_ACCESS_DENIED );
755 return FALSE;
759 * FIXME: We don't return FALSE here because of differences between
760 * Linux and Windows privileges. Under Linux only the owner of
761 * the file is allowed to change file attributes. Under Windows,
762 * applications expect that if you can write to a file, you can also
763 * change its attributes (see GENERIC_WRITE). We could try to be
764 * clever here but that would break multi-user installations where
765 * users share read-only DLLs. This is because some installers like
766 * to change attributes of already installed DLLs.
768 FIXME("Couldn't set file attributes for existing file \"%s\".\n"
769 "Check permissions or set VFAT \"quiet\" mount flag\n", full_name.long_name);
771 return TRUE;
775 /**************************************************************************
776 * SetFileAttributesA (KERNEL32.@)
778 BOOL WINAPI SetFileAttributesA(LPCSTR lpFileName, DWORD attributes)
780 UNICODE_STRING filenameW;
781 BOOL ret = FALSE;
783 if (!lpFileName)
785 SetLastError( ERROR_INVALID_PARAMETER );
786 return FALSE;
789 if (RtlCreateUnicodeStringFromAsciiz(&filenameW, lpFileName))
791 ret = SetFileAttributesW(filenameW.Buffer, attributes);
792 RtlFreeUnicodeString(&filenameW);
794 else
795 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
796 return ret;
800 /******************************************************************************
801 * GetCompressedFileSizeA [KERNEL32.@]
803 DWORD WINAPI GetCompressedFileSizeA(
804 LPCSTR lpFileName,
805 LPDWORD lpFileSizeHigh)
807 UNICODE_STRING filenameW;
808 DWORD ret;
810 if (RtlCreateUnicodeStringFromAsciiz(&filenameW, lpFileName))
812 ret = GetCompressedFileSizeW(filenameW.Buffer, lpFileSizeHigh);
813 RtlFreeUnicodeString(&filenameW);
815 else
817 ret = INVALID_FILE_SIZE;
818 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
820 return ret;
824 /******************************************************************************
825 * GetCompressedFileSizeW [KERNEL32.@]
827 * RETURNS
828 * Success: Low-order doubleword of number of bytes
829 * Failure: INVALID_FILE_SIZE
831 DWORD WINAPI GetCompressedFileSizeW(
832 LPCWSTR lpFileName, /* [in] Pointer to name of file */
833 LPDWORD lpFileSizeHigh) /* [out] Receives high-order doubleword of size */
835 DOS_FULL_NAME full_name;
836 struct stat st;
837 DWORD low;
839 TRACE("(%s,%p)\n",debugstr_w(lpFileName),lpFileSizeHigh);
841 if (!DOSFS_GetFullName( lpFileName, TRUE, &full_name )) return INVALID_FILE_SIZE;
842 if (stat(full_name.long_name, &st) != 0)
844 FILE_SetDosError();
845 return INVALID_FILE_SIZE;
847 #if HAVE_STRUCT_STAT_ST_BLOCKS
848 /* blocks are 512 bytes long */
849 if (lpFileSizeHigh) *lpFileSizeHigh = (st.st_blocks >> 23);
850 low = (DWORD)(st.st_blocks << 9);
851 #else
852 if (lpFileSizeHigh) *lpFileSizeHigh = (st.st_size >> 32);
853 low = (DWORD)st.st_size;
854 #endif
855 return low;
859 /***********************************************************************
860 * GetFileTime (KERNEL32.@)
862 BOOL WINAPI GetFileTime( HANDLE hFile, FILETIME *lpCreationTime,
863 FILETIME *lpLastAccessTime,
864 FILETIME *lpLastWriteTime )
866 BY_HANDLE_FILE_INFORMATION info;
867 if (!GetFileInformationByHandle( hFile, &info )) return FALSE;
868 if (lpCreationTime) *lpCreationTime = info.ftCreationTime;
869 if (lpLastAccessTime) *lpLastAccessTime = info.ftLastAccessTime;
870 if (lpLastWriteTime) *lpLastWriteTime = info.ftLastWriteTime;
871 return TRUE;
875 /***********************************************************************
876 * GetTempFileNameA (KERNEL32.@)
878 UINT WINAPI GetTempFileNameA( LPCSTR path, LPCSTR prefix, UINT unique,
879 LPSTR buffer)
881 UNICODE_STRING pathW, prefixW;
882 WCHAR bufferW[MAX_PATH];
883 UINT ret;
885 if ( !path || !prefix || !buffer )
887 SetLastError( ERROR_INVALID_PARAMETER );
888 return 0;
891 RtlCreateUnicodeStringFromAsciiz(&pathW, path);
892 RtlCreateUnicodeStringFromAsciiz(&prefixW, prefix);
894 ret = GetTempFileNameW(pathW.Buffer, prefixW.Buffer, unique, bufferW);
895 if (ret)
896 WideCharToMultiByte(CP_ACP, 0, bufferW, -1, buffer, MAX_PATH, NULL, NULL);
898 RtlFreeUnicodeString(&pathW);
899 RtlFreeUnicodeString(&prefixW);
900 return ret;
903 /***********************************************************************
904 * GetTempFileNameW (KERNEL32.@)
906 UINT WINAPI GetTempFileNameW( LPCWSTR path, LPCWSTR prefix, UINT unique,
907 LPWSTR buffer )
909 static const WCHAR formatW[] = {'%','x','.','t','m','p',0};
911 DOS_FULL_NAME full_name;
912 int i;
913 LPWSTR p;
915 if ( !path || !prefix || !buffer )
917 SetLastError( ERROR_INVALID_PARAMETER );
918 return 0;
921 strcpyW( buffer, path );
922 p = buffer + strlenW(buffer);
924 /* add a \, if there isn't one */
925 if ((p == buffer) || (p[-1] != '\\')) *p++ = '\\';
927 for (i = 3; (i > 0) && (*prefix); i--) *p++ = *prefix++;
929 unique &= 0xffff;
931 if (unique) sprintfW( p, formatW, unique );
932 else
934 /* get a "random" unique number and try to create the file */
935 HANDLE handle;
936 UINT num = GetTickCount() & 0xffff;
938 if (!num) num = 1;
939 unique = num;
942 sprintfW( p, formatW, unique );
943 handle = CreateFileW( buffer, GENERIC_WRITE, 0, NULL,
944 CREATE_NEW, FILE_ATTRIBUTE_NORMAL, 0 );
945 if (handle != INVALID_HANDLE_VALUE)
946 { /* We created it */
947 TRACE("created %s\n", debugstr_w(buffer) );
948 CloseHandle( handle );
949 break;
951 if (GetLastError() != ERROR_FILE_EXISTS &&
952 GetLastError() != ERROR_SHARING_VIOLATION)
953 break; /* No need to go on */
954 if (!(++unique & 0xffff)) unique = 1;
955 } while (unique != num);
958 /* Get the full path name */
960 if (DOSFS_GetFullName( buffer, FALSE, &full_name ))
962 char *slash;
963 /* Check if we have write access in the directory */
964 if ((slash = strrchr( full_name.long_name, '/' ))) *slash = '\0';
965 if (access( full_name.long_name, W_OK ) == -1)
966 WARN("returns %s, which doesn't seem to be writeable.\n",
967 debugstr_w(buffer) );
969 TRACE("returning %s\n", debugstr_w(buffer) );
970 return unique;
974 /***********************************************************************
975 * FILE_DoOpenFile
977 * Implementation of OpenFile16() and OpenFile32().
979 static HFILE FILE_DoOpenFile( LPCSTR name, OFSTRUCT *ofs, UINT mode, BOOL win32 )
981 HFILE hFileRet;
982 HANDLE handle;
983 FILETIME filetime;
984 WORD filedatetime[2];
985 DOS_FULL_NAME full_name;
986 DWORD access, sharing;
987 WCHAR *p;
988 WCHAR buffer[MAX_PATH];
989 LPWSTR nameW;
991 if (!ofs) return HFILE_ERROR;
993 TRACE("%s %s %s %s%s%s%s%s%s%s%s%s\n",name,
994 ((mode & 0x3 )==OF_READ)?"OF_READ":
995 ((mode & 0x3 )==OF_WRITE)?"OF_WRITE":
996 ((mode & 0x3 )==OF_READWRITE)?"OF_READWRITE":"unknown",
997 ((mode & 0x70 )==OF_SHARE_COMPAT)?"OF_SHARE_COMPAT":
998 ((mode & 0x70 )==OF_SHARE_DENY_NONE)?"OF_SHARE_DENY_NONE":
999 ((mode & 0x70 )==OF_SHARE_DENY_READ)?"OF_SHARE_DENY_READ":
1000 ((mode & 0x70 )==OF_SHARE_DENY_WRITE)?"OF_SHARE_DENY_WRITE":
1001 ((mode & 0x70 )==OF_SHARE_EXCLUSIVE)?"OF_SHARE_EXCLUSIVE":"unknown",
1002 ((mode & OF_PARSE )==OF_PARSE)?"OF_PARSE ":"",
1003 ((mode & OF_DELETE )==OF_DELETE)?"OF_DELETE ":"",
1004 ((mode & OF_VERIFY )==OF_VERIFY)?"OF_VERIFY ":"",
1005 ((mode & OF_SEARCH )==OF_SEARCH)?"OF_SEARCH ":"",
1006 ((mode & OF_CANCEL )==OF_CANCEL)?"OF_CANCEL ":"",
1007 ((mode & OF_CREATE )==OF_CREATE)?"OF_CREATE ":"",
1008 ((mode & OF_PROMPT )==OF_PROMPT)?"OF_PROMPT ":"",
1009 ((mode & OF_EXIST )==OF_EXIST)?"OF_EXIST ":"",
1010 ((mode & OF_REOPEN )==OF_REOPEN)?"OF_REOPEN ":""
1014 ofs->cBytes = sizeof(OFSTRUCT);
1015 ofs->nErrCode = 0;
1016 if (mode & OF_REOPEN) name = ofs->szPathName;
1018 if (!name) {
1019 ERR("called with `name' set to NULL ! Please debug.\n");
1020 return HFILE_ERROR;
1023 TRACE("%s %04x\n", name, mode );
1025 /* the watcom 10.6 IDE relies on a valid path returned in ofs->szPathName
1026 Are there any cases where getting the path here is wrong?
1027 Uwe Bonnes 1997 Apr 2 */
1028 if (!GetFullPathNameA( name, sizeof(ofs->szPathName),
1029 ofs->szPathName, NULL )) goto error;
1030 FILE_ConvertOFMode( mode, &access, &sharing );
1032 /* OF_PARSE simply fills the structure */
1034 if (mode & OF_PARSE)
1036 ofs->fFixedDisk = (GetDriveType16( ofs->szPathName[0]-'A' )
1037 != DRIVE_REMOVABLE);
1038 TRACE("(%s): OF_PARSE, res = '%s'\n",
1039 name, ofs->szPathName );
1040 return 0;
1043 /* OF_CREATE is completely different from all other options, so
1044 handle it first */
1046 if (mode & OF_CREATE)
1048 if ((handle = CreateFileA( name, GENERIC_READ | GENERIC_WRITE,
1049 sharing, NULL, CREATE_ALWAYS,
1050 FILE_ATTRIBUTE_NORMAL, 0 ))== INVALID_HANDLE_VALUE)
1051 goto error;
1052 goto success;
1055 MultiByteToWideChar(CP_ACP, 0, name, -1, buffer, MAX_PATH);
1056 nameW = buffer;
1058 /* If OF_SEARCH is set, ignore the given path */
1060 if ((mode & OF_SEARCH) && !(mode & OF_REOPEN))
1062 /* First try the file name as is */
1063 if (DOSFS_GetFullName( nameW, TRUE, &full_name )) goto found;
1064 /* Now remove the path */
1065 if (nameW[0] && (nameW[1] == ':')) nameW += 2;
1066 if ((p = strrchrW( nameW, '\\' ))) nameW = p + 1;
1067 if ((p = strrchrW( nameW, '/' ))) nameW = p + 1;
1068 if (!nameW[0]) goto not_found;
1071 /* Now look for the file */
1073 if (!DIR_SearchPath( NULL, nameW, NULL, &full_name, win32 )) goto not_found;
1075 found:
1076 TRACE("found %s = %s\n",
1077 full_name.long_name, debugstr_w(full_name.short_name) );
1078 WideCharToMultiByte(CP_ACP, 0, full_name.short_name, -1,
1079 ofs->szPathName, sizeof(ofs->szPathName), NULL, NULL);
1081 if (mode & OF_DELETE)
1083 handle = FILE_CreateFile( full_name.long_name, GENERIC_READ|GENERIC_WRITE, 0,
1084 NULL, OPEN_EXISTING, 0, 0, TRUE,
1085 GetDriveTypeW( full_name.short_name ) );
1086 if (!handle) goto error;
1087 CloseHandle( handle );
1088 if (unlink( full_name.long_name ) == -1) goto not_found;
1089 TRACE("(%s): OF_DELETE return = OK\n", name);
1090 return 1;
1093 handle = FILE_CreateFile( full_name.long_name, access, sharing,
1094 NULL, OPEN_EXISTING, 0, 0,
1095 DRIVE_GetFlags(full_name.drive) & DRIVE_FAIL_READ_ONLY,
1096 GetDriveTypeW( full_name.short_name ) );
1097 if (!handle) goto not_found;
1099 GetFileTime( handle, NULL, NULL, &filetime );
1100 FileTimeToDosDateTime( &filetime, &filedatetime[0], &filedatetime[1] );
1101 if ((mode & OF_VERIFY) && (mode & OF_REOPEN))
1103 if (ofs->Reserved1 != filedatetime[0] || ofs->Reserved2 != filedatetime[1] )
1105 CloseHandle( handle );
1106 WARN("(%s): OF_VERIFY failed\n", name );
1107 /* FIXME: what error here? */
1108 SetLastError( ERROR_FILE_NOT_FOUND );
1109 goto error;
1112 ofs->Reserved1 = filedatetime[0];
1113 ofs->Reserved2 = filedatetime[1];
1115 success: /* We get here if the open was successful */
1116 TRACE("(%s): OK, return = %p\n", name, handle );
1117 if (win32)
1119 hFileRet = (HFILE)handle;
1120 if (mode & OF_EXIST) /* Return the handle, but close it first */
1121 CloseHandle( handle );
1123 else
1125 hFileRet = Win32HandleToDosFileHandle( handle );
1126 if (hFileRet == HFILE_ERROR16) goto error;
1127 if (mode & OF_EXIST) /* Return the handle, but close it first */
1128 _lclose16( hFileRet );
1130 return hFileRet;
1132 not_found: /* We get here if the file does not exist */
1133 WARN("'%s' not found or sharing violation\n", name );
1134 SetLastError( ERROR_FILE_NOT_FOUND );
1135 /* fall through */
1137 error: /* We get here if there was an error opening the file */
1138 ofs->nErrCode = GetLastError();
1139 WARN("(%s): return = HFILE_ERROR error= %d\n",
1140 name,ofs->nErrCode );
1141 return HFILE_ERROR;
1145 /***********************************************************************
1146 * OpenFile (KERNEL.74)
1147 * OpenFileEx (KERNEL.360)
1149 HFILE16 WINAPI OpenFile16( LPCSTR name, OFSTRUCT *ofs, UINT16 mode )
1151 return FILE_DoOpenFile( name, ofs, mode, FALSE );
1155 /***********************************************************************
1156 * OpenFile (KERNEL32.@)
1158 HFILE WINAPI OpenFile( LPCSTR name, OFSTRUCT *ofs, UINT mode )
1160 return FILE_DoOpenFile( name, ofs, mode, TRUE );
1164 /******************************************************************
1165 * FILE_ReadWriteApc (internal)
1169 static void WINAPI FILE_ReadWriteApc(void* apc_user, PIO_STATUS_BLOCK io_status, ULONG len)
1171 LPOVERLAPPED_COMPLETION_ROUTINE cr = (LPOVERLAPPED_COMPLETION_ROUTINE)apc_user;
1173 cr(RtlNtStatusToDosError(io_status->u.Status), len, (LPOVERLAPPED)io_status);
1176 /***********************************************************************
1177 * ReadFileEx (KERNEL32.@)
1179 BOOL WINAPI ReadFileEx(HANDLE hFile, LPVOID buffer, DWORD bytesToRead,
1180 LPOVERLAPPED overlapped,
1181 LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine)
1183 LARGE_INTEGER offset;
1184 NTSTATUS status;
1185 PIO_STATUS_BLOCK io_status;
1187 if (!overlapped)
1189 SetLastError(ERROR_INVALID_PARAMETER);
1190 return FALSE;
1193 offset.u.LowPart = overlapped->Offset;
1194 offset.u.HighPart = overlapped->OffsetHigh;
1195 io_status = (PIO_STATUS_BLOCK)overlapped;
1196 io_status->u.Status = STATUS_PENDING;
1198 status = NtReadFile(hFile, NULL, FILE_ReadWriteApc, lpCompletionRoutine,
1199 io_status, buffer, bytesToRead, &offset, NULL);
1201 if (status)
1203 SetLastError( RtlNtStatusToDosError(status) );
1204 return FALSE;
1206 return TRUE;
1209 /***********************************************************************
1210 * ReadFile (KERNEL32.@)
1212 BOOL WINAPI ReadFile( HANDLE hFile, LPVOID buffer, DWORD bytesToRead,
1213 LPDWORD bytesRead, LPOVERLAPPED overlapped )
1215 LARGE_INTEGER offset;
1216 PLARGE_INTEGER poffset = NULL;
1217 IO_STATUS_BLOCK iosb;
1218 PIO_STATUS_BLOCK io_status = &iosb;
1219 HANDLE hEvent = 0;
1220 NTSTATUS status;
1222 TRACE("%p %p %ld %p %p\n", hFile, buffer, bytesToRead,
1223 bytesRead, overlapped );
1225 if (bytesRead) *bytesRead = 0; /* Do this before anything else */
1226 if (!bytesToRead) return TRUE;
1228 if (IsBadReadPtr(buffer, bytesToRead))
1230 SetLastError(ERROR_WRITE_FAULT); /* FIXME */
1231 return FALSE;
1233 if (is_console_handle(hFile))
1234 return ReadConsoleA(hFile, buffer, bytesToRead, bytesRead, NULL);
1236 if (overlapped != NULL)
1238 offset.u.LowPart = overlapped->Offset;
1239 offset.u.HighPart = overlapped->OffsetHigh;
1240 poffset = &offset;
1241 hEvent = overlapped->hEvent;
1242 io_status = (PIO_STATUS_BLOCK)overlapped;
1244 io_status->u.Status = STATUS_PENDING;
1245 io_status->Information = 0;
1247 status = NtReadFile(hFile, hEvent, NULL, NULL, io_status, buffer, bytesToRead, poffset, NULL);
1249 if (status != STATUS_PENDING && bytesRead)
1250 *bytesRead = io_status->Information;
1252 if (status && status != STATUS_END_OF_FILE)
1254 SetLastError( RtlNtStatusToDosError(status) );
1255 return FALSE;
1257 return TRUE;
1261 /***********************************************************************
1262 * WriteFileEx (KERNEL32.@)
1264 BOOL WINAPI WriteFileEx(HANDLE hFile, LPCVOID buffer, DWORD bytesToWrite,
1265 LPOVERLAPPED overlapped,
1266 LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine)
1268 LARGE_INTEGER offset;
1269 NTSTATUS status;
1270 PIO_STATUS_BLOCK io_status;
1272 TRACE("%p %p %ld %p %p\n",
1273 hFile, buffer, bytesToWrite, overlapped, lpCompletionRoutine);
1275 if (overlapped == NULL)
1277 SetLastError(ERROR_INVALID_PARAMETER);
1278 return FALSE;
1280 offset.u.LowPart = overlapped->Offset;
1281 offset.u.HighPart = overlapped->OffsetHigh;
1283 io_status = (PIO_STATUS_BLOCK)overlapped;
1284 io_status->u.Status = STATUS_PENDING;
1286 status = NtWriteFile(hFile, NULL, FILE_ReadWriteApc, lpCompletionRoutine,
1287 io_status, buffer, bytesToWrite, &offset, NULL);
1289 if (status) SetLastError( RtlNtStatusToDosError(status) );
1290 return !status;
1293 /***********************************************************************
1294 * WriteFile (KERNEL32.@)
1296 BOOL WINAPI WriteFile( HANDLE hFile, LPCVOID buffer, DWORD bytesToWrite,
1297 LPDWORD bytesWritten, LPOVERLAPPED overlapped )
1299 HANDLE hEvent = NULL;
1300 LARGE_INTEGER offset;
1301 PLARGE_INTEGER poffset = NULL;
1302 NTSTATUS status;
1303 IO_STATUS_BLOCK iosb;
1304 PIO_STATUS_BLOCK piosb = &iosb;
1306 TRACE("%p %p %ld %p %p\n",
1307 hFile, buffer, bytesToWrite, bytesWritten, overlapped );
1309 if (is_console_handle(hFile))
1310 return WriteConsoleA(hFile, buffer, bytesToWrite, bytesWritten, NULL);
1312 if (IsBadReadPtr(buffer, bytesToWrite))
1314 SetLastError(ERROR_READ_FAULT); /* FIXME */
1315 return FALSE;
1318 if (overlapped)
1320 offset.u.LowPart = overlapped->Offset;
1321 offset.u.HighPart = overlapped->OffsetHigh;
1322 poffset = &offset;
1323 hEvent = overlapped->hEvent;
1324 piosb = (PIO_STATUS_BLOCK)overlapped;
1326 piosb->u.Status = STATUS_PENDING;
1327 piosb->Information = 0;
1329 status = NtWriteFile(hFile, hEvent, NULL, NULL, piosb,
1330 buffer, bytesToWrite, poffset, NULL);
1331 if (status)
1333 SetLastError( RtlNtStatusToDosError(status) );
1334 return FALSE;
1336 if (bytesWritten) *bytesWritten = piosb->Information;
1338 return TRUE;
1342 /***********************************************************************
1343 * SetFilePointer (KERNEL32.@)
1345 DWORD WINAPI SetFilePointer( HANDLE hFile, LONG distance, LONG *highword,
1346 DWORD method )
1348 DWORD ret = INVALID_SET_FILE_POINTER;
1350 TRACE("handle %p offset %ld high %ld origin %ld\n",
1351 hFile, distance, highword?*highword:0, method );
1353 SERVER_START_REQ( set_file_pointer )
1355 req->handle = hFile;
1356 req->low = distance;
1357 req->high = highword ? *highword : (distance >= 0) ? 0 : -1;
1358 /* FIXME: assumes 1:1 mapping between Windows and Unix seek constants */
1359 req->whence = method;
1360 SetLastError( 0 );
1361 if (!wine_server_call_err( req ))
1363 ret = reply->new_low;
1364 if (highword) *highword = reply->new_high;
1367 SERVER_END_REQ;
1368 return ret;
1372 /*************************************************************************
1373 * SetHandleCount (KERNEL32.@)
1375 UINT WINAPI SetHandleCount( UINT count )
1377 return min( 256, count );
1381 /**************************************************************************
1382 * SetEndOfFile (KERNEL32.@)
1384 BOOL WINAPI SetEndOfFile( HANDLE hFile )
1386 BOOL ret;
1387 SERVER_START_REQ( truncate_file )
1389 req->handle = hFile;
1390 ret = !wine_server_call_err( req );
1392 SERVER_END_REQ;
1393 return ret;
1397 /***********************************************************************
1398 * DeleteFileW (KERNEL32.@)
1400 BOOL WINAPI DeleteFileW( LPCWSTR path )
1402 DOS_FULL_NAME full_name;
1403 HANDLE hFile;
1405 TRACE("%s\n", debugstr_w(path) );
1406 if (!path || !*path)
1408 SetLastError(ERROR_PATH_NOT_FOUND);
1409 return FALSE;
1411 if (DOSFS_GetDevice( path ))
1413 WARN("cannot remove DOS device %s!\n", debugstr_w(path));
1414 SetLastError( ERROR_FILE_NOT_FOUND );
1415 return FALSE;
1418 if (!DOSFS_GetFullName( path, TRUE, &full_name )) return FALSE;
1420 /* check if we are allowed to delete the source */
1421 hFile = FILE_CreateFile( full_name.long_name, GENERIC_READ|GENERIC_WRITE, 0,
1422 NULL, OPEN_EXISTING, 0, 0, TRUE,
1423 GetDriveTypeW( full_name.short_name ) );
1424 if (!hFile) return FALSE;
1426 if (unlink( full_name.long_name ) == -1)
1428 FILE_SetDosError();
1429 CloseHandle(hFile);
1430 return FALSE;
1432 CloseHandle(hFile);
1433 return TRUE;
1437 /***********************************************************************
1438 * DeleteFileA (KERNEL32.@)
1440 BOOL WINAPI DeleteFileA( LPCSTR path )
1442 UNICODE_STRING pathW;
1443 BOOL ret = FALSE;
1445 if (!path)
1447 SetLastError(ERROR_INVALID_PARAMETER);
1448 return FALSE;
1451 if (RtlCreateUnicodeStringFromAsciiz(&pathW, path))
1453 ret = DeleteFileW(pathW.Buffer);
1454 RtlFreeUnicodeString(&pathW);
1456 else
1457 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1458 return ret;
1462 /***********************************************************************
1463 * GetFileType (KERNEL32.@)
1465 DWORD WINAPI GetFileType( HANDLE hFile )
1467 DWORD ret = FILE_TYPE_UNKNOWN;
1469 if (is_console_handle( hFile ))
1470 return FILE_TYPE_CHAR;
1472 SERVER_START_REQ( get_file_info )
1474 req->handle = hFile;
1475 if (!wine_server_call_err( req )) ret = reply->type;
1477 SERVER_END_REQ;
1478 return ret;
1482 /* check if a file name is for an executable file (.exe or .com) */
1483 inline static BOOL is_executable( const char *name )
1485 int len = strlen(name);
1487 if (len < 4) return FALSE;
1488 return (!strcasecmp( name + len - 4, ".exe" ) ||
1489 !strcasecmp( name + len - 4, ".com" ));
1493 /***********************************************************************
1494 * FILE_AddBootRenameEntry
1496 * Adds an entry to the registry that is loaded when windows boots and
1497 * checks if there are some files to be removed or renamed/moved.
1498 * <fn1> has to be valid and <fn2> may be NULL. If both pointers are
1499 * non-NULL then the file is moved, otherwise it is deleted. The
1500 * entry of the registrykey is always appended with two zero
1501 * terminated strings. If <fn2> is NULL then the second entry is
1502 * simply a single 0-byte. Otherwise the second filename goes
1503 * there. The entries are prepended with \??\ before the path and the
1504 * second filename gets also a '!' as the first character if
1505 * MOVEFILE_REPLACE_EXISTING is set. After the final string another
1506 * 0-byte follows to indicate the end of the strings.
1507 * i.e.:
1508 * \??\D:\test\file1[0]
1509 * !\??\D:\test\file1_renamed[0]
1510 * \??\D:\Test|delete[0]
1511 * [0] <- file is to be deleted, second string empty
1512 * \??\D:\test\file2[0]
1513 * !\??\D:\test\file2_renamed[0]
1514 * [0] <- indicates end of strings
1516 * or:
1517 * \??\D:\test\file1[0]
1518 * !\??\D:\test\file1_renamed[0]
1519 * \??\D:\Test|delete[0]
1520 * [0] <- file is to be deleted, second string empty
1521 * [0] <- indicates end of strings
1524 static BOOL FILE_AddBootRenameEntry( LPCWSTR fn1, LPCWSTR fn2, DWORD flags )
1526 static const WCHAR PreString[] = {'\\','?','?','\\',0};
1527 static const WCHAR ValueName[] = {'P','e','n','d','i','n','g',
1528 'F','i','l','e','R','e','n','a','m','e',
1529 'O','p','e','r','a','t','i','o','n','s',0};
1530 static const WCHAR SessionW[] = {'M','a','c','h','i','n','e','\\',
1531 'S','y','s','t','e','m','\\',
1532 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
1533 'C','o','n','t','r','o','l','\\',
1534 'S','e','s','s','i','o','n',' ','M','a','n','a','g','e','r',0};
1535 static const int info_size = FIELD_OFFSET( KEY_VALUE_PARTIAL_INFORMATION, Data );
1537 OBJECT_ATTRIBUTES attr;
1538 UNICODE_STRING nameW;
1539 KEY_VALUE_PARTIAL_INFORMATION *info;
1540 BOOL rc = FALSE;
1541 HKEY Reboot = 0;
1542 DWORD len0, len1, len2;
1543 DWORD DataSize = 0;
1544 BYTE *Buffer = NULL;
1545 WCHAR *p;
1547 attr.Length = sizeof(attr);
1548 attr.RootDirectory = 0;
1549 attr.ObjectName = &nameW;
1550 attr.Attributes = 0;
1551 attr.SecurityDescriptor = NULL;
1552 attr.SecurityQualityOfService = NULL;
1553 RtlInitUnicodeString( &nameW, SessionW );
1555 if (NtCreateKey( &Reboot, KEY_ALL_ACCESS, &attr, 0, NULL, 0, NULL ) != STATUS_SUCCESS)
1557 WARN("Error creating key for reboot managment [%s]\n",
1558 "SYSTEM\\CurrentControlSet\\Control\\Session Manager");
1559 return FALSE;
1562 len0 = strlenW(PreString);
1563 len1 = strlenW(fn1) + len0 + 1;
1564 if (fn2)
1566 len2 = strlenW(fn2) + len0 + 1;
1567 if (flags & MOVEFILE_REPLACE_EXISTING) len2++; /* Plus 1 because of the leading '!' */
1569 else len2 = 1; /* minimum is the 0 characters for the empty second string */
1571 /* convert characters to bytes */
1572 len0 *= sizeof(WCHAR);
1573 len1 *= sizeof(WCHAR);
1574 len2 *= sizeof(WCHAR);
1576 RtlInitUnicodeString( &nameW, ValueName );
1578 /* First we check if the key exists and if so how many bytes it already contains. */
1579 if (NtQueryValueKey( Reboot, &nameW, KeyValuePartialInformation,
1580 NULL, 0, &DataSize ) == STATUS_BUFFER_OVERFLOW)
1582 if (!(Buffer = HeapAlloc( GetProcessHeap(), 0, DataSize + len1 + len2 + sizeof(WCHAR) )))
1583 goto Quit;
1584 if (NtQueryValueKey( Reboot, &nameW, KeyValuePartialInformation,
1585 Buffer, DataSize, &DataSize )) goto Quit;
1586 info = (KEY_VALUE_PARTIAL_INFORMATION *)Buffer;
1587 if (info->Type != REG_MULTI_SZ) goto Quit;
1588 if (DataSize > sizeof(info)) DataSize -= sizeof(WCHAR); /* remove terminating null (will be added back later) */
1590 else
1592 DataSize = info_size;
1593 if (!(Buffer = HeapAlloc( GetProcessHeap(), 0, DataSize + len1 + len2 + sizeof(WCHAR) )))
1594 goto Quit;
1597 p = (WCHAR *)(Buffer + DataSize);
1598 strcpyW( p, PreString );
1599 strcatW( p, fn1 );
1600 DataSize += len1;
1601 if (fn2)
1603 p = (WCHAR *)(Buffer + DataSize);
1604 if (flags & MOVEFILE_REPLACE_EXISTING)
1605 *p++ = '!';
1606 strcpyW( p, PreString );
1607 strcatW( p, fn2 );
1608 DataSize += len2;
1610 else
1612 p = (WCHAR *)(Buffer + DataSize);
1613 *p = 0;
1614 DataSize += sizeof(WCHAR);
1617 /* add final null */
1618 p = (WCHAR *)(Buffer + DataSize);
1619 *p = 0;
1620 DataSize += sizeof(WCHAR);
1622 rc = !NtSetValueKey(Reboot, &nameW, 0, REG_MULTI_SZ, Buffer + info_size, DataSize - info_size);
1624 Quit:
1625 if (Reboot) NtClose(Reboot);
1626 if (Buffer) HeapFree( GetProcessHeap(), 0, Buffer );
1627 return(rc);
1631 /**************************************************************************
1632 * MoveFileExW (KERNEL32.@)
1634 BOOL WINAPI MoveFileExW( LPCWSTR fn1, LPCWSTR fn2, DWORD flag )
1636 DOS_FULL_NAME full_name1, full_name2;
1637 HANDLE hFile;
1638 DWORD attr = INVALID_FILE_ATTRIBUTES;
1640 TRACE("(%s,%s,%04lx)\n", debugstr_w(fn1), debugstr_w(fn2), flag);
1642 /* FIXME: <Gerhard W. Gruber>sparhawk@gmx.at
1643 In case of W9x and lesser this function should return 120 (ERROR_CALL_NOT_IMPLEMENTED)
1644 to be really compatible. Most programs won't have any problems though. In case
1645 you encounter one, this is what you should return here. I don't know what's up
1646 with NT 3.5. Is this function available there or not?
1647 Does anybody really care about 3.5? :)
1650 /* Filename1 has to be always set to a valid path. Filename2 may be NULL
1651 if the source file has to be deleted.
1653 if (!fn1) {
1654 SetLastError(ERROR_INVALID_PARAMETER);
1655 return FALSE;
1658 /* This function has to be run through in order to process the name properly.
1659 If the BOOTDELAY flag is set, the file doesn't need to exist though. At least
1660 that is the behaviour on NT 4.0. The operation accepts the filenames as
1661 they are given but it can't reply with a reasonable returncode. Success
1662 means in that case success for entering the values into the registry.
1664 if(!DOSFS_GetFullName( fn1, TRUE, &full_name1 ))
1666 if(!(flag & MOVEFILE_DELAY_UNTIL_REBOOT))
1667 return FALSE;
1670 if (fn2) /* !fn2 means delete fn1 */
1672 if (DOSFS_GetFullName( fn2, TRUE, &full_name2 ))
1674 if(!(flag & MOVEFILE_DELAY_UNTIL_REBOOT))
1676 /* target exists, check if we may overwrite */
1677 if (!(flag & MOVEFILE_REPLACE_EXISTING))
1679 SetLastError( ERROR_ALREADY_EXISTS );
1680 return FALSE;
1684 else
1686 if (!DOSFS_GetFullName( fn2, FALSE, &full_name2 ))
1688 if(!(flag & MOVEFILE_DELAY_UNTIL_REBOOT))
1689 return FALSE;
1693 /* Source name and target path are valid */
1695 if (flag & MOVEFILE_DELAY_UNTIL_REBOOT)
1697 return FILE_AddBootRenameEntry( fn1, fn2, flag );
1700 attr = GetFileAttributesW( fn1 );
1701 if ( attr == INVALID_FILE_ATTRIBUTES ) return FALSE;
1703 /* check if we are allowed to rename the source */
1704 hFile = FILE_CreateFile( full_name1.long_name, 0, 0,
1705 NULL, OPEN_EXISTING, 0, 0, TRUE,
1706 GetDriveTypeW( full_name1.short_name ) );
1707 if (!hFile)
1709 if (GetLastError() != ERROR_ACCESS_DENIED) return FALSE;
1710 if ( !(attr & FILE_ATTRIBUTE_DIRECTORY) ) return FALSE;
1711 /* if it's a directory we can continue */
1713 else CloseHandle(hFile);
1715 /* check, if we are allowed to delete the destination,
1716 ** (but the file not being there is fine) */
1717 hFile = FILE_CreateFile( full_name2.long_name, GENERIC_READ|GENERIC_WRITE, 0,
1718 NULL, OPEN_EXISTING, 0, 0, TRUE,
1719 GetDriveTypeW( full_name2.short_name ) );
1720 if(!hFile && GetLastError() != ERROR_FILE_NOT_FOUND) return FALSE;
1721 CloseHandle(hFile);
1723 if (full_name1.drive != full_name2.drive)
1725 if (!(flag & MOVEFILE_COPY_ALLOWED))
1727 SetLastError( ERROR_NOT_SAME_DEVICE );
1728 return FALSE;
1730 else if ( attr & FILE_ATTRIBUTE_DIRECTORY )
1732 /* Strange, but that's what Windows returns */
1733 SetLastError ( ERROR_ACCESS_DENIED );
1734 return FALSE;
1737 if (rename( full_name1.long_name, full_name2.long_name ) == -1)
1738 /* Try copy/delete unless it's a directory. */
1739 /* FIXME: This does not handle the (unlikely) case that the two locations
1740 are on the same Wine drive, but on different Unix file systems. */
1742 if ( attr & FILE_ATTRIBUTE_DIRECTORY )
1744 FILE_SetDosError();
1745 return FALSE;
1747 else
1749 if ( ! CopyFileW( fn1, fn2, !(flag & MOVEFILE_REPLACE_EXISTING) ))
1750 return FALSE;
1751 if ( ! DeleteFileW ( fn1 ) )
1752 return FALSE;
1755 if (is_executable( full_name1.long_name ) != is_executable( full_name2.long_name ))
1757 struct stat fstat;
1758 if (stat( full_name2.long_name, &fstat ) != -1)
1760 if (is_executable( full_name2.long_name ))
1761 /* set executable bit where read bit is set */
1762 fstat.st_mode |= (fstat.st_mode & 0444) >> 2;
1763 else
1764 fstat.st_mode &= ~0111;
1765 chmod( full_name2.long_name, fstat.st_mode );
1768 return TRUE;
1770 else /* fn2 == NULL means delete source */
1772 if (flag & MOVEFILE_DELAY_UNTIL_REBOOT)
1774 if (flag & MOVEFILE_COPY_ALLOWED) {
1775 WARN("Illegal flag\n");
1776 SetLastError( ERROR_GEN_FAILURE );
1777 return FALSE;
1780 return FILE_AddBootRenameEntry( fn1, NULL, flag );
1783 if (unlink( full_name1.long_name ) == -1)
1785 FILE_SetDosError();
1786 return FALSE;
1788 return TRUE; /* successfully deleted */
1792 /**************************************************************************
1793 * MoveFileExA (KERNEL32.@)
1795 BOOL WINAPI MoveFileExA( LPCSTR fn1, LPCSTR fn2, DWORD flag )
1797 UNICODE_STRING fn1W, fn2W;
1798 BOOL ret;
1800 if (!fn1)
1802 SetLastError(ERROR_INVALID_PARAMETER);
1803 return FALSE;
1806 RtlCreateUnicodeStringFromAsciiz(&fn1W, fn1);
1807 if (fn2) RtlCreateUnicodeStringFromAsciiz(&fn2W, fn2);
1808 else fn2W.Buffer = NULL;
1810 ret = MoveFileExW( fn1W.Buffer, fn2W.Buffer, flag );
1812 RtlFreeUnicodeString(&fn1W);
1813 RtlFreeUnicodeString(&fn2W);
1814 return ret;
1818 /**************************************************************************
1819 * MoveFileW (KERNEL32.@)
1821 * Move file or directory
1823 BOOL WINAPI MoveFileW( LPCWSTR fn1, LPCWSTR fn2 )
1825 return MoveFileExW( fn1, fn2, MOVEFILE_COPY_ALLOWED );
1829 /**************************************************************************
1830 * MoveFileA (KERNEL32.@)
1832 BOOL WINAPI MoveFileA( LPCSTR fn1, LPCSTR fn2 )
1834 return MoveFileExA( fn1, fn2, MOVEFILE_COPY_ALLOWED );
1838 /**************************************************************************
1839 * CopyFileW (KERNEL32.@)
1841 BOOL WINAPI CopyFileW( LPCWSTR source, LPCWSTR dest, BOOL fail_if_exists )
1843 HANDLE h1, h2;
1844 BY_HANDLE_FILE_INFORMATION info;
1845 DWORD count;
1846 BOOL ret = FALSE;
1847 char buffer[2048];
1849 if (!source || !dest)
1851 SetLastError(ERROR_INVALID_PARAMETER);
1852 return FALSE;
1855 TRACE("%s -> %s\n", debugstr_w(source), debugstr_w(dest));
1857 if ((h1 = CreateFileW(source, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE,
1858 NULL, OPEN_EXISTING, 0, 0)) == INVALID_HANDLE_VALUE)
1860 WARN("Unable to open source %s\n", debugstr_w(source));
1861 return FALSE;
1864 if (!GetFileInformationByHandle( h1, &info ))
1866 WARN("GetFileInformationByHandle returned error for %s\n", debugstr_w(source));
1867 CloseHandle( h1 );
1868 return FALSE;
1871 if ((h2 = CreateFileW( dest, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
1872 fail_if_exists ? CREATE_NEW : CREATE_ALWAYS,
1873 info.dwFileAttributes, h1 )) == INVALID_HANDLE_VALUE)
1875 WARN("Unable to open dest %s\n", debugstr_w(dest));
1876 CloseHandle( h1 );
1877 return FALSE;
1880 while (ReadFile( h1, buffer, sizeof(buffer), &count, NULL ) && count)
1882 char *p = buffer;
1883 while (count != 0)
1885 DWORD res;
1886 if (!WriteFile( h2, p, count, &res, NULL ) || !res) goto done;
1887 p += res;
1888 count -= res;
1891 ret = TRUE;
1892 done:
1893 CloseHandle( h1 );
1894 CloseHandle( h2 );
1895 return ret;
1899 /**************************************************************************
1900 * CopyFileA (KERNEL32.@)
1902 BOOL WINAPI CopyFileA( LPCSTR source, LPCSTR dest, BOOL fail_if_exists)
1904 UNICODE_STRING sourceW, destW;
1905 BOOL ret;
1907 if (!source || !dest)
1909 SetLastError(ERROR_INVALID_PARAMETER);
1910 return FALSE;
1913 RtlCreateUnicodeStringFromAsciiz(&sourceW, source);
1914 RtlCreateUnicodeStringFromAsciiz(&destW, dest);
1916 ret = CopyFileW(sourceW.Buffer, destW.Buffer, fail_if_exists);
1918 RtlFreeUnicodeString(&sourceW);
1919 RtlFreeUnicodeString(&destW);
1920 return ret;
1924 /**************************************************************************
1925 * CopyFileExW (KERNEL32.@)
1927 * This implementation ignores most of the extra parameters passed-in into
1928 * the "ex" version of the method and calls the CopyFile method.
1929 * It will have to be fixed eventually.
1931 BOOL WINAPI CopyFileExW(LPCWSTR sourceFilename, LPCWSTR destFilename,
1932 LPPROGRESS_ROUTINE progressRoutine, LPVOID appData,
1933 LPBOOL cancelFlagPointer, DWORD copyFlags)
1936 * Interpret the only flag that CopyFile can interpret.
1938 return CopyFileW(sourceFilename, destFilename, (copyFlags & COPY_FILE_FAIL_IF_EXISTS) != 0);
1942 /**************************************************************************
1943 * CopyFileExA (KERNEL32.@)
1945 BOOL WINAPI CopyFileExA(LPCSTR sourceFilename, LPCSTR destFilename,
1946 LPPROGRESS_ROUTINE progressRoutine, LPVOID appData,
1947 LPBOOL cancelFlagPointer, DWORD copyFlags)
1949 UNICODE_STRING sourceW, destW;
1950 BOOL ret;
1952 if (!sourceFilename || !destFilename)
1954 SetLastError(ERROR_INVALID_PARAMETER);
1955 return FALSE;
1958 RtlCreateUnicodeStringFromAsciiz(&sourceW, sourceFilename);
1959 RtlCreateUnicodeStringFromAsciiz(&destW, destFilename);
1961 ret = CopyFileExW(sourceW.Buffer, destW.Buffer, progressRoutine, appData,
1962 cancelFlagPointer, copyFlags);
1964 RtlFreeUnicodeString(&sourceW);
1965 RtlFreeUnicodeString(&destW);
1966 return ret;
1970 /***********************************************************************
1971 * SetFileTime (KERNEL32.@)
1973 BOOL WINAPI SetFileTime( HANDLE hFile,
1974 const FILETIME *lpCreationTime,
1975 const FILETIME *lpLastAccessTime,
1976 const FILETIME *lpLastWriteTime )
1978 BOOL ret;
1979 SERVER_START_REQ( set_file_time )
1981 req->handle = hFile;
1982 if (lpLastAccessTime)
1983 RtlTimeToSecondsSince1970( (PLARGE_INTEGER) lpLastAccessTime, (DWORD *)&req->access_time );
1984 else
1985 req->access_time = 0; /* FIXME */
1986 if (lpLastWriteTime)
1987 RtlTimeToSecondsSince1970( (PLARGE_INTEGER) lpLastWriteTime, (DWORD *)&req->write_time );
1988 else
1989 req->write_time = 0; /* FIXME */
1990 ret = !wine_server_call_err( req );
1992 SERVER_END_REQ;
1993 return ret;
1997 /**************************************************************************
1998 * GetFileAttributesExW (KERNEL32.@)
2000 BOOL WINAPI GetFileAttributesExW(
2001 LPCWSTR lpFileName, GET_FILEEX_INFO_LEVELS fInfoLevelId,
2002 LPVOID lpFileInformation)
2004 DOS_FULL_NAME full_name;
2005 BY_HANDLE_FILE_INFORMATION info;
2007 if (!lpFileName || !lpFileInformation)
2009 SetLastError(ERROR_INVALID_PARAMETER);
2010 return FALSE;
2013 if (fInfoLevelId == GetFileExInfoStandard) {
2014 LPWIN32_FILE_ATTRIBUTE_DATA lpFad =
2015 (LPWIN32_FILE_ATTRIBUTE_DATA) lpFileInformation;
2016 if (!DOSFS_GetFullName( lpFileName, TRUE, &full_name )) return FALSE;
2017 if (!FILE_Stat( full_name.long_name, &info, NULL )) return FALSE;
2019 lpFad->dwFileAttributes = info.dwFileAttributes;
2020 lpFad->ftCreationTime = info.ftCreationTime;
2021 lpFad->ftLastAccessTime = info.ftLastAccessTime;
2022 lpFad->ftLastWriteTime = info.ftLastWriteTime;
2023 lpFad->nFileSizeHigh = info.nFileSizeHigh;
2024 lpFad->nFileSizeLow = info.nFileSizeLow;
2026 else {
2027 FIXME("invalid info level %d!\n", fInfoLevelId);
2028 return FALSE;
2031 return TRUE;
2035 /**************************************************************************
2036 * GetFileAttributesExA (KERNEL32.@)
2038 BOOL WINAPI GetFileAttributesExA(
2039 LPCSTR filename, GET_FILEEX_INFO_LEVELS fInfoLevelId,
2040 LPVOID lpFileInformation)
2042 UNICODE_STRING filenameW;
2043 BOOL ret = FALSE;
2045 if (!filename || !lpFileInformation)
2047 SetLastError(ERROR_INVALID_PARAMETER);
2048 return FALSE;
2051 if (RtlCreateUnicodeStringFromAsciiz(&filenameW, filename))
2053 ret = GetFileAttributesExW(filenameW.Buffer, fInfoLevelId, lpFileInformation);
2054 RtlFreeUnicodeString(&filenameW);
2056 else
2057 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
2058 return ret;