Small fix for the WPR_SIGNED case (count the sign).
[wine/multimedia.git] / files / file.c
blob9c4167836764cc20c69ffc8730cd3441586b114a
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 = DEVICE_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|FILE_ATTRIBUTE_SYSTEM);
747 if (attributes)
748 FIXME("(%s):%lx attribute(s) not implemented.\n", debugstr_w(lpFileName), attributes);
749 if (-1==chmod(full_name.long_name,buf.st_mode))
751 if (GetDriveTypeW(lpFileName) == DRIVE_CDROM)
753 SetLastError( ERROR_ACCESS_DENIED );
754 return FALSE;
758 * FIXME: We don't return FALSE here because of differences between
759 * Linux and Windows privileges. Under Linux only the owner of
760 * the file is allowed to change file attributes. Under Windows,
761 * applications expect that if you can write to a file, you can also
762 * change its attributes (see GENERIC_WRITE). We could try to be
763 * clever here but that would break multi-user installations where
764 * users share read-only DLLs. This is because some installers like
765 * to change attributes of already installed DLLs.
767 FIXME("Couldn't set file attributes for existing file \"%s\".\n"
768 "Check permissions or set VFAT \"quiet\" mount flag\n", full_name.long_name);
770 return TRUE;
774 /**************************************************************************
775 * SetFileAttributesA (KERNEL32.@)
777 BOOL WINAPI SetFileAttributesA(LPCSTR lpFileName, DWORD attributes)
779 UNICODE_STRING filenameW;
780 BOOL ret = FALSE;
782 if (!lpFileName)
784 SetLastError( ERROR_INVALID_PARAMETER );
785 return FALSE;
788 if (RtlCreateUnicodeStringFromAsciiz(&filenameW, lpFileName))
790 ret = SetFileAttributesW(filenameW.Buffer, attributes);
791 RtlFreeUnicodeString(&filenameW);
793 else
794 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
795 return ret;
799 /******************************************************************************
800 * GetCompressedFileSizeA [KERNEL32.@]
802 DWORD WINAPI GetCompressedFileSizeA(
803 LPCSTR lpFileName,
804 LPDWORD lpFileSizeHigh)
806 UNICODE_STRING filenameW;
807 DWORD ret;
809 if (RtlCreateUnicodeStringFromAsciiz(&filenameW, lpFileName))
811 ret = GetCompressedFileSizeW(filenameW.Buffer, lpFileSizeHigh);
812 RtlFreeUnicodeString(&filenameW);
814 else
816 ret = INVALID_FILE_SIZE;
817 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
819 return ret;
823 /******************************************************************************
824 * GetCompressedFileSizeW [KERNEL32.@]
826 * RETURNS
827 * Success: Low-order doubleword of number of bytes
828 * Failure: INVALID_FILE_SIZE
830 DWORD WINAPI GetCompressedFileSizeW(
831 LPCWSTR lpFileName, /* [in] Pointer to name of file */
832 LPDWORD lpFileSizeHigh) /* [out] Receives high-order doubleword of size */
834 DOS_FULL_NAME full_name;
835 struct stat st;
836 DWORD low;
838 TRACE("(%s,%p)\n",debugstr_w(lpFileName),lpFileSizeHigh);
840 if (!DOSFS_GetFullName( lpFileName, TRUE, &full_name )) return INVALID_FILE_SIZE;
841 if (stat(full_name.long_name, &st) != 0)
843 FILE_SetDosError();
844 return INVALID_FILE_SIZE;
846 #if HAVE_STRUCT_STAT_ST_BLOCKS
847 /* blocks are 512 bytes long */
848 if (lpFileSizeHigh) *lpFileSizeHigh = (st.st_blocks >> 23);
849 low = (DWORD)(st.st_blocks << 9);
850 #else
851 if (lpFileSizeHigh) *lpFileSizeHigh = (st.st_size >> 32);
852 low = (DWORD)st.st_size;
853 #endif
854 return low;
858 /***********************************************************************
859 * GetFileTime (KERNEL32.@)
861 BOOL WINAPI GetFileTime( HANDLE hFile, FILETIME *lpCreationTime,
862 FILETIME *lpLastAccessTime,
863 FILETIME *lpLastWriteTime )
865 BY_HANDLE_FILE_INFORMATION info;
866 if (!GetFileInformationByHandle( hFile, &info )) return FALSE;
867 if (lpCreationTime) *lpCreationTime = info.ftCreationTime;
868 if (lpLastAccessTime) *lpLastAccessTime = info.ftLastAccessTime;
869 if (lpLastWriteTime) *lpLastWriteTime = info.ftLastWriteTime;
870 return TRUE;
874 /***********************************************************************
875 * GetTempFileNameA (KERNEL32.@)
877 UINT WINAPI GetTempFileNameA( LPCSTR path, LPCSTR prefix, UINT unique,
878 LPSTR buffer)
880 UNICODE_STRING pathW, prefixW;
881 WCHAR bufferW[MAX_PATH];
882 UINT ret;
884 if ( !path || !prefix || !buffer )
886 SetLastError( ERROR_INVALID_PARAMETER );
887 return 0;
890 RtlCreateUnicodeStringFromAsciiz(&pathW, path);
891 RtlCreateUnicodeStringFromAsciiz(&prefixW, prefix);
893 ret = GetTempFileNameW(pathW.Buffer, prefixW.Buffer, unique, bufferW);
894 if (ret)
895 WideCharToMultiByte(CP_ACP, 0, bufferW, -1, buffer, MAX_PATH, NULL, NULL);
897 RtlFreeUnicodeString(&pathW);
898 RtlFreeUnicodeString(&prefixW);
899 return ret;
902 /***********************************************************************
903 * GetTempFileNameW (KERNEL32.@)
905 UINT WINAPI GetTempFileNameW( LPCWSTR path, LPCWSTR prefix, UINT unique,
906 LPWSTR buffer )
908 static const WCHAR formatW[] = {'%','x','.','t','m','p',0};
910 DOS_FULL_NAME full_name;
911 int i;
912 LPWSTR p;
914 if ( !path || !prefix || !buffer )
916 SetLastError( ERROR_INVALID_PARAMETER );
917 return 0;
920 strcpyW( buffer, path );
921 p = buffer + strlenW(buffer);
923 /* add a \, if there isn't one */
924 if ((p == buffer) || (p[-1] != '\\')) *p++ = '\\';
926 for (i = 3; (i > 0) && (*prefix); i--) *p++ = *prefix++;
928 unique &= 0xffff;
930 if (unique) sprintfW( p, formatW, unique );
931 else
933 /* get a "random" unique number and try to create the file */
934 HANDLE handle;
935 UINT num = GetTickCount() & 0xffff;
937 if (!num) num = 1;
938 unique = num;
941 sprintfW( p, formatW, unique );
942 handle = CreateFileW( buffer, GENERIC_WRITE, 0, NULL,
943 CREATE_NEW, FILE_ATTRIBUTE_NORMAL, 0 );
944 if (handle != INVALID_HANDLE_VALUE)
945 { /* We created it */
946 TRACE("created %s\n", debugstr_w(buffer) );
947 CloseHandle( handle );
948 break;
950 if (GetLastError() != ERROR_FILE_EXISTS &&
951 GetLastError() != ERROR_SHARING_VIOLATION)
952 break; /* No need to go on */
953 if (!(++unique & 0xffff)) unique = 1;
954 } while (unique != num);
957 /* Get the full path name */
959 if (DOSFS_GetFullName( buffer, FALSE, &full_name ))
961 char *slash;
962 /* Check if we have write access in the directory */
963 if ((slash = strrchr( full_name.long_name, '/' ))) *slash = '\0';
964 if (access( full_name.long_name, W_OK ) == -1)
965 WARN("returns %s, which doesn't seem to be writeable.\n",
966 debugstr_w(buffer) );
968 TRACE("returning %s\n", debugstr_w(buffer) );
969 return unique;
973 /***********************************************************************
974 * FILE_DoOpenFile
976 * Implementation of OpenFile16() and OpenFile32().
978 static HFILE FILE_DoOpenFile( LPCSTR name, OFSTRUCT *ofs, UINT mode, BOOL win32 )
980 HFILE hFileRet;
981 HANDLE handle;
982 FILETIME filetime;
983 WORD filedatetime[2];
984 DOS_FULL_NAME full_name;
985 DWORD access, sharing;
986 WCHAR *p;
987 WCHAR buffer[MAX_PATH];
988 LPWSTR nameW;
990 if (!ofs) return HFILE_ERROR;
992 TRACE("%s %s %s %s%s%s%s%s%s%s%s%s\n",name,
993 ((mode & 0x3 )==OF_READ)?"OF_READ":
994 ((mode & 0x3 )==OF_WRITE)?"OF_WRITE":
995 ((mode & 0x3 )==OF_READWRITE)?"OF_READWRITE":"unknown",
996 ((mode & 0x70 )==OF_SHARE_COMPAT)?"OF_SHARE_COMPAT":
997 ((mode & 0x70 )==OF_SHARE_DENY_NONE)?"OF_SHARE_DENY_NONE":
998 ((mode & 0x70 )==OF_SHARE_DENY_READ)?"OF_SHARE_DENY_READ":
999 ((mode & 0x70 )==OF_SHARE_DENY_WRITE)?"OF_SHARE_DENY_WRITE":
1000 ((mode & 0x70 )==OF_SHARE_EXCLUSIVE)?"OF_SHARE_EXCLUSIVE":"unknown",
1001 ((mode & OF_PARSE )==OF_PARSE)?"OF_PARSE ":"",
1002 ((mode & OF_DELETE )==OF_DELETE)?"OF_DELETE ":"",
1003 ((mode & OF_VERIFY )==OF_VERIFY)?"OF_VERIFY ":"",
1004 ((mode & OF_SEARCH )==OF_SEARCH)?"OF_SEARCH ":"",
1005 ((mode & OF_CANCEL )==OF_CANCEL)?"OF_CANCEL ":"",
1006 ((mode & OF_CREATE )==OF_CREATE)?"OF_CREATE ":"",
1007 ((mode & OF_PROMPT )==OF_PROMPT)?"OF_PROMPT ":"",
1008 ((mode & OF_EXIST )==OF_EXIST)?"OF_EXIST ":"",
1009 ((mode & OF_REOPEN )==OF_REOPEN)?"OF_REOPEN ":""
1013 ofs->cBytes = sizeof(OFSTRUCT);
1014 ofs->nErrCode = 0;
1015 if (mode & OF_REOPEN) name = ofs->szPathName;
1017 if (!name) {
1018 ERR("called with `name' set to NULL ! Please debug.\n");
1019 return HFILE_ERROR;
1022 TRACE("%s %04x\n", name, mode );
1024 /* the watcom 10.6 IDE relies on a valid path returned in ofs->szPathName
1025 Are there any cases where getting the path here is wrong?
1026 Uwe Bonnes 1997 Apr 2 */
1027 if (!GetFullPathNameA( name, sizeof(ofs->szPathName),
1028 ofs->szPathName, NULL )) goto error;
1029 FILE_ConvertOFMode( mode, &access, &sharing );
1031 /* OF_PARSE simply fills the structure */
1033 if (mode & OF_PARSE)
1035 ofs->fFixedDisk = (GetDriveType16( ofs->szPathName[0]-'A' )
1036 != DRIVE_REMOVABLE);
1037 TRACE("(%s): OF_PARSE, res = '%s'\n",
1038 name, ofs->szPathName );
1039 return 0;
1042 /* OF_CREATE is completely different from all other options, so
1043 handle it first */
1045 if (mode & OF_CREATE)
1047 if ((handle = CreateFileA( name, GENERIC_READ | GENERIC_WRITE,
1048 sharing, NULL, CREATE_ALWAYS,
1049 FILE_ATTRIBUTE_NORMAL, 0 ))== INVALID_HANDLE_VALUE)
1050 goto error;
1051 goto success;
1054 MultiByteToWideChar(CP_ACP, 0, name, -1, buffer, MAX_PATH);
1055 nameW = buffer;
1057 /* If OF_SEARCH is set, ignore the given path */
1059 if ((mode & OF_SEARCH) && !(mode & OF_REOPEN))
1061 /* First try the file name as is */
1062 if (DOSFS_GetFullName( nameW, TRUE, &full_name )) goto found;
1063 /* Now remove the path */
1064 if (nameW[0] && (nameW[1] == ':')) nameW += 2;
1065 if ((p = strrchrW( nameW, '\\' ))) nameW = p + 1;
1066 if ((p = strrchrW( nameW, '/' ))) nameW = p + 1;
1067 if (!nameW[0]) goto not_found;
1070 /* Now look for the file */
1072 if (!DIR_SearchPath( NULL, nameW, NULL, &full_name, win32 )) goto not_found;
1074 found:
1075 TRACE("found %s = %s\n",
1076 full_name.long_name, debugstr_w(full_name.short_name) );
1077 WideCharToMultiByte(CP_ACP, 0, full_name.short_name, -1,
1078 ofs->szPathName, sizeof(ofs->szPathName), NULL, NULL);
1080 if (mode & OF_DELETE)
1082 handle = FILE_CreateFile( full_name.long_name, GENERIC_READ|GENERIC_WRITE, 0,
1083 NULL, OPEN_EXISTING, 0, 0, TRUE,
1084 GetDriveTypeW( full_name.short_name ) );
1085 if (!handle) goto error;
1086 CloseHandle( handle );
1087 if (unlink( full_name.long_name ) == -1) goto not_found;
1088 TRACE("(%s): OF_DELETE return = OK\n", name);
1089 return 1;
1092 handle = FILE_CreateFile( full_name.long_name, access, sharing,
1093 NULL, OPEN_EXISTING, 0, 0,
1094 DRIVE_GetFlags(full_name.drive) & DRIVE_FAIL_READ_ONLY,
1095 GetDriveTypeW( full_name.short_name ) );
1096 if (!handle) goto not_found;
1098 GetFileTime( handle, NULL, NULL, &filetime );
1099 FileTimeToDosDateTime( &filetime, &filedatetime[0], &filedatetime[1] );
1100 if ((mode & OF_VERIFY) && (mode & OF_REOPEN))
1102 if (ofs->Reserved1 != filedatetime[0] || ofs->Reserved2 != filedatetime[1] )
1104 CloseHandle( handle );
1105 WARN("(%s): OF_VERIFY failed\n", name );
1106 /* FIXME: what error here? */
1107 SetLastError( ERROR_FILE_NOT_FOUND );
1108 goto error;
1111 ofs->Reserved1 = filedatetime[0];
1112 ofs->Reserved2 = filedatetime[1];
1114 success: /* We get here if the open was successful */
1115 TRACE("(%s): OK, return = %p\n", name, handle );
1116 if (win32)
1118 hFileRet = (HFILE)handle;
1119 if (mode & OF_EXIST) /* Return the handle, but close it first */
1120 CloseHandle( handle );
1122 else
1124 hFileRet = Win32HandleToDosFileHandle( handle );
1125 if (hFileRet == HFILE_ERROR16) goto error;
1126 if (mode & OF_EXIST) /* Return the handle, but close it first */
1127 _lclose16( hFileRet );
1129 return hFileRet;
1131 not_found: /* We get here if the file does not exist */
1132 WARN("'%s' not found or sharing violation\n", name );
1133 SetLastError( ERROR_FILE_NOT_FOUND );
1134 /* fall through */
1136 error: /* We get here if there was an error opening the file */
1137 ofs->nErrCode = GetLastError();
1138 WARN("(%s): return = HFILE_ERROR error= %d\n",
1139 name,ofs->nErrCode );
1140 return HFILE_ERROR;
1144 /***********************************************************************
1145 * OpenFile (KERNEL.74)
1146 * OpenFileEx (KERNEL.360)
1148 HFILE16 WINAPI OpenFile16( LPCSTR name, OFSTRUCT *ofs, UINT16 mode )
1150 return FILE_DoOpenFile( name, ofs, mode, FALSE );
1154 /***********************************************************************
1155 * OpenFile (KERNEL32.@)
1157 HFILE WINAPI OpenFile( LPCSTR name, OFSTRUCT *ofs, UINT mode )
1159 return FILE_DoOpenFile( name, ofs, mode, TRUE );
1163 /******************************************************************
1164 * FILE_ReadWriteApc (internal)
1168 static void WINAPI FILE_ReadWriteApc(void* apc_user, PIO_STATUS_BLOCK io_status, ULONG len)
1170 LPOVERLAPPED_COMPLETION_ROUTINE cr = (LPOVERLAPPED_COMPLETION_ROUTINE)apc_user;
1172 cr(RtlNtStatusToDosError(io_status->u.Status), len, (LPOVERLAPPED)io_status);
1175 /***********************************************************************
1176 * ReadFileEx (KERNEL32.@)
1178 BOOL WINAPI ReadFileEx(HANDLE hFile, LPVOID buffer, DWORD bytesToRead,
1179 LPOVERLAPPED overlapped,
1180 LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine)
1182 LARGE_INTEGER offset;
1183 NTSTATUS status;
1184 PIO_STATUS_BLOCK io_status;
1186 if (!overlapped)
1188 SetLastError(ERROR_INVALID_PARAMETER);
1189 return FALSE;
1192 offset.u.LowPart = overlapped->Offset;
1193 offset.u.HighPart = overlapped->OffsetHigh;
1194 io_status = (PIO_STATUS_BLOCK)overlapped;
1195 io_status->u.Status = STATUS_PENDING;
1197 status = NtReadFile(hFile, NULL, FILE_ReadWriteApc, lpCompletionRoutine,
1198 io_status, buffer, bytesToRead, &offset, NULL);
1200 if (status)
1202 SetLastError( RtlNtStatusToDosError(status) );
1203 return FALSE;
1205 return TRUE;
1208 /***********************************************************************
1209 * ReadFile (KERNEL32.@)
1211 BOOL WINAPI ReadFile( HANDLE hFile, LPVOID buffer, DWORD bytesToRead,
1212 LPDWORD bytesRead, LPOVERLAPPED overlapped )
1214 LARGE_INTEGER offset;
1215 PLARGE_INTEGER poffset = NULL;
1216 IO_STATUS_BLOCK iosb;
1217 PIO_STATUS_BLOCK io_status = &iosb;
1218 HANDLE hEvent = 0;
1219 NTSTATUS status;
1221 TRACE("%p %p %ld %p %p\n", hFile, buffer, bytesToRead,
1222 bytesRead, overlapped );
1224 if (bytesRead) *bytesRead = 0; /* Do this before anything else */
1225 if (!bytesToRead) return TRUE;
1227 if (IsBadReadPtr(buffer, bytesToRead))
1229 SetLastError(ERROR_WRITE_FAULT); /* FIXME */
1230 return FALSE;
1232 if (is_console_handle(hFile))
1233 return ReadConsoleA(hFile, buffer, bytesToRead, bytesRead, NULL);
1235 if (overlapped != NULL)
1237 offset.u.LowPart = overlapped->Offset;
1238 offset.u.HighPart = overlapped->OffsetHigh;
1239 poffset = &offset;
1240 hEvent = overlapped->hEvent;
1241 io_status = (PIO_STATUS_BLOCK)overlapped;
1243 io_status->u.Status = STATUS_PENDING;
1244 io_status->Information = 0;
1246 status = NtReadFile(hFile, hEvent, NULL, NULL, io_status, buffer, bytesToRead, poffset, NULL);
1248 if (status != STATUS_PENDING && bytesRead)
1249 *bytesRead = io_status->Information;
1251 if (status && status != STATUS_END_OF_FILE)
1253 SetLastError( RtlNtStatusToDosError(status) );
1254 return FALSE;
1256 return TRUE;
1260 /***********************************************************************
1261 * WriteFileEx (KERNEL32.@)
1263 BOOL WINAPI WriteFileEx(HANDLE hFile, LPCVOID buffer, DWORD bytesToWrite,
1264 LPOVERLAPPED overlapped,
1265 LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine)
1267 LARGE_INTEGER offset;
1268 NTSTATUS status;
1269 PIO_STATUS_BLOCK io_status;
1271 TRACE("%p %p %ld %p %p\n",
1272 hFile, buffer, bytesToWrite, overlapped, lpCompletionRoutine);
1274 if (overlapped == NULL)
1276 SetLastError(ERROR_INVALID_PARAMETER);
1277 return FALSE;
1279 offset.u.LowPart = overlapped->Offset;
1280 offset.u.HighPart = overlapped->OffsetHigh;
1282 io_status = (PIO_STATUS_BLOCK)overlapped;
1283 io_status->u.Status = STATUS_PENDING;
1285 status = NtWriteFile(hFile, NULL, FILE_ReadWriteApc, lpCompletionRoutine,
1286 io_status, buffer, bytesToWrite, &offset, NULL);
1288 if (status) SetLastError( RtlNtStatusToDosError(status) );
1289 return !status;
1292 /***********************************************************************
1293 * WriteFile (KERNEL32.@)
1295 BOOL WINAPI WriteFile( HANDLE hFile, LPCVOID buffer, DWORD bytesToWrite,
1296 LPDWORD bytesWritten, LPOVERLAPPED overlapped )
1298 HANDLE hEvent = NULL;
1299 LARGE_INTEGER offset;
1300 PLARGE_INTEGER poffset = NULL;
1301 NTSTATUS status;
1302 IO_STATUS_BLOCK iosb;
1303 PIO_STATUS_BLOCK piosb = &iosb;
1305 TRACE("%p %p %ld %p %p\n",
1306 hFile, buffer, bytesToWrite, bytesWritten, overlapped );
1308 if (is_console_handle(hFile))
1309 return WriteConsoleA(hFile, buffer, bytesToWrite, bytesWritten, NULL);
1311 if (IsBadReadPtr(buffer, bytesToWrite))
1313 SetLastError(ERROR_READ_FAULT); /* FIXME */
1314 return FALSE;
1317 if (overlapped)
1319 offset.u.LowPart = overlapped->Offset;
1320 offset.u.HighPart = overlapped->OffsetHigh;
1321 poffset = &offset;
1322 hEvent = overlapped->hEvent;
1323 piosb = (PIO_STATUS_BLOCK)overlapped;
1325 piosb->u.Status = STATUS_PENDING;
1326 piosb->Information = 0;
1328 status = NtWriteFile(hFile, hEvent, NULL, NULL, piosb,
1329 buffer, bytesToWrite, poffset, NULL);
1330 if (status)
1332 SetLastError( RtlNtStatusToDosError(status) );
1333 return FALSE;
1335 if (bytesWritten) *bytesWritten = piosb->Information;
1337 return TRUE;
1341 /***********************************************************************
1342 * SetFilePointer (KERNEL32.@)
1344 DWORD WINAPI SetFilePointer( HANDLE hFile, LONG distance, LONG *highword,
1345 DWORD method )
1347 DWORD ret = INVALID_SET_FILE_POINTER;
1349 TRACE("handle %p offset %ld high %ld origin %ld\n",
1350 hFile, distance, highword?*highword:0, method );
1352 SERVER_START_REQ( set_file_pointer )
1354 req->handle = hFile;
1355 req->low = distance;
1356 req->high = highword ? *highword : (distance >= 0) ? 0 : -1;
1357 /* FIXME: assumes 1:1 mapping between Windows and Unix seek constants */
1358 req->whence = method;
1359 SetLastError( 0 );
1360 if (!wine_server_call_err( req ))
1362 ret = reply->new_low;
1363 if (highword) *highword = reply->new_high;
1366 SERVER_END_REQ;
1367 return ret;
1371 /*************************************************************************
1372 * SetHandleCount (KERNEL32.@)
1374 UINT WINAPI SetHandleCount( UINT count )
1376 return min( 256, count );
1380 /**************************************************************************
1381 * SetEndOfFile (KERNEL32.@)
1383 BOOL WINAPI SetEndOfFile( HANDLE hFile )
1385 BOOL ret;
1386 SERVER_START_REQ( truncate_file )
1388 req->handle = hFile;
1389 ret = !wine_server_call_err( req );
1391 SERVER_END_REQ;
1392 return ret;
1396 /***********************************************************************
1397 * DeleteFileW (KERNEL32.@)
1399 BOOL WINAPI DeleteFileW( LPCWSTR path )
1401 DOS_FULL_NAME full_name;
1402 HANDLE hFile;
1404 TRACE("%s\n", debugstr_w(path) );
1405 if (!path || !*path)
1407 SetLastError(ERROR_PATH_NOT_FOUND);
1408 return FALSE;
1410 if (DOSFS_GetDevice( path ))
1412 WARN("cannot remove DOS device %s!\n", debugstr_w(path));
1413 SetLastError( ERROR_FILE_NOT_FOUND );
1414 return FALSE;
1417 if (!DOSFS_GetFullName( path, TRUE, &full_name )) return FALSE;
1419 /* check if we are allowed to delete the source */
1420 hFile = FILE_CreateFile( full_name.long_name, GENERIC_READ|GENERIC_WRITE, 0,
1421 NULL, OPEN_EXISTING, 0, 0, TRUE,
1422 GetDriveTypeW( full_name.short_name ) );
1423 if (!hFile) return FALSE;
1425 if (unlink( full_name.long_name ) == -1)
1427 FILE_SetDosError();
1428 CloseHandle(hFile);
1429 return FALSE;
1431 CloseHandle(hFile);
1432 return TRUE;
1436 /***********************************************************************
1437 * DeleteFileA (KERNEL32.@)
1439 BOOL WINAPI DeleteFileA( LPCSTR path )
1441 UNICODE_STRING pathW;
1442 BOOL ret = FALSE;
1444 if (!path)
1446 SetLastError(ERROR_INVALID_PARAMETER);
1447 return FALSE;
1450 if (RtlCreateUnicodeStringFromAsciiz(&pathW, path))
1452 ret = DeleteFileW(pathW.Buffer);
1453 RtlFreeUnicodeString(&pathW);
1455 else
1456 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1457 return ret;
1461 /***********************************************************************
1462 * GetFileType (KERNEL32.@)
1464 DWORD WINAPI GetFileType( HANDLE hFile )
1466 DWORD ret = FILE_TYPE_UNKNOWN;
1468 if (is_console_handle( hFile ))
1469 return FILE_TYPE_CHAR;
1471 SERVER_START_REQ( get_file_info )
1473 req->handle = hFile;
1474 if (!wine_server_call_err( req )) ret = reply->type;
1476 SERVER_END_REQ;
1477 return ret;
1481 /* check if a file name is for an executable file (.exe or .com) */
1482 inline static BOOL is_executable( const char *name )
1484 int len = strlen(name);
1486 if (len < 4) return FALSE;
1487 return (!strcasecmp( name + len - 4, ".exe" ) ||
1488 !strcasecmp( name + len - 4, ".com" ));
1492 /***********************************************************************
1493 * FILE_AddBootRenameEntry
1495 * Adds an entry to the registry that is loaded when windows boots and
1496 * checks if there are some files to be removed or renamed/moved.
1497 * <fn1> has to be valid and <fn2> may be NULL. If both pointers are
1498 * non-NULL then the file is moved, otherwise it is deleted. The
1499 * entry of the registrykey is always appended with two zero
1500 * terminated strings. If <fn2> is NULL then the second entry is
1501 * simply a single 0-byte. Otherwise the second filename goes
1502 * there. The entries are prepended with \??\ before the path and the
1503 * second filename gets also a '!' as the first character if
1504 * MOVEFILE_REPLACE_EXISTING is set. After the final string another
1505 * 0-byte follows to indicate the end of the strings.
1506 * i.e.:
1507 * \??\D:\test\file1[0]
1508 * !\??\D:\test\file1_renamed[0]
1509 * \??\D:\Test|delete[0]
1510 * [0] <- file is to be deleted, second string empty
1511 * \??\D:\test\file2[0]
1512 * !\??\D:\test\file2_renamed[0]
1513 * [0] <- indicates end of strings
1515 * or:
1516 * \??\D:\test\file1[0]
1517 * !\??\D:\test\file1_renamed[0]
1518 * \??\D:\Test|delete[0]
1519 * [0] <- file is to be deleted, second string empty
1520 * [0] <- indicates end of strings
1523 static BOOL FILE_AddBootRenameEntry( LPCWSTR fn1, LPCWSTR fn2, DWORD flags )
1525 static const WCHAR PreString[] = {'\\','?','?','\\',0};
1526 static const WCHAR ValueName[] = {'P','e','n','d','i','n','g',
1527 'F','i','l','e','R','e','n','a','m','e',
1528 'O','p','e','r','a','t','i','o','n','s',0};
1529 static const WCHAR SessionW[] = {'M','a','c','h','i','n','e','\\',
1530 'S','y','s','t','e','m','\\',
1531 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
1532 'C','o','n','t','r','o','l','\\',
1533 'S','e','s','s','i','o','n',' ','M','a','n','a','g','e','r',0};
1534 static const int info_size = FIELD_OFFSET( KEY_VALUE_PARTIAL_INFORMATION, Data );
1536 OBJECT_ATTRIBUTES attr;
1537 UNICODE_STRING nameW;
1538 KEY_VALUE_PARTIAL_INFORMATION *info;
1539 BOOL rc = FALSE;
1540 HKEY Reboot = 0;
1541 DWORD len0, len1, len2;
1542 DWORD DataSize = 0;
1543 BYTE *Buffer = NULL;
1544 WCHAR *p;
1546 attr.Length = sizeof(attr);
1547 attr.RootDirectory = 0;
1548 attr.ObjectName = &nameW;
1549 attr.Attributes = 0;
1550 attr.SecurityDescriptor = NULL;
1551 attr.SecurityQualityOfService = NULL;
1552 RtlInitUnicodeString( &nameW, SessionW );
1554 if (NtCreateKey( &Reboot, KEY_ALL_ACCESS, &attr, 0, NULL, 0, NULL ) != STATUS_SUCCESS)
1556 WARN("Error creating key for reboot managment [%s]\n",
1557 "SYSTEM\\CurrentControlSet\\Control\\Session Manager");
1558 return FALSE;
1561 len0 = strlenW(PreString);
1562 len1 = strlenW(fn1) + len0 + 1;
1563 if (fn2)
1565 len2 = strlenW(fn2) + len0 + 1;
1566 if (flags & MOVEFILE_REPLACE_EXISTING) len2++; /* Plus 1 because of the leading '!' */
1568 else len2 = 1; /* minimum is the 0 characters for the empty second string */
1570 /* convert characters to bytes */
1571 len0 *= sizeof(WCHAR);
1572 len1 *= sizeof(WCHAR);
1573 len2 *= sizeof(WCHAR);
1575 RtlInitUnicodeString( &nameW, ValueName );
1577 /* First we check if the key exists and if so how many bytes it already contains. */
1578 if (NtQueryValueKey( Reboot, &nameW, KeyValuePartialInformation,
1579 NULL, 0, &DataSize ) == STATUS_BUFFER_OVERFLOW)
1581 if (!(Buffer = HeapAlloc( GetProcessHeap(), 0, DataSize + len1 + len2 + sizeof(WCHAR) )))
1582 goto Quit;
1583 if (NtQueryValueKey( Reboot, &nameW, KeyValuePartialInformation,
1584 Buffer, DataSize, &DataSize )) goto Quit;
1585 info = (KEY_VALUE_PARTIAL_INFORMATION *)Buffer;
1586 if (info->Type != REG_MULTI_SZ) goto Quit;
1587 if (DataSize > sizeof(info)) DataSize -= sizeof(WCHAR); /* remove terminating null (will be added back later) */
1589 else
1591 DataSize = info_size;
1592 if (!(Buffer = HeapAlloc( GetProcessHeap(), 0, DataSize + len1 + len2 + sizeof(WCHAR) )))
1593 goto Quit;
1596 p = (WCHAR *)(Buffer + DataSize);
1597 strcpyW( p, PreString );
1598 strcatW( p, fn1 );
1599 DataSize += len1;
1600 if (fn2)
1602 p = (WCHAR *)(Buffer + DataSize);
1603 if (flags & MOVEFILE_REPLACE_EXISTING)
1604 *p++ = '!';
1605 strcpyW( p, PreString );
1606 strcatW( p, fn2 );
1607 DataSize += len2;
1609 else
1611 p = (WCHAR *)(Buffer + DataSize);
1612 *p = 0;
1613 DataSize += sizeof(WCHAR);
1616 /* add final null */
1617 p = (WCHAR *)(Buffer + DataSize);
1618 *p = 0;
1619 DataSize += sizeof(WCHAR);
1621 rc = !NtSetValueKey(Reboot, &nameW, 0, REG_MULTI_SZ, Buffer + info_size, DataSize - info_size);
1623 Quit:
1624 if (Reboot) NtClose(Reboot);
1625 if (Buffer) HeapFree( GetProcessHeap(), 0, Buffer );
1626 return(rc);
1630 /**************************************************************************
1631 * MoveFileExW (KERNEL32.@)
1633 BOOL WINAPI MoveFileExW( LPCWSTR fn1, LPCWSTR fn2, DWORD flag )
1635 DOS_FULL_NAME full_name1, full_name2;
1636 HANDLE hFile;
1637 DWORD attr = INVALID_FILE_ATTRIBUTES;
1639 TRACE("(%s,%s,%04lx)\n", debugstr_w(fn1), debugstr_w(fn2), flag);
1641 /* FIXME: <Gerhard W. Gruber>sparhawk@gmx.at
1642 In case of W9x and lesser this function should return 120 (ERROR_CALL_NOT_IMPLEMENTED)
1643 to be really compatible. Most programs won't have any problems though. In case
1644 you encounter one, this is what you should return here. I don't know what's up
1645 with NT 3.5. Is this function available there or not?
1646 Does anybody really care about 3.5? :)
1649 /* Filename1 has to be always set to a valid path. Filename2 may be NULL
1650 if the source file has to be deleted.
1652 if (!fn1) {
1653 SetLastError(ERROR_INVALID_PARAMETER);
1654 return FALSE;
1657 /* This function has to be run through in order to process the name properly.
1658 If the BOOTDELAY flag is set, the file doesn't need to exist though. At least
1659 that is the behaviour on NT 4.0. The operation accepts the filenames as
1660 they are given but it can't reply with a reasonable returncode. Success
1661 means in that case success for entering the values into the registry.
1663 if(!DOSFS_GetFullName( fn1, TRUE, &full_name1 ))
1665 if(!(flag & MOVEFILE_DELAY_UNTIL_REBOOT))
1666 return FALSE;
1669 if (fn2) /* !fn2 means delete fn1 */
1671 if (DOSFS_GetFullName( fn2, TRUE, &full_name2 ))
1673 if(!(flag & MOVEFILE_DELAY_UNTIL_REBOOT))
1675 /* target exists, check if we may overwrite */
1676 if (!(flag & MOVEFILE_REPLACE_EXISTING))
1678 SetLastError( ERROR_ALREADY_EXISTS );
1679 return FALSE;
1683 else
1685 if (!DOSFS_GetFullName( fn2, FALSE, &full_name2 ))
1687 if(!(flag & MOVEFILE_DELAY_UNTIL_REBOOT))
1688 return FALSE;
1692 /* Source name and target path are valid */
1694 if (flag & MOVEFILE_DELAY_UNTIL_REBOOT)
1696 return FILE_AddBootRenameEntry( fn1, fn2, flag );
1699 attr = GetFileAttributesW( fn1 );
1700 if ( attr == INVALID_FILE_ATTRIBUTES ) return FALSE;
1702 /* check if we are allowed to rename the source */
1703 hFile = FILE_CreateFile( full_name1.long_name, 0, 0,
1704 NULL, OPEN_EXISTING, 0, 0, TRUE,
1705 GetDriveTypeW( full_name1.short_name ) );
1706 if (!hFile)
1708 if (GetLastError() != ERROR_ACCESS_DENIED) return FALSE;
1709 if ( !(attr & FILE_ATTRIBUTE_DIRECTORY) ) return FALSE;
1710 /* if it's a directory we can continue */
1712 else CloseHandle(hFile);
1714 /* check, if we are allowed to delete the destination,
1715 ** (but the file not being there is fine) */
1716 hFile = FILE_CreateFile( full_name2.long_name, GENERIC_READ|GENERIC_WRITE, 0,
1717 NULL, OPEN_EXISTING, 0, 0, TRUE,
1718 GetDriveTypeW( full_name2.short_name ) );
1719 if(!hFile && GetLastError() != ERROR_FILE_NOT_FOUND) return FALSE;
1720 CloseHandle(hFile);
1722 if (full_name1.drive != full_name2.drive)
1724 if (!(flag & MOVEFILE_COPY_ALLOWED))
1726 SetLastError( ERROR_NOT_SAME_DEVICE );
1727 return FALSE;
1729 else if ( attr & FILE_ATTRIBUTE_DIRECTORY )
1731 /* Strange, but that's what Windows returns */
1732 SetLastError ( ERROR_ACCESS_DENIED );
1733 return FALSE;
1736 if (rename( full_name1.long_name, full_name2.long_name ) == -1)
1737 /* Try copy/delete unless it's a directory. */
1738 /* FIXME: This does not handle the (unlikely) case that the two locations
1739 are on the same Wine drive, but on different Unix file systems. */
1741 if ( attr & FILE_ATTRIBUTE_DIRECTORY )
1743 FILE_SetDosError();
1744 return FALSE;
1746 else
1748 if ( ! CopyFileW( fn1, fn2, !(flag & MOVEFILE_REPLACE_EXISTING) ))
1749 return FALSE;
1750 if ( ! DeleteFileW ( fn1 ) )
1751 return FALSE;
1754 if (is_executable( full_name1.long_name ) != is_executable( full_name2.long_name ))
1756 struct stat fstat;
1757 if (stat( full_name2.long_name, &fstat ) != -1)
1759 if (is_executable( full_name2.long_name ))
1760 /* set executable bit where read bit is set */
1761 fstat.st_mode |= (fstat.st_mode & 0444) >> 2;
1762 else
1763 fstat.st_mode &= ~0111;
1764 chmod( full_name2.long_name, fstat.st_mode );
1767 return TRUE;
1769 else /* fn2 == NULL means delete source */
1771 if (flag & MOVEFILE_DELAY_UNTIL_REBOOT)
1773 if (flag & MOVEFILE_COPY_ALLOWED) {
1774 WARN("Illegal flag\n");
1775 SetLastError( ERROR_GEN_FAILURE );
1776 return FALSE;
1779 return FILE_AddBootRenameEntry( fn1, NULL, flag );
1782 if (unlink( full_name1.long_name ) == -1)
1784 FILE_SetDosError();
1785 return FALSE;
1787 return TRUE; /* successfully deleted */
1791 /**************************************************************************
1792 * MoveFileExA (KERNEL32.@)
1794 BOOL WINAPI MoveFileExA( LPCSTR fn1, LPCSTR fn2, DWORD flag )
1796 UNICODE_STRING fn1W, fn2W;
1797 BOOL ret;
1799 if (!fn1)
1801 SetLastError(ERROR_INVALID_PARAMETER);
1802 return FALSE;
1805 RtlCreateUnicodeStringFromAsciiz(&fn1W, fn1);
1806 if (fn2) RtlCreateUnicodeStringFromAsciiz(&fn2W, fn2);
1807 else fn2W.Buffer = NULL;
1809 ret = MoveFileExW( fn1W.Buffer, fn2W.Buffer, flag );
1811 RtlFreeUnicodeString(&fn1W);
1812 RtlFreeUnicodeString(&fn2W);
1813 return ret;
1817 /**************************************************************************
1818 * MoveFileW (KERNEL32.@)
1820 * Move file or directory
1822 BOOL WINAPI MoveFileW( LPCWSTR fn1, LPCWSTR fn2 )
1824 return MoveFileExW( fn1, fn2, MOVEFILE_COPY_ALLOWED );
1828 /**************************************************************************
1829 * MoveFileA (KERNEL32.@)
1831 BOOL WINAPI MoveFileA( LPCSTR fn1, LPCSTR fn2 )
1833 return MoveFileExA( fn1, fn2, MOVEFILE_COPY_ALLOWED );
1837 /**************************************************************************
1838 * CopyFileW (KERNEL32.@)
1840 BOOL WINAPI CopyFileW( LPCWSTR source, LPCWSTR dest, BOOL fail_if_exists )
1842 HANDLE h1, h2;
1843 BY_HANDLE_FILE_INFORMATION info;
1844 DWORD count;
1845 BOOL ret = FALSE;
1846 char buffer[2048];
1848 if (!source || !dest)
1850 SetLastError(ERROR_INVALID_PARAMETER);
1851 return FALSE;
1854 TRACE("%s -> %s\n", debugstr_w(source), debugstr_w(dest));
1856 if ((h1 = CreateFileW(source, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE,
1857 NULL, OPEN_EXISTING, 0, 0)) == INVALID_HANDLE_VALUE)
1859 WARN("Unable to open source %s\n", debugstr_w(source));
1860 return FALSE;
1863 if (!GetFileInformationByHandle( h1, &info ))
1865 WARN("GetFileInformationByHandle returned error for %s\n", debugstr_w(source));
1866 CloseHandle( h1 );
1867 return FALSE;
1870 if ((h2 = CreateFileW( dest, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
1871 fail_if_exists ? CREATE_NEW : CREATE_ALWAYS,
1872 info.dwFileAttributes, h1 )) == INVALID_HANDLE_VALUE)
1874 WARN("Unable to open dest %s\n", debugstr_w(dest));
1875 CloseHandle( h1 );
1876 return FALSE;
1879 while (ReadFile( h1, buffer, sizeof(buffer), &count, NULL ) && count)
1881 char *p = buffer;
1882 while (count != 0)
1884 DWORD res;
1885 if (!WriteFile( h2, p, count, &res, NULL ) || !res) goto done;
1886 p += res;
1887 count -= res;
1890 ret = TRUE;
1891 done:
1892 CloseHandle( h1 );
1893 CloseHandle( h2 );
1894 return ret;
1898 /**************************************************************************
1899 * CopyFileA (KERNEL32.@)
1901 BOOL WINAPI CopyFileA( LPCSTR source, LPCSTR dest, BOOL fail_if_exists)
1903 UNICODE_STRING sourceW, destW;
1904 BOOL ret;
1906 if (!source || !dest)
1908 SetLastError(ERROR_INVALID_PARAMETER);
1909 return FALSE;
1912 RtlCreateUnicodeStringFromAsciiz(&sourceW, source);
1913 RtlCreateUnicodeStringFromAsciiz(&destW, dest);
1915 ret = CopyFileW(sourceW.Buffer, destW.Buffer, fail_if_exists);
1917 RtlFreeUnicodeString(&sourceW);
1918 RtlFreeUnicodeString(&destW);
1919 return ret;
1923 /**************************************************************************
1924 * CopyFileExW (KERNEL32.@)
1926 * This implementation ignores most of the extra parameters passed-in into
1927 * the "ex" version of the method and calls the CopyFile method.
1928 * It will have to be fixed eventually.
1930 BOOL WINAPI CopyFileExW(LPCWSTR sourceFilename, LPCWSTR destFilename,
1931 LPPROGRESS_ROUTINE progressRoutine, LPVOID appData,
1932 LPBOOL cancelFlagPointer, DWORD copyFlags)
1935 * Interpret the only flag that CopyFile can interpret.
1937 return CopyFileW(sourceFilename, destFilename, (copyFlags & COPY_FILE_FAIL_IF_EXISTS) != 0);
1941 /**************************************************************************
1942 * CopyFileExA (KERNEL32.@)
1944 BOOL WINAPI CopyFileExA(LPCSTR sourceFilename, LPCSTR destFilename,
1945 LPPROGRESS_ROUTINE progressRoutine, LPVOID appData,
1946 LPBOOL cancelFlagPointer, DWORD copyFlags)
1948 UNICODE_STRING sourceW, destW;
1949 BOOL ret;
1951 if (!sourceFilename || !destFilename)
1953 SetLastError(ERROR_INVALID_PARAMETER);
1954 return FALSE;
1957 RtlCreateUnicodeStringFromAsciiz(&sourceW, sourceFilename);
1958 RtlCreateUnicodeStringFromAsciiz(&destW, destFilename);
1960 ret = CopyFileExW(sourceW.Buffer, destW.Buffer, progressRoutine, appData,
1961 cancelFlagPointer, copyFlags);
1963 RtlFreeUnicodeString(&sourceW);
1964 RtlFreeUnicodeString(&destW);
1965 return ret;
1969 /***********************************************************************
1970 * SetFileTime (KERNEL32.@)
1972 BOOL WINAPI SetFileTime( HANDLE hFile,
1973 const FILETIME *lpCreationTime,
1974 const FILETIME *lpLastAccessTime,
1975 const FILETIME *lpLastWriteTime )
1977 BOOL ret;
1978 SERVER_START_REQ( set_file_time )
1980 req->handle = hFile;
1981 if (lpLastAccessTime)
1982 RtlTimeToSecondsSince1970( (PLARGE_INTEGER) lpLastAccessTime, (DWORD *)&req->access_time );
1983 else
1984 req->access_time = 0; /* FIXME */
1985 if (lpLastWriteTime)
1986 RtlTimeToSecondsSince1970( (PLARGE_INTEGER) lpLastWriteTime, (DWORD *)&req->write_time );
1987 else
1988 req->write_time = 0; /* FIXME */
1989 ret = !wine_server_call_err( req );
1991 SERVER_END_REQ;
1992 return ret;
1996 /**************************************************************************
1997 * GetFileAttributesExW (KERNEL32.@)
1999 BOOL WINAPI GetFileAttributesExW(
2000 LPCWSTR lpFileName, GET_FILEEX_INFO_LEVELS fInfoLevelId,
2001 LPVOID lpFileInformation)
2003 DOS_FULL_NAME full_name;
2004 BY_HANDLE_FILE_INFORMATION info;
2006 if (!lpFileName || !lpFileInformation)
2008 SetLastError(ERROR_INVALID_PARAMETER);
2009 return FALSE;
2012 if (fInfoLevelId == GetFileExInfoStandard) {
2013 LPWIN32_FILE_ATTRIBUTE_DATA lpFad =
2014 (LPWIN32_FILE_ATTRIBUTE_DATA) lpFileInformation;
2015 if (!DOSFS_GetFullName( lpFileName, TRUE, &full_name )) return FALSE;
2016 if (!FILE_Stat( full_name.long_name, &info, NULL )) return FALSE;
2018 lpFad->dwFileAttributes = info.dwFileAttributes;
2019 lpFad->ftCreationTime = info.ftCreationTime;
2020 lpFad->ftLastAccessTime = info.ftLastAccessTime;
2021 lpFad->ftLastWriteTime = info.ftLastWriteTime;
2022 lpFad->nFileSizeHigh = info.nFileSizeHigh;
2023 lpFad->nFileSizeLow = info.nFileSizeLow;
2025 else {
2026 FIXME("invalid info level %d!\n", fInfoLevelId);
2027 return FALSE;
2030 return TRUE;
2034 /**************************************************************************
2035 * GetFileAttributesExA (KERNEL32.@)
2037 BOOL WINAPI GetFileAttributesExA(
2038 LPCSTR filename, GET_FILEEX_INFO_LEVELS fInfoLevelId,
2039 LPVOID lpFileInformation)
2041 UNICODE_STRING filenameW;
2042 BOOL ret = FALSE;
2044 if (!filename || !lpFileInformation)
2046 SetLastError(ERROR_INVALID_PARAMETER);
2047 return FALSE;
2050 if (RtlCreateUnicodeStringFromAsciiz(&filenameW, filename))
2052 ret = GetFileAttributesExW(filenameW.Buffer, fInfoLevelId, lpFileInformation);
2053 RtlFreeUnicodeString(&filenameW);
2055 else
2056 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
2057 return ret;