HTTP_DealWithProxy: Only add http:// to proxy string when needed.
[wine/multimedia.git] / files / file.c
blob94924f076ee8dca3f42b97957c0b7f5dc232f425
1 /*
2 * File handling functions
4 * Copyright 1993 John Burton
5 * Copyright 1996 Alexandre Julliard
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 * TODO:
22 * Fix the CopyFileEx methods to implement the "extended" functionality.
23 * Right now, they simply call the CopyFile method.
26 #include "config.h"
27 #include "wine/port.h"
29 #include <assert.h>
30 #include <ctype.h>
31 #include <errno.h>
32 #include <fcntl.h>
33 #include <stdlib.h>
34 #include <stdarg.h>
35 #include <stdio.h>
36 #include <string.h>
37 #ifdef HAVE_SYS_ERRNO_H
38 #include <sys/errno.h>
39 #endif
40 #include <sys/types.h>
41 #include <sys/stat.h>
42 #ifdef HAVE_SYS_MMAN_H
43 #include <sys/mman.h>
44 #endif
45 #ifdef HAVE_SYS_TIME_H
46 # include <sys/time.h>
47 #endif
48 #ifdef HAVE_SYS_POLL_H
49 # include <sys/poll.h>
50 #endif
51 #include <time.h>
52 #ifdef HAVE_UNISTD_H
53 # include <unistd.h>
54 #endif
55 #ifdef HAVE_UTIME_H
56 # include <utime.h>
57 #endif
59 #define NONAMELESSUNION
60 #define NONAMELESSSTRUCT
61 #include "winerror.h"
62 #include "ntstatus.h"
63 #include "windef.h"
64 #include "winbase.h"
65 #include "winreg.h"
66 #include "winternl.h"
67 #include "wine/winbase16.h"
68 #include "wine/server.h"
70 #include "drive.h"
71 #include "file.h"
72 #include "wincon.h"
73 #include "kernel_private.h"
75 #include "smb.h"
76 #include "wine/unicode.h"
77 #include "wine/debug.h"
79 WINE_DEFAULT_DEBUG_CHANNEL(file);
81 #if defined(MAP_ANONYMOUS) && !defined(MAP_ANON)
82 #define MAP_ANON MAP_ANONYMOUS
83 #endif
85 #define IS_OPTION_TRUE(ch) ((ch) == 'y' || (ch) == 'Y' || (ch) == 't' || (ch) == 'T' || (ch) == '1')
87 HANDLE dos_handles[DOS_TABLE_SIZE];
88 mode_t FILE_umask;
90 /***********************************************************************
91 * FILE_ConvertOFMode
93 * Convert OF_* mode into flags for CreateFile.
95 void FILE_ConvertOFMode( INT mode, DWORD *access, DWORD *sharing )
97 switch(mode & 0x03)
99 case OF_READ: *access = GENERIC_READ; break;
100 case OF_WRITE: *access = GENERIC_WRITE; break;
101 case OF_READWRITE: *access = GENERIC_READ | GENERIC_WRITE; break;
102 default: *access = 0; break;
104 switch(mode & 0x70)
106 case OF_SHARE_EXCLUSIVE: *sharing = 0; break;
107 case OF_SHARE_DENY_WRITE: *sharing = FILE_SHARE_READ; break;
108 case OF_SHARE_DENY_READ: *sharing = FILE_SHARE_WRITE; break;
109 case OF_SHARE_DENY_NONE:
110 case OF_SHARE_COMPAT:
111 default: *sharing = FILE_SHARE_READ | FILE_SHARE_WRITE; break;
116 /***********************************************************************
117 * FILE_strcasecmp
119 * locale-independent case conversion for file I/O
121 int FILE_strcasecmp( const char *str1, const char *str2 )
123 int ret = 0;
124 for ( ; ; str1++, str2++)
125 if ((ret = FILE_toupper(*str1) - FILE_toupper(*str2)) || !*str1) break;
126 return ret;
130 /***********************************************************************
131 * FILE_strncasecmp
133 * locale-independent case conversion for file I/O
135 int FILE_strncasecmp( const char *str1, const char *str2, int len )
137 int ret = 0;
138 for ( ; len > 0; len--, str1++, str2++)
139 if ((ret = FILE_toupper(*str1) - FILE_toupper(*str2)) || !*str1) break;
140 return ret;
144 /***********************************************************************
145 * FILE_SetDosError
147 * Set the DOS error code from errno.
149 void FILE_SetDosError(void)
151 int save_errno = errno; /* errno gets overwritten by printf */
153 TRACE("errno = %d %s\n", errno, strerror(errno));
154 switch (save_errno)
156 case EAGAIN:
157 SetLastError( ERROR_SHARING_VIOLATION );
158 break;
159 case EBADF:
160 SetLastError( ERROR_INVALID_HANDLE );
161 break;
162 case ENOSPC:
163 SetLastError( ERROR_HANDLE_DISK_FULL );
164 break;
165 case EACCES:
166 case EPERM:
167 case EROFS:
168 SetLastError( ERROR_ACCESS_DENIED );
169 break;
170 case EBUSY:
171 SetLastError( ERROR_LOCK_VIOLATION );
172 break;
173 case ENOENT:
174 SetLastError( ERROR_FILE_NOT_FOUND );
175 break;
176 case EISDIR:
177 SetLastError( ERROR_CANNOT_MAKE );
178 break;
179 case ENFILE:
180 case EMFILE:
181 SetLastError( ERROR_NO_MORE_FILES );
182 break;
183 case EEXIST:
184 SetLastError( ERROR_FILE_EXISTS );
185 break;
186 case EINVAL:
187 case ESPIPE:
188 SetLastError( ERROR_SEEK );
189 break;
190 case ENOTEMPTY:
191 SetLastError( ERROR_DIR_NOT_EMPTY );
192 break;
193 case ENOEXEC:
194 SetLastError( ERROR_BAD_FORMAT );
195 break;
196 default:
197 WARN("unknown file error: %s\n", strerror(save_errno) );
198 SetLastError( ERROR_GEN_FAILURE );
199 break;
201 errno = save_errno;
205 /***********************************************************************
206 * FILE_CreateFile
208 * Implementation of CreateFile. Takes a Unix path name.
209 * Returns 0 on failure.
211 HANDLE FILE_CreateFile( LPCSTR filename, DWORD access, DWORD sharing,
212 LPSECURITY_ATTRIBUTES sa, DWORD creation,
213 DWORD attributes, HANDLE template, BOOL fail_read_only,
214 UINT drive_type )
216 unsigned int err;
217 HANDLE ret;
219 for (;;)
221 SERVER_START_REQ( create_file )
223 req->access = access;
224 req->inherit = (sa && (sa->nLength>=sizeof(*sa)) && sa->bInheritHandle);
225 req->sharing = sharing;
226 req->create = creation;
227 req->attrs = attributes;
228 req->removable = (drive_type == DRIVE_REMOVABLE || drive_type == DRIVE_CDROM);
229 wine_server_add_data( req, filename, strlen(filename) );
230 SetLastError(0);
231 err = wine_server_call( req );
232 ret = reply->handle;
234 SERVER_END_REQ;
236 /* If write access failed, retry without GENERIC_WRITE */
238 if (!ret && !fail_read_only && (access & GENERIC_WRITE))
240 if ((err == STATUS_MEDIA_WRITE_PROTECTED) || (err == STATUS_ACCESS_DENIED))
242 TRACE("Write access failed for file '%s', trying without "
243 "write access\n", filename);
244 access &= ~GENERIC_WRITE;
245 continue;
249 if (err)
251 /* In the case file creation was rejected due to CREATE_NEW flag
252 * was specified and file with that name already exists, correct
253 * last error is ERROR_FILE_EXISTS and not ERROR_ALREADY_EXISTS.
254 * Note: RtlNtStatusToDosError is not the subject to blame here.
256 if (err == STATUS_OBJECT_NAME_COLLISION)
257 SetLastError( ERROR_FILE_EXISTS );
258 else
259 SetLastError( RtlNtStatusToDosError(err) );
262 if (!ret) WARN("Unable to create file '%s' (GLE %ld)\n", filename, GetLastError());
263 return ret;
268 /***********************************************************************
269 * FILE_CreateDevice
271 * Same as FILE_CreateFile but for a device
272 * Returns 0 on failure.
274 HANDLE FILE_CreateDevice( int client_id, DWORD access, LPSECURITY_ATTRIBUTES sa )
276 HANDLE ret;
277 SERVER_START_REQ( create_device )
279 req->access = access;
280 req->inherit = (sa && (sa->nLength>=sizeof(*sa)) && sa->bInheritHandle);
281 req->id = client_id;
282 SetLastError(0);
283 wine_server_call_err( req );
284 ret = reply->handle;
286 SERVER_END_REQ;
287 return ret;
290 static HANDLE FILE_OpenPipe(LPCWSTR name, DWORD access, LPSECURITY_ATTRIBUTES sa )
292 HANDLE ret;
293 DWORD len = 0;
295 if (name && (len = strlenW(name)) > MAX_PATH)
297 SetLastError( ERROR_FILENAME_EXCED_RANGE );
298 return 0;
300 SERVER_START_REQ( open_named_pipe )
302 req->access = access;
303 req->inherit = (sa && (sa->nLength>=sizeof(*sa)) && sa->bInheritHandle);
304 SetLastError(0);
305 wine_server_add_data( req, name, len * sizeof(WCHAR) );
306 wine_server_call_err( req );
307 ret = reply->handle;
309 SERVER_END_REQ;
310 TRACE("Returned %p\n",ret);
311 return ret;
314 /*************************************************************************
315 * CreateFileW [KERNEL32.@] Creates or opens a file or other object
317 * Creates or opens an object, and returns a handle that can be used to
318 * access that object.
320 * PARAMS
322 * filename [in] pointer to filename to be accessed
323 * access [in] access mode requested
324 * sharing [in] share mode
325 * sa [in] pointer to security attributes
326 * creation [in] how to create the file
327 * attributes [in] attributes for newly created file
328 * template [in] handle to file with extended attributes to copy
330 * RETURNS
331 * Success: Open handle to specified file
332 * Failure: INVALID_HANDLE_VALUE
334 * NOTES
335 * Should call SetLastError() on failure.
337 * BUGS
339 * Doesn't support character devices, template files, or a
340 * lot of the 'attributes' flags yet.
342 HANDLE WINAPI CreateFileW( LPCWSTR filename, DWORD access, DWORD sharing,
343 LPSECURITY_ATTRIBUTES sa, DWORD creation,
344 DWORD attributes, HANDLE template )
346 DOS_FULL_NAME full_name;
347 HANDLE ret;
348 static const WCHAR bkslashes_with_question_markW[] = {'\\','\\','?','\\',0};
349 static const WCHAR bkslashes_with_dotW[] = {'\\','\\','.','\\',0};
350 static const WCHAR bkslashesW[] = {'\\','\\',0};
351 static const WCHAR coninW[] = {'C','O','N','I','N','$',0};
352 static const WCHAR conoutW[] = {'C','O','N','O','U','T','$',0};
354 if (!filename)
356 SetLastError( ERROR_INVALID_PARAMETER );
357 return INVALID_HANDLE_VALUE;
359 TRACE("%s %s%s%s%s%s%s%s attributes 0x%lx\n", debugstr_w(filename),
360 ((access & GENERIC_READ)==GENERIC_READ)?"GENERIC_READ ":"",
361 ((access & GENERIC_WRITE)==GENERIC_WRITE)?"GENERIC_WRITE ":"",
362 (!access)?"QUERY_ACCESS ":"",
363 ((sharing & FILE_SHARE_READ)==FILE_SHARE_READ)?"FILE_SHARE_READ ":"",
364 ((sharing & FILE_SHARE_WRITE)==FILE_SHARE_WRITE)?"FILE_SHARE_WRITE ":"",
365 ((sharing & FILE_SHARE_DELETE)==FILE_SHARE_DELETE)?"FILE_SHARE_DELETE ":"",
366 (creation ==CREATE_NEW)?"CREATE_NEW":
367 (creation ==CREATE_ALWAYS)?"CREATE_ALWAYS ":
368 (creation ==OPEN_EXISTING)?"OPEN_EXISTING ":
369 (creation ==OPEN_ALWAYS)?"OPEN_ALWAYS ":
370 (creation ==TRUNCATE_EXISTING)?"TRUNCATE_EXISTING ":"", attributes);
372 /* If the name starts with '\\?\', ignore the first 4 chars. */
373 if (!strncmpW(filename, bkslashes_with_question_markW, 4))
375 static const WCHAR uncW[] = {'U','N','C','\\',0};
376 filename += 4;
377 if (!strncmpiW(filename, uncW, 4))
379 FIXME("UNC name (%s) not supported.\n", debugstr_w(filename) );
380 SetLastError( ERROR_PATH_NOT_FOUND );
381 return INVALID_HANDLE_VALUE;
385 if (!strncmpW(filename, bkslashes_with_dotW, 4))
387 static const WCHAR pipeW[] = {'P','I','P','E','\\',0};
388 if(!strncmpiW(filename + 4, pipeW, 5))
390 TRACE("Opening a pipe: %s\n", debugstr_w(filename));
391 ret = FILE_OpenPipe( filename, access, sa );
392 goto done;
394 else if (isalphaW(filename[4]) && filename[5] == ':' && filename[6] == '\0')
396 ret = FILE_CreateDevice( (toupperW(filename[4]) - 'A') | 0x20000, access, sa );
397 goto done;
399 else if (!DOSFS_GetDevice( filename ))
401 ret = DEVICE_Open( filename+4, access, sa );
402 goto done;
404 else
405 filename+=4; /* fall into DOSFS_Device case below */
408 /* If the name still starts with '\\', it's a UNC name. */
409 if (!strncmpW(filename, bkslashesW, 2))
411 ret = SMB_CreateFileW(filename, access, sharing, sa, creation, attributes, template );
412 goto done;
415 /* If the name contains a DOS wild card (* or ?), do no create a file */
416 if(strchrW(filename, '*') || strchrW(filename, '?'))
418 SetLastError(ERROR_BAD_PATHNAME);
419 return INVALID_HANDLE_VALUE;
422 /* Open a console for CONIN$ or CONOUT$ */
423 if (!strcmpiW(filename, coninW) || !strcmpiW(filename, conoutW))
425 ret = OpenConsoleW(filename, access, sa, creation);
426 goto done;
429 if (DOSFS_GetDevice( filename ))
431 TRACE("opening device %s\n", debugstr_w(filename) );
433 if (!(ret = DOSFS_OpenDevice( filename, access, attributes, sa )))
435 /* Do not silence this please. It is a critical error. -MM */
436 ERR("Couldn't open device %s!\n", debugstr_w(filename));
437 SetLastError( ERROR_FILE_NOT_FOUND );
439 goto done;
442 /* check for filename, don't check for last entry if creating */
443 if (!DOSFS_GetFullName( filename,
444 (creation == OPEN_EXISTING) ||
445 (creation == TRUNCATE_EXISTING),
446 &full_name )) {
447 WARN("Unable to get full filename from %s (GLE %ld)\n",
448 debugstr_w(filename), GetLastError());
449 return INVALID_HANDLE_VALUE;
452 ret = FILE_CreateFile( full_name.long_name, access, sharing,
453 sa, creation, attributes, template,
454 DRIVE_GetFlags(full_name.drive) & DRIVE_FAIL_READ_ONLY,
455 GetDriveTypeW( full_name.short_name ) );
456 done:
457 if (!ret) ret = INVALID_HANDLE_VALUE;
458 TRACE("returning %p\n", ret);
459 return ret;
464 /*************************************************************************
465 * CreateFileA (KERNEL32.@)
467 HANDLE WINAPI CreateFileA( LPCSTR filename, DWORD access, DWORD sharing,
468 LPSECURITY_ATTRIBUTES sa, DWORD creation,
469 DWORD attributes, HANDLE template)
471 UNICODE_STRING filenameW;
472 HANDLE ret = INVALID_HANDLE_VALUE;
474 if (!filename)
476 SetLastError( ERROR_INVALID_PARAMETER );
477 return INVALID_HANDLE_VALUE;
480 if (RtlCreateUnicodeStringFromAsciiz(&filenameW, filename))
482 ret = CreateFileW(filenameW.Buffer, access, sharing, sa, creation,
483 attributes, template);
484 RtlFreeUnicodeString(&filenameW);
486 else
487 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
488 return ret;
492 /***********************************************************************
493 * FILE_FillInfo
495 * Fill a file information from a struct stat.
497 static void FILE_FillInfo( struct stat *st, BY_HANDLE_FILE_INFORMATION *info )
499 if (S_ISDIR(st->st_mode))
500 info->dwFileAttributes = FILE_ATTRIBUTE_DIRECTORY;
501 else
502 info->dwFileAttributes = FILE_ATTRIBUTE_ARCHIVE;
503 if (!(st->st_mode & S_IWUSR))
504 info->dwFileAttributes |= FILE_ATTRIBUTE_READONLY;
506 RtlSecondsSince1970ToTime( st->st_mtime, (LARGE_INTEGER *)&info->ftCreationTime );
507 RtlSecondsSince1970ToTime( st->st_mtime, (LARGE_INTEGER *)&info->ftLastWriteTime );
508 RtlSecondsSince1970ToTime( st->st_atime, (LARGE_INTEGER *)&info->ftLastAccessTime );
510 info->dwVolumeSerialNumber = 0; /* FIXME */
511 info->nFileSizeHigh = 0;
512 info->nFileSizeLow = 0;
513 if (!S_ISDIR(st->st_mode)) {
514 info->nFileSizeHigh = st->st_size >> 32;
515 info->nFileSizeLow = st->st_size & 0xffffffff;
517 info->nNumberOfLinks = st->st_nlink;
518 info->nFileIndexHigh = 0;
519 info->nFileIndexLow = st->st_ino;
523 /***********************************************************************
524 * get_show_dot_files_option
526 static BOOL get_show_dot_files_option(void)
528 static const WCHAR WineW[] = {'M','a','c','h','i','n','e','\\',
529 'S','o','f','t','w','a','r','e','\\',
530 'W','i','n','e','\\','W','i','n','e','\\',
531 'C','o','n','f','i','g','\\','W','i','n','e',0};
532 static const WCHAR ShowDotFilesW[] = {'S','h','o','w','D','o','t','F','i','l','e','s',0};
534 char tmp[80];
535 HKEY hkey;
536 DWORD dummy;
537 OBJECT_ATTRIBUTES attr;
538 UNICODE_STRING nameW;
539 BOOL ret = FALSE;
541 attr.Length = sizeof(attr);
542 attr.RootDirectory = 0;
543 attr.ObjectName = &nameW;
544 attr.Attributes = 0;
545 attr.SecurityDescriptor = NULL;
546 attr.SecurityQualityOfService = NULL;
547 RtlInitUnicodeString( &nameW, WineW );
549 if (!NtOpenKey( &hkey, KEY_ALL_ACCESS, &attr ))
551 RtlInitUnicodeString( &nameW, ShowDotFilesW );
552 if (!NtQueryValueKey( hkey, &nameW, KeyValuePartialInformation, tmp, sizeof(tmp), &dummy ))
554 WCHAR *str = (WCHAR *)((KEY_VALUE_PARTIAL_INFORMATION *)tmp)->Data;
555 ret = IS_OPTION_TRUE( str[0] );
557 NtClose( hkey );
559 return ret;
563 /***********************************************************************
564 * FILE_Stat
566 * Stat a Unix path name. Return TRUE if OK.
568 BOOL FILE_Stat( LPCSTR unixName, BY_HANDLE_FILE_INFORMATION *info, BOOL *is_symlink_ptr )
570 struct stat st;
571 int is_symlink;
572 LPCSTR p;
574 if (lstat( unixName, &st ) == -1)
576 FILE_SetDosError();
577 return FALSE;
579 is_symlink = S_ISLNK(st.st_mode);
580 if (is_symlink)
582 /* do a "real" stat to find out
583 about the type of the symlink destination */
584 if (stat( unixName, &st ) == -1)
586 FILE_SetDosError();
587 return FALSE;
591 /* fill in the information we gathered so far */
592 FILE_FillInfo( &st, info );
594 /* and now see if this is a hidden file, based on the name */
595 p = strrchr( unixName, '/');
596 p = p ? p + 1 : unixName;
597 if (*p == '.' && *(p+1) && (*(p+1) != '.' || *(p+2)))
599 static int show_dot_files = -1;
600 if (show_dot_files == -1)
601 show_dot_files = get_show_dot_files_option();
602 if (!show_dot_files)
603 info->dwFileAttributes |= FILE_ATTRIBUTE_HIDDEN;
605 if (is_symlink_ptr) *is_symlink_ptr = is_symlink;
606 return TRUE;
610 /***********************************************************************
611 * GetFileInformationByHandle (KERNEL32.@)
613 DWORD WINAPI GetFileInformationByHandle( HANDLE hFile,
614 BY_HANDLE_FILE_INFORMATION *info )
616 DWORD ret;
617 if (!info) return 0;
619 TRACE("%p\n", hFile);
621 SERVER_START_REQ( get_file_info )
623 req->handle = hFile;
624 if ((ret = !wine_server_call_err( req )))
626 /* FIXME: which file types are supported ?
627 * Serial ports (FILE_TYPE_CHAR) are not,
628 * and MSDN also says that pipes are not supported.
629 * FILE_TYPE_REMOTE seems to be supported according to
630 * MSDN q234741.txt */
631 if ((reply->type == FILE_TYPE_DISK) || (reply->type == FILE_TYPE_REMOTE))
633 RtlSecondsSince1970ToTime( reply->write_time, (LARGE_INTEGER *)&info->ftCreationTime );
634 RtlSecondsSince1970ToTime( reply->write_time, (LARGE_INTEGER *)&info->ftLastWriteTime );
635 RtlSecondsSince1970ToTime( reply->access_time, (LARGE_INTEGER *)&info->ftLastAccessTime );
636 info->dwFileAttributes = reply->attr;
637 info->dwVolumeSerialNumber = reply->serial;
638 info->nFileSizeHigh = reply->size_high;
639 info->nFileSizeLow = reply->size_low;
640 info->nNumberOfLinks = reply->links;
641 info->nFileIndexHigh = reply->index_high;
642 info->nFileIndexLow = reply->index_low;
644 else
646 SetLastError(ERROR_NOT_SUPPORTED);
647 ret = 0;
651 SERVER_END_REQ;
652 return ret;
656 /**************************************************************************
657 * GetFileAttributesW (KERNEL32.@)
659 DWORD WINAPI GetFileAttributesW( LPCWSTR name )
661 DOS_FULL_NAME full_name;
662 BY_HANDLE_FILE_INFORMATION info;
664 if (name == NULL)
666 SetLastError( ERROR_INVALID_PARAMETER );
667 return INVALID_FILE_ATTRIBUTES;
669 if (!DOSFS_GetFullName( name, TRUE, &full_name) )
670 return INVALID_FILE_ATTRIBUTES;
671 if (!FILE_Stat( full_name.long_name, &info, NULL ))
672 return INVALID_FILE_ATTRIBUTES;
673 return info.dwFileAttributes;
677 /**************************************************************************
678 * GetFileAttributesA (KERNEL32.@)
680 DWORD WINAPI GetFileAttributesA( LPCSTR name )
682 UNICODE_STRING nameW;
683 DWORD ret = INVALID_FILE_ATTRIBUTES;
685 if (!name)
687 SetLastError( ERROR_INVALID_PARAMETER );
688 return INVALID_FILE_ATTRIBUTES;
691 if (RtlCreateUnicodeStringFromAsciiz(&nameW, name))
693 ret = GetFileAttributesW(nameW.Buffer);
694 RtlFreeUnicodeString(&nameW);
696 else
697 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
698 return ret;
702 /**************************************************************************
703 * SetFileAttributesW (KERNEL32.@)
705 BOOL WINAPI SetFileAttributesW(LPCWSTR lpFileName, DWORD attributes)
707 struct stat buf;
708 DOS_FULL_NAME full_name;
710 if (!lpFileName)
712 SetLastError( ERROR_INVALID_PARAMETER );
713 return FALSE;
716 TRACE("(%s,%lx)\n", debugstr_w(lpFileName), attributes);
718 if (!DOSFS_GetFullName( lpFileName, TRUE, &full_name ))
719 return FALSE;
721 if(stat(full_name.long_name,&buf)==-1)
723 FILE_SetDosError();
724 return FALSE;
726 if (attributes & FILE_ATTRIBUTE_READONLY)
728 if(S_ISDIR(buf.st_mode))
729 /* FIXME */
730 WARN("FILE_ATTRIBUTE_READONLY ignored for directory.\n");
731 else
732 buf.st_mode &= ~0222; /* octal!, clear write permission bits */
733 attributes &= ~FILE_ATTRIBUTE_READONLY;
735 else
737 /* add write permission */
738 buf.st_mode |= (0600 | ((buf.st_mode & 044) >> 1)) & (~FILE_umask);
740 if (attributes & FILE_ATTRIBUTE_DIRECTORY)
742 if (!S_ISDIR(buf.st_mode))
743 FIXME("SetFileAttributes expected the file %s to be a directory\n",
744 debugstr_w(lpFileName));
745 attributes &= ~FILE_ATTRIBUTE_DIRECTORY;
747 attributes &= ~(FILE_ATTRIBUTE_NORMAL|FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_HIDDEN|FILE_ATTRIBUTE_SYSTEM);
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[] = {'%','0','4','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 and path is more than just the drive letter ... */
925 if ( !((strlenW(buffer) == 2) && (buffer[1] == ':'))
926 && ((p == buffer) || (p[-1] != '\\'))) *p++ = '\\';
928 for (i = 3; (i > 0) && (*prefix); i--) *p++ = *prefix++;
930 unique &= 0xffff;
932 if (unique) sprintfW( p, formatW, unique );
933 else
935 /* get a "random" unique number and try to create the file */
936 HANDLE handle;
937 UINT num = GetTickCount() & 0xffff;
939 if (!num) num = 1;
940 unique = num;
943 sprintfW( p, formatW, unique );
944 handle = CreateFileW( buffer, GENERIC_WRITE, 0, NULL,
945 CREATE_NEW, FILE_ATTRIBUTE_NORMAL, 0 );
946 if (handle != INVALID_HANDLE_VALUE)
947 { /* We created it */
948 TRACE("created %s\n", debugstr_w(buffer) );
949 CloseHandle( handle );
950 break;
952 if (GetLastError() != ERROR_FILE_EXISTS &&
953 GetLastError() != ERROR_SHARING_VIOLATION)
954 break; /* No need to go on */
955 if (!(++unique & 0xffff)) unique = 1;
956 } while (unique != num);
959 /* Get the full path name */
961 if (DOSFS_GetFullName( buffer, FALSE, &full_name ))
963 char *slash;
964 /* Check if we have write access in the directory */
965 if ((slash = strrchr( full_name.long_name, '/' ))) *slash = '\0';
966 if (access( full_name.long_name, W_OK ) == -1)
967 WARN("returns %s, which doesn't seem to be writeable.\n",
968 debugstr_w(buffer) );
970 TRACE("returning %s\n", debugstr_w(buffer) );
971 return unique;
975 /***********************************************************************
976 * FILE_DoOpenFile
978 * Implementation of OpenFile16() and OpenFile32().
980 static HFILE FILE_DoOpenFile( LPCSTR name, OFSTRUCT *ofs, UINT mode, BOOL win32 )
982 HFILE hFileRet;
983 HANDLE handle;
984 FILETIME filetime;
985 WORD filedatetime[2];
986 DOS_FULL_NAME full_name;
987 DWORD access, sharing;
988 WCHAR *p;
989 WCHAR buffer[MAX_PATH];
990 LPWSTR nameW;
992 if (!ofs) return HFILE_ERROR;
994 TRACE("%s %s %s %s%s%s%s%s%s%s%s%s\n",name,
995 ((mode & 0x3 )==OF_READ)?"OF_READ":
996 ((mode & 0x3 )==OF_WRITE)?"OF_WRITE":
997 ((mode & 0x3 )==OF_READWRITE)?"OF_READWRITE":"unknown",
998 ((mode & 0x70 )==OF_SHARE_COMPAT)?"OF_SHARE_COMPAT":
999 ((mode & 0x70 )==OF_SHARE_DENY_NONE)?"OF_SHARE_DENY_NONE":
1000 ((mode & 0x70 )==OF_SHARE_DENY_READ)?"OF_SHARE_DENY_READ":
1001 ((mode & 0x70 )==OF_SHARE_DENY_WRITE)?"OF_SHARE_DENY_WRITE":
1002 ((mode & 0x70 )==OF_SHARE_EXCLUSIVE)?"OF_SHARE_EXCLUSIVE":"unknown",
1003 ((mode & OF_PARSE )==OF_PARSE)?"OF_PARSE ":"",
1004 ((mode & OF_DELETE )==OF_DELETE)?"OF_DELETE ":"",
1005 ((mode & OF_VERIFY )==OF_VERIFY)?"OF_VERIFY ":"",
1006 ((mode & OF_SEARCH )==OF_SEARCH)?"OF_SEARCH ":"",
1007 ((mode & OF_CANCEL )==OF_CANCEL)?"OF_CANCEL ":"",
1008 ((mode & OF_CREATE )==OF_CREATE)?"OF_CREATE ":"",
1009 ((mode & OF_PROMPT )==OF_PROMPT)?"OF_PROMPT ":"",
1010 ((mode & OF_EXIST )==OF_EXIST)?"OF_EXIST ":"",
1011 ((mode & OF_REOPEN )==OF_REOPEN)?"OF_REOPEN ":""
1015 ofs->cBytes = sizeof(OFSTRUCT);
1016 ofs->nErrCode = 0;
1017 if (mode & OF_REOPEN) name = ofs->szPathName;
1019 if (!name) {
1020 ERR("called with `name' set to NULL ! Please debug.\n");
1021 return HFILE_ERROR;
1024 TRACE("%s %04x\n", name, mode );
1026 /* the watcom 10.6 IDE relies on a valid path returned in ofs->szPathName
1027 Are there any cases where getting the path here is wrong?
1028 Uwe Bonnes 1997 Apr 2 */
1029 if (!GetFullPathNameA( name, sizeof(ofs->szPathName),
1030 ofs->szPathName, NULL )) goto error;
1031 FILE_ConvertOFMode( mode, &access, &sharing );
1033 /* OF_PARSE simply fills the structure */
1035 if (mode & OF_PARSE)
1037 ofs->fFixedDisk = (GetDriveType16( ofs->szPathName[0]-'A' )
1038 != DRIVE_REMOVABLE);
1039 TRACE("(%s): OF_PARSE, res = '%s'\n",
1040 name, ofs->szPathName );
1041 return 0;
1044 /* OF_CREATE is completely different from all other options, so
1045 handle it first */
1047 if (mode & OF_CREATE)
1049 if ((handle = CreateFileA( name, GENERIC_READ | GENERIC_WRITE,
1050 sharing, NULL, CREATE_ALWAYS,
1051 FILE_ATTRIBUTE_NORMAL, 0 ))== INVALID_HANDLE_VALUE)
1052 goto error;
1053 goto success;
1056 MultiByteToWideChar(CP_ACP, 0, name, -1, buffer, MAX_PATH);
1057 nameW = buffer;
1059 /* If OF_SEARCH is set, ignore the given path */
1061 if ((mode & OF_SEARCH) && !(mode & OF_REOPEN))
1063 /* First try the file name as is */
1064 if (DOSFS_GetFullName( nameW, TRUE, &full_name )) goto found;
1065 /* Now remove the path */
1066 if (nameW[0] && (nameW[1] == ':')) nameW += 2;
1067 if ((p = strrchrW( nameW, '\\' ))) nameW = p + 1;
1068 if ((p = strrchrW( nameW, '/' ))) nameW = p + 1;
1069 if (!nameW[0]) goto not_found;
1072 /* Now look for the file */
1074 if (!DIR_SearchPath( NULL, nameW, NULL, &full_name, win32 )) goto not_found;
1076 found:
1077 TRACE("found %s = %s\n",
1078 full_name.long_name, debugstr_w(full_name.short_name) );
1079 WideCharToMultiByte(CP_ACP, 0, full_name.short_name, -1,
1080 ofs->szPathName, sizeof(ofs->szPathName), NULL, NULL);
1082 if (mode & OF_DELETE)
1084 handle = FILE_CreateFile( full_name.long_name, GENERIC_READ|GENERIC_WRITE, 0,
1085 NULL, OPEN_EXISTING, 0, 0, TRUE,
1086 GetDriveTypeW( full_name.short_name ) );
1087 if (!handle) goto error;
1088 CloseHandle( handle );
1089 if (unlink( full_name.long_name ) == -1) goto not_found;
1090 TRACE("(%s): OF_DELETE return = OK\n", name);
1091 return 1;
1094 handle = FILE_CreateFile( full_name.long_name, access, sharing,
1095 NULL, OPEN_EXISTING, 0, 0,
1096 DRIVE_GetFlags(full_name.drive) & DRIVE_FAIL_READ_ONLY,
1097 GetDriveTypeW( full_name.short_name ) );
1098 if (!handle) goto not_found;
1100 GetFileTime( handle, NULL, NULL, &filetime );
1101 FileTimeToDosDateTime( &filetime, &filedatetime[0], &filedatetime[1] );
1102 if ((mode & OF_VERIFY) && (mode & OF_REOPEN))
1104 if (ofs->Reserved1 != filedatetime[0] || ofs->Reserved2 != filedatetime[1] )
1106 CloseHandle( handle );
1107 WARN("(%s): OF_VERIFY failed\n", name );
1108 /* FIXME: what error here? */
1109 SetLastError( ERROR_FILE_NOT_FOUND );
1110 goto error;
1113 ofs->Reserved1 = filedatetime[0];
1114 ofs->Reserved2 = filedatetime[1];
1116 success: /* We get here if the open was successful */
1117 TRACE("(%s): OK, return = %p\n", name, handle );
1118 if (win32)
1120 hFileRet = (HFILE)handle;
1121 if (mode & OF_EXIST) /* Return the handle, but close it first */
1122 CloseHandle( handle );
1124 else
1126 hFileRet = Win32HandleToDosFileHandle( handle );
1127 if (hFileRet == HFILE_ERROR16) goto error;
1128 if (mode & OF_EXIST) /* Return the handle, but close it first */
1129 _lclose16( hFileRet );
1131 return hFileRet;
1133 not_found: /* We get here if the file does not exist */
1134 WARN("'%s' not found or sharing violation\n", name );
1135 SetLastError( ERROR_FILE_NOT_FOUND );
1136 /* fall through */
1138 error: /* We get here if there was an error opening the file */
1139 ofs->nErrCode = GetLastError();
1140 WARN("(%s): return = HFILE_ERROR error= %d\n",
1141 name,ofs->nErrCode );
1142 return HFILE_ERROR;
1146 /***********************************************************************
1147 * OpenFile (KERNEL.74)
1148 * OpenFileEx (KERNEL.360)
1150 HFILE16 WINAPI OpenFile16( LPCSTR name, OFSTRUCT *ofs, UINT16 mode )
1152 return FILE_DoOpenFile( name, ofs, mode, FALSE );
1156 /***********************************************************************
1157 * OpenFile (KERNEL32.@)
1159 HFILE WINAPI OpenFile( LPCSTR name, OFSTRUCT *ofs, UINT mode )
1161 return FILE_DoOpenFile( name, ofs, mode, TRUE );
1165 /***********************************************************************
1166 * FILE_InitProcessDosHandles
1168 * Allocates the default DOS handles for a process. Called either by
1169 * Win32HandleToDosFileHandle below or by the DOSVM stuff.
1171 static void FILE_InitProcessDosHandles( void )
1173 HANDLE cp = GetCurrentProcess();
1174 DuplicateHandle(cp, GetStdHandle(STD_INPUT_HANDLE), cp, &dos_handles[0],
1175 0, TRUE, DUPLICATE_SAME_ACCESS);
1176 DuplicateHandle(cp, GetStdHandle(STD_OUTPUT_HANDLE), cp, &dos_handles[1],
1177 0, TRUE, DUPLICATE_SAME_ACCESS);
1178 DuplicateHandle(cp, GetStdHandle(STD_ERROR_HANDLE), cp, &dos_handles[2],
1179 0, TRUE, DUPLICATE_SAME_ACCESS);
1180 DuplicateHandle(cp, GetStdHandle(STD_ERROR_HANDLE), cp, &dos_handles[3],
1181 0, TRUE, DUPLICATE_SAME_ACCESS);
1182 DuplicateHandle(cp, GetStdHandle(STD_ERROR_HANDLE), cp, &dos_handles[4],
1183 0, TRUE, DUPLICATE_SAME_ACCESS);
1186 /***********************************************************************
1187 * Win32HandleToDosFileHandle (KERNEL32.21)
1189 * Allocate a DOS handle for a Win32 handle. The Win32 handle is no
1190 * longer valid after this function (even on failure).
1192 * Note: this is not exactly right, since on Win95 the Win32 handles
1193 * are on top of DOS handles and we do it the other way
1194 * around. Should be good enough though.
1196 HFILE WINAPI Win32HandleToDosFileHandle( HANDLE handle )
1198 int i;
1200 if (!handle || (handle == INVALID_HANDLE_VALUE))
1201 return HFILE_ERROR;
1203 for (i = 5; i < DOS_TABLE_SIZE; i++)
1204 if (!dos_handles[i])
1206 dos_handles[i] = handle;
1207 TRACE("Got %d for h32 %p\n", i, handle );
1208 return (HFILE)i;
1210 CloseHandle( handle );
1211 SetLastError( ERROR_TOO_MANY_OPEN_FILES );
1212 return HFILE_ERROR;
1216 /***********************************************************************
1217 * DosFileHandleToWin32Handle (KERNEL32.20)
1219 * Return the Win32 handle for a DOS handle.
1221 * Note: this is not exactly right, since on Win95 the Win32 handles
1222 * are on top of DOS handles and we do it the other way
1223 * around. Should be good enough though.
1225 HANDLE WINAPI DosFileHandleToWin32Handle( HFILE handle )
1227 HFILE16 hfile = (HFILE16)handle;
1228 if (hfile < 5 && !dos_handles[hfile]) FILE_InitProcessDosHandles();
1229 if ((hfile >= DOS_TABLE_SIZE) || !dos_handles[hfile])
1231 SetLastError( ERROR_INVALID_HANDLE );
1232 return INVALID_HANDLE_VALUE;
1234 return dos_handles[hfile];
1238 /***********************************************************************
1239 * DisposeLZ32Handle (KERNEL32.22)
1241 * Note: this is not entirely correct, we should only close the
1242 * 32-bit handle and not the 16-bit one, but we cannot do
1243 * this because of the way our DOS handles are implemented.
1244 * It shouldn't break anything though.
1246 void WINAPI DisposeLZ32Handle( HANDLE handle )
1248 int i;
1250 if (!handle || (handle == INVALID_HANDLE_VALUE)) return;
1252 for (i = 5; i < DOS_TABLE_SIZE; i++)
1253 if (dos_handles[i] == handle)
1255 dos_handles[i] = 0;
1256 CloseHandle( handle );
1257 break;
1262 /***********************************************************************
1263 * FILE_Dup2
1265 * dup2() function for DOS handles.
1267 HFILE16 FILE_Dup2( HFILE16 hFile1, HFILE16 hFile2 )
1269 HANDLE new_handle;
1271 if (hFile1 < 5 && !dos_handles[hFile1]) FILE_InitProcessDosHandles();
1273 if ((hFile1 >= DOS_TABLE_SIZE) || (hFile2 >= DOS_TABLE_SIZE) || !dos_handles[hFile1])
1275 SetLastError( ERROR_INVALID_HANDLE );
1276 return HFILE_ERROR16;
1278 if (!DuplicateHandle( GetCurrentProcess(), dos_handles[hFile1],
1279 GetCurrentProcess(), &new_handle,
1280 0, FALSE, DUPLICATE_SAME_ACCESS ))
1281 return HFILE_ERROR16;
1282 if (dos_handles[hFile2]) CloseHandle( dos_handles[hFile2] );
1283 dos_handles[hFile2] = new_handle;
1284 return hFile2;
1288 /***********************************************************************
1289 * _lclose (KERNEL.81)
1291 HFILE16 WINAPI _lclose16( HFILE16 hFile )
1293 if ((hFile >= DOS_TABLE_SIZE) || !dos_handles[hFile])
1295 SetLastError( ERROR_INVALID_HANDLE );
1296 return HFILE_ERROR16;
1298 TRACE("%d (handle32=%p)\n", hFile, dos_handles[hFile] );
1299 CloseHandle( dos_handles[hFile] );
1300 dos_handles[hFile] = 0;
1301 return 0;
1305 /******************************************************************
1306 * FILE_ReadWriteApc (internal)
1310 static void WINAPI FILE_ReadWriteApc(void* apc_user, PIO_STATUS_BLOCK io_status, ULONG len)
1312 LPOVERLAPPED_COMPLETION_ROUTINE cr = (LPOVERLAPPED_COMPLETION_ROUTINE)apc_user;
1314 cr(RtlNtStatusToDosError(io_status->u.Status), len, (LPOVERLAPPED)io_status);
1317 /***********************************************************************
1318 * ReadFileEx (KERNEL32.@)
1320 BOOL WINAPI ReadFileEx(HANDLE hFile, LPVOID buffer, DWORD bytesToRead,
1321 LPOVERLAPPED overlapped,
1322 LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine)
1324 LARGE_INTEGER offset;
1325 NTSTATUS status;
1326 PIO_STATUS_BLOCK io_status;
1328 if (!overlapped)
1330 SetLastError(ERROR_INVALID_PARAMETER);
1331 return FALSE;
1334 offset.s.LowPart = overlapped->Offset;
1335 offset.s.HighPart = overlapped->OffsetHigh;
1336 io_status = (PIO_STATUS_BLOCK)overlapped;
1337 io_status->u.Status = STATUS_PENDING;
1339 status = NtReadFile(hFile, NULL, FILE_ReadWriteApc, lpCompletionRoutine,
1340 io_status, buffer, bytesToRead, &offset, NULL);
1342 if (status)
1344 SetLastError( RtlNtStatusToDosError(status) );
1345 return FALSE;
1347 return TRUE;
1350 /***********************************************************************
1351 * ReadFile (KERNEL32.@)
1353 BOOL WINAPI ReadFile( HANDLE hFile, LPVOID buffer, DWORD bytesToRead,
1354 LPDWORD bytesRead, LPOVERLAPPED overlapped )
1356 LARGE_INTEGER offset;
1357 PLARGE_INTEGER poffset = NULL;
1358 IO_STATUS_BLOCK iosb;
1359 PIO_STATUS_BLOCK io_status = &iosb;
1360 HANDLE hEvent = 0;
1361 NTSTATUS status;
1363 TRACE("%p %p %ld %p %p\n", hFile, buffer, bytesToRead,
1364 bytesRead, overlapped );
1366 if (bytesRead) *bytesRead = 0; /* Do this before anything else */
1367 if (!bytesToRead) return TRUE;
1369 if (IsBadReadPtr(buffer, bytesToRead))
1371 SetLastError(ERROR_WRITE_FAULT); /* FIXME */
1372 return FALSE;
1374 if (is_console_handle(hFile))
1375 return ReadConsoleA(hFile, buffer, bytesToRead, bytesRead, NULL);
1377 if (overlapped != NULL)
1379 offset.s.LowPart = overlapped->Offset;
1380 offset.s.HighPart = overlapped->OffsetHigh;
1381 poffset = &offset;
1382 hEvent = overlapped->hEvent;
1383 io_status = (PIO_STATUS_BLOCK)overlapped;
1385 io_status->u.Status = STATUS_PENDING;
1386 io_status->Information = 0;
1388 status = NtReadFile(hFile, hEvent, NULL, NULL, io_status, buffer, bytesToRead, poffset, NULL);
1390 if (status != STATUS_PENDING && bytesRead)
1391 *bytesRead = io_status->Information;
1393 if (status && status != STATUS_END_OF_FILE)
1395 SetLastError( RtlNtStatusToDosError(status) );
1396 return FALSE;
1398 return TRUE;
1402 /***********************************************************************
1403 * WriteFileEx (KERNEL32.@)
1405 BOOL WINAPI WriteFileEx(HANDLE hFile, LPCVOID buffer, DWORD bytesToWrite,
1406 LPOVERLAPPED overlapped,
1407 LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine)
1409 LARGE_INTEGER offset;
1410 NTSTATUS status;
1411 PIO_STATUS_BLOCK io_status;
1413 TRACE("%p %p %ld %p %p\n",
1414 hFile, buffer, bytesToWrite, overlapped, lpCompletionRoutine);
1416 if (overlapped == NULL)
1418 SetLastError(ERROR_INVALID_PARAMETER);
1419 return FALSE;
1421 offset.s.LowPart = overlapped->Offset;
1422 offset.s.HighPart = overlapped->OffsetHigh;
1424 io_status = (PIO_STATUS_BLOCK)overlapped;
1425 io_status->u.Status = STATUS_PENDING;
1427 status = NtWriteFile(hFile, NULL, FILE_ReadWriteApc, lpCompletionRoutine,
1428 io_status, buffer, bytesToWrite, &offset, NULL);
1430 if (status) SetLastError( RtlNtStatusToDosError(status) );
1431 return !status;
1434 /***********************************************************************
1435 * WriteFile (KERNEL32.@)
1437 BOOL WINAPI WriteFile( HANDLE hFile, LPCVOID buffer, DWORD bytesToWrite,
1438 LPDWORD bytesWritten, LPOVERLAPPED overlapped )
1440 HANDLE hEvent = NULL;
1441 LARGE_INTEGER offset;
1442 PLARGE_INTEGER poffset = NULL;
1443 NTSTATUS status;
1444 IO_STATUS_BLOCK iosb;
1445 PIO_STATUS_BLOCK piosb = &iosb;
1447 TRACE("%p %p %ld %p %p\n",
1448 hFile, buffer, bytesToWrite, bytesWritten, overlapped );
1450 if (is_console_handle(hFile))
1451 return WriteConsoleA(hFile, buffer, bytesToWrite, bytesWritten, NULL);
1453 if (IsBadReadPtr(buffer, bytesToWrite))
1455 SetLastError(ERROR_READ_FAULT); /* FIXME */
1456 return FALSE;
1459 if (overlapped)
1461 offset.s.LowPart = overlapped->Offset;
1462 offset.s.HighPart = overlapped->OffsetHigh;
1463 poffset = &offset;
1464 hEvent = overlapped->hEvent;
1465 piosb = (PIO_STATUS_BLOCK)overlapped;
1467 piosb->u.Status = STATUS_PENDING;
1468 piosb->Information = 0;
1470 status = NtWriteFile(hFile, hEvent, NULL, NULL, piosb,
1471 buffer, bytesToWrite, poffset, NULL);
1472 if (status)
1474 SetLastError( RtlNtStatusToDosError(status) );
1475 return FALSE;
1477 if (bytesWritten) *bytesWritten = piosb->Information;
1479 return TRUE;
1483 /***********************************************************************
1484 * SetFilePointer (KERNEL32.@)
1486 DWORD WINAPI SetFilePointer( HANDLE hFile, LONG distance, LONG *highword,
1487 DWORD method )
1489 DWORD ret = INVALID_SET_FILE_POINTER;
1491 TRACE("handle %p offset %ld high %ld origin %ld\n",
1492 hFile, distance, highword?*highword:0, method );
1494 SERVER_START_REQ( set_file_pointer )
1496 req->handle = hFile;
1497 req->low = distance;
1498 req->high = highword ? *highword : (distance >= 0) ? 0 : -1;
1499 /* FIXME: assumes 1:1 mapping between Windows and Unix seek constants */
1500 req->whence = method;
1501 SetLastError( 0 );
1502 if (!wine_server_call_err( req ))
1504 ret = reply->new_low;
1505 if (highword) *highword = reply->new_high;
1508 SERVER_END_REQ;
1509 return ret;
1513 /*************************************************************************
1514 * SetHandleCount (KERNEL32.@)
1516 UINT WINAPI SetHandleCount( UINT count )
1518 return min( 256, count );
1522 /**************************************************************************
1523 * SetEndOfFile (KERNEL32.@)
1525 BOOL WINAPI SetEndOfFile( HANDLE hFile )
1527 BOOL ret;
1528 SERVER_START_REQ( truncate_file )
1530 req->handle = hFile;
1531 ret = !wine_server_call_err( req );
1533 SERVER_END_REQ;
1534 return ret;
1538 /***********************************************************************
1539 * DeleteFileW (KERNEL32.@)
1541 BOOL WINAPI DeleteFileW( LPCWSTR path )
1543 DOS_FULL_NAME full_name;
1544 HANDLE hFile;
1546 TRACE("%s\n", debugstr_w(path) );
1547 if (!path || !*path)
1549 SetLastError(ERROR_PATH_NOT_FOUND);
1550 return FALSE;
1552 if (DOSFS_GetDevice( path ))
1554 WARN("cannot remove DOS device %s!\n", debugstr_w(path));
1555 SetLastError( ERROR_FILE_NOT_FOUND );
1556 return FALSE;
1559 if (!DOSFS_GetFullName( path, TRUE, &full_name )) return FALSE;
1561 /* check if we are allowed to delete the source */
1562 hFile = FILE_CreateFile( full_name.long_name, GENERIC_READ|GENERIC_WRITE, 0,
1563 NULL, OPEN_EXISTING, 0, 0, TRUE,
1564 GetDriveTypeW( full_name.short_name ) );
1565 if (!hFile) return FALSE;
1567 if (unlink( full_name.long_name ) == -1)
1569 FILE_SetDosError();
1570 CloseHandle(hFile);
1571 return FALSE;
1573 CloseHandle(hFile);
1574 return TRUE;
1578 /***********************************************************************
1579 * DeleteFileA (KERNEL32.@)
1581 BOOL WINAPI DeleteFileA( LPCSTR path )
1583 UNICODE_STRING pathW;
1584 BOOL ret = FALSE;
1586 if (!path)
1588 SetLastError(ERROR_INVALID_PARAMETER);
1589 return FALSE;
1592 if (RtlCreateUnicodeStringFromAsciiz(&pathW, path))
1594 ret = DeleteFileW(pathW.Buffer);
1595 RtlFreeUnicodeString(&pathW);
1597 else
1598 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1599 return ret;
1603 /***********************************************************************
1604 * GetFileType (KERNEL32.@)
1606 DWORD WINAPI GetFileType( HANDLE hFile )
1608 DWORD ret = FILE_TYPE_UNKNOWN;
1610 if (is_console_handle( hFile ))
1611 return FILE_TYPE_CHAR;
1613 SERVER_START_REQ( get_file_info )
1615 req->handle = hFile;
1616 if (!wine_server_call_err( req )) ret = reply->type;
1618 SERVER_END_REQ;
1619 return ret;
1623 /* check if a file name is for an executable file (.exe or .com) */
1624 inline static BOOL is_executable( const char *name )
1626 int len = strlen(name);
1628 if (len < 4) return FALSE;
1629 return (!strcasecmp( name + len - 4, ".exe" ) ||
1630 !strcasecmp( name + len - 4, ".com" ));
1634 /***********************************************************************
1635 * FILE_AddBootRenameEntry
1637 * Adds an entry to the registry that is loaded when windows boots and
1638 * checks if there are some files to be removed or renamed/moved.
1639 * <fn1> has to be valid and <fn2> may be NULL. If both pointers are
1640 * non-NULL then the file is moved, otherwise it is deleted. The
1641 * entry of the registrykey is always appended with two zero
1642 * terminated strings. If <fn2> is NULL then the second entry is
1643 * simply a single 0-byte. Otherwise the second filename goes
1644 * there. The entries are prepended with \??\ before the path and the
1645 * second filename gets also a '!' as the first character if
1646 * MOVEFILE_REPLACE_EXISTING is set. After the final string another
1647 * 0-byte follows to indicate the end of the strings.
1648 * i.e.:
1649 * \??\D:\test\file1[0]
1650 * !\??\D:\test\file1_renamed[0]
1651 * \??\D:\Test|delete[0]
1652 * [0] <- file is to be deleted, second string empty
1653 * \??\D:\test\file2[0]
1654 * !\??\D:\test\file2_renamed[0]
1655 * [0] <- indicates end of strings
1657 * or:
1658 * \??\D:\test\file1[0]
1659 * !\??\D:\test\file1_renamed[0]
1660 * \??\D:\Test|delete[0]
1661 * [0] <- file is to be deleted, second string empty
1662 * [0] <- indicates end of strings
1665 static BOOL FILE_AddBootRenameEntry( LPCWSTR fn1, LPCWSTR fn2, DWORD flags )
1667 static const WCHAR PreString[] = {'\\','?','?','\\',0};
1668 static const WCHAR ValueName[] = {'P','e','n','d','i','n','g',
1669 'F','i','l','e','R','e','n','a','m','e',
1670 'O','p','e','r','a','t','i','o','n','s',0};
1671 static const WCHAR SessionW[] = {'M','a','c','h','i','n','e','\\',
1672 'S','y','s','t','e','m','\\',
1673 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
1674 'C','o','n','t','r','o','l','\\',
1675 'S','e','s','s','i','o','n',' ','M','a','n','a','g','e','r',0};
1676 static const int info_size = FIELD_OFFSET( KEY_VALUE_PARTIAL_INFORMATION, Data );
1678 OBJECT_ATTRIBUTES attr;
1679 UNICODE_STRING nameW;
1680 KEY_VALUE_PARTIAL_INFORMATION *info;
1681 BOOL rc = FALSE;
1682 HKEY Reboot = 0;
1683 DWORD len0, len1, len2;
1684 DWORD DataSize = 0;
1685 BYTE *Buffer = NULL;
1686 WCHAR *p;
1688 attr.Length = sizeof(attr);
1689 attr.RootDirectory = 0;
1690 attr.ObjectName = &nameW;
1691 attr.Attributes = 0;
1692 attr.SecurityDescriptor = NULL;
1693 attr.SecurityQualityOfService = NULL;
1694 RtlInitUnicodeString( &nameW, SessionW );
1696 if (NtCreateKey( &Reboot, KEY_ALL_ACCESS, &attr, 0, NULL, 0, NULL ) != STATUS_SUCCESS)
1698 WARN("Error creating key for reboot managment [%s]\n",
1699 "SYSTEM\\CurrentControlSet\\Control\\Session Manager");
1700 return FALSE;
1703 len0 = strlenW(PreString);
1704 len1 = strlenW(fn1) + len0 + 1;
1705 if (fn2)
1707 len2 = strlenW(fn2) + len0 + 1;
1708 if (flags & MOVEFILE_REPLACE_EXISTING) len2++; /* Plus 1 because of the leading '!' */
1710 else len2 = 1; /* minimum is the 0 characters for the empty second string */
1712 /* convert characters to bytes */
1713 len0 *= sizeof(WCHAR);
1714 len1 *= sizeof(WCHAR);
1715 len2 *= sizeof(WCHAR);
1717 RtlInitUnicodeString( &nameW, ValueName );
1719 /* First we check if the key exists and if so how many bytes it already contains. */
1720 if (NtQueryValueKey( Reboot, &nameW, KeyValuePartialInformation,
1721 NULL, 0, &DataSize ) == STATUS_BUFFER_OVERFLOW)
1723 if (!(Buffer = HeapAlloc( GetProcessHeap(), 0, DataSize + len1 + len2 + sizeof(WCHAR) )))
1724 goto Quit;
1725 if (NtQueryValueKey( Reboot, &nameW, KeyValuePartialInformation,
1726 Buffer, DataSize, &DataSize )) goto Quit;
1727 info = (KEY_VALUE_PARTIAL_INFORMATION *)Buffer;
1728 if (info->Type != REG_MULTI_SZ) goto Quit;
1729 if (DataSize > sizeof(info)) DataSize -= sizeof(WCHAR); /* remove terminating null (will be added back later) */
1731 else
1733 DataSize = info_size;
1734 if (!(Buffer = HeapAlloc( GetProcessHeap(), 0, DataSize + len1 + len2 + sizeof(WCHAR) )))
1735 goto Quit;
1738 p = (WCHAR *)(Buffer + DataSize);
1739 strcpyW( p, PreString );
1740 strcatW( p, fn1 );
1741 DataSize += len1;
1742 if (fn2)
1744 p = (WCHAR *)(Buffer + DataSize);
1745 if (flags & MOVEFILE_REPLACE_EXISTING)
1746 *p++ = '!';
1747 strcpyW( p, PreString );
1748 strcatW( p, fn2 );
1749 DataSize += len2;
1751 else
1753 p = (WCHAR *)(Buffer + DataSize);
1754 *p = 0;
1755 DataSize += sizeof(WCHAR);
1758 /* add final null */
1759 p = (WCHAR *)(Buffer + DataSize);
1760 *p = 0;
1761 DataSize += sizeof(WCHAR);
1763 rc = !NtSetValueKey(Reboot, &nameW, 0, REG_MULTI_SZ, Buffer + info_size, DataSize - info_size);
1765 Quit:
1766 if (Reboot) NtClose(Reboot);
1767 if (Buffer) HeapFree( GetProcessHeap(), 0, Buffer );
1768 return(rc);
1772 /**************************************************************************
1773 * MoveFileExW (KERNEL32.@)
1775 BOOL WINAPI MoveFileExW( LPCWSTR fn1, LPCWSTR fn2, DWORD flag )
1777 DOS_FULL_NAME full_name1, full_name2;
1778 HANDLE hFile;
1779 DWORD attr = INVALID_FILE_ATTRIBUTES;
1781 TRACE("(%s,%s,%04lx)\n", debugstr_w(fn1), debugstr_w(fn2), flag);
1783 /* FIXME: <Gerhard W. Gruber>sparhawk@gmx.at
1784 In case of W9x and lesser this function should return 120 (ERROR_CALL_NOT_IMPLEMENTED)
1785 to be really compatible. Most programs wont have any problems though. In case
1786 you encounter one, this is what you should return here. I don't know what's up
1787 with NT 3.5. Is this function available there or not?
1788 Does anybody really care about 3.5? :)
1791 /* Filename1 has to be always set to a valid path. Filename2 may be NULL
1792 if the source file has to be deleted.
1794 if (!fn1) {
1795 SetLastError(ERROR_INVALID_PARAMETER);
1796 return FALSE;
1799 /* This function has to be run through in order to process the name properly.
1800 If the BOOTDELAY flag is set, the file doesn't need to exist though. At least
1801 that is the behaviour on NT 4.0. The operation accepts the filenames as
1802 they are given but it can't reply with a reasonable returncode. Success
1803 means in that case success for entering the values into the registry.
1805 if(!DOSFS_GetFullName( fn1, TRUE, &full_name1 ))
1807 if(!(flag & MOVEFILE_DELAY_UNTIL_REBOOT))
1808 return FALSE;
1811 if (fn2) /* !fn2 means delete fn1 */
1813 if (DOSFS_GetFullName( fn2, TRUE, &full_name2 ))
1815 if(!(flag & MOVEFILE_DELAY_UNTIL_REBOOT))
1817 /* target exists, check if we may overwrite */
1818 if (!(flag & MOVEFILE_REPLACE_EXISTING))
1820 SetLastError( ERROR_FILE_EXISTS );
1821 return FALSE;
1825 else
1827 if (!DOSFS_GetFullName( fn2, FALSE, &full_name2 ))
1829 if(!(flag & MOVEFILE_DELAY_UNTIL_REBOOT))
1830 return FALSE;
1834 /* Source name and target path are valid */
1836 if (flag & MOVEFILE_DELAY_UNTIL_REBOOT)
1838 return FILE_AddBootRenameEntry( fn1, fn2, flag );
1841 attr = GetFileAttributesW( fn1 );
1842 if ( attr == INVALID_FILE_ATTRIBUTES ) return FALSE;
1844 /* check if we are allowed to rename the source */
1845 hFile = FILE_CreateFile( full_name1.long_name, 0, 0,
1846 NULL, OPEN_EXISTING, 0, 0, TRUE,
1847 GetDriveTypeW( full_name1.short_name ) );
1848 if (!hFile)
1850 if (GetLastError() != ERROR_ACCESS_DENIED) return FALSE;
1851 if ( !(attr & FILE_ATTRIBUTE_DIRECTORY) ) return FALSE;
1852 /* if it's a directory we can continue */
1854 else CloseHandle(hFile);
1856 /* check, if we are allowed to delete the destination,
1857 ** (but the file not being there is fine) */
1858 hFile = FILE_CreateFile( full_name2.long_name, GENERIC_READ|GENERIC_WRITE, 0,
1859 NULL, OPEN_EXISTING, 0, 0, TRUE,
1860 GetDriveTypeW( full_name2.short_name ) );
1861 if(!hFile && GetLastError() != ERROR_FILE_NOT_FOUND) return FALSE;
1862 CloseHandle(hFile);
1864 if (full_name1.drive != full_name2.drive)
1866 if (!(flag & MOVEFILE_COPY_ALLOWED))
1868 SetLastError( ERROR_NOT_SAME_DEVICE );
1869 return FALSE;
1871 else if ( attr & FILE_ATTRIBUTE_DIRECTORY )
1873 /* Strange, but that's what Windows returns */
1874 SetLastError ( ERROR_ACCESS_DENIED );
1875 return FALSE;
1878 if (rename( full_name1.long_name, full_name2.long_name ) == -1)
1879 /* Try copy/delete unless it's a directory. */
1880 /* FIXME: This does not handle the (unlikely) case that the two locations
1881 are on the same Wine drive, but on different Unix file systems. */
1883 if ( attr & FILE_ATTRIBUTE_DIRECTORY )
1885 FILE_SetDosError();
1886 return FALSE;
1888 else
1890 if ( ! CopyFileW( fn1, fn2, !(flag & MOVEFILE_REPLACE_EXISTING) ))
1891 return FALSE;
1892 if ( ! DeleteFileW ( fn1 ) )
1893 return FALSE;
1896 if (is_executable( full_name1.long_name ) != is_executable( full_name2.long_name ))
1898 struct stat fstat;
1899 if (stat( full_name2.long_name, &fstat ) != -1)
1901 if (is_executable( full_name2.long_name ))
1902 /* set executable bit where read bit is set */
1903 fstat.st_mode |= (fstat.st_mode & 0444) >> 2;
1904 else
1905 fstat.st_mode &= ~0111;
1906 chmod( full_name2.long_name, fstat.st_mode );
1909 return TRUE;
1911 else /* fn2 == NULL means delete source */
1913 if (flag & MOVEFILE_DELAY_UNTIL_REBOOT)
1915 if (flag & MOVEFILE_COPY_ALLOWED) {
1916 WARN("Illegal flag\n");
1917 SetLastError( ERROR_GEN_FAILURE );
1918 return FALSE;
1921 return FILE_AddBootRenameEntry( fn1, NULL, flag );
1924 if (unlink( full_name1.long_name ) == -1)
1926 FILE_SetDosError();
1927 return FALSE;
1929 return TRUE; /* successfully deleted */
1933 /**************************************************************************
1934 * MoveFileExA (KERNEL32.@)
1936 BOOL WINAPI MoveFileExA( LPCSTR fn1, LPCSTR fn2, DWORD flag )
1938 UNICODE_STRING fn1W, fn2W;
1939 BOOL ret;
1941 if (!fn1)
1943 SetLastError(ERROR_INVALID_PARAMETER);
1944 return FALSE;
1947 RtlCreateUnicodeStringFromAsciiz(&fn1W, fn1);
1948 if (fn2) RtlCreateUnicodeStringFromAsciiz(&fn2W, fn2);
1949 else fn2W.Buffer = NULL;
1951 ret = MoveFileExW( fn1W.Buffer, fn2W.Buffer, flag );
1953 RtlFreeUnicodeString(&fn1W);
1954 RtlFreeUnicodeString(&fn2W);
1955 return ret;
1959 /**************************************************************************
1960 * MoveFileW (KERNEL32.@)
1962 * Move file or directory
1964 BOOL WINAPI MoveFileW( LPCWSTR fn1, LPCWSTR fn2 )
1966 return MoveFileExW( fn1, fn2, MOVEFILE_COPY_ALLOWED );
1970 /**************************************************************************
1971 * MoveFileA (KERNEL32.@)
1973 BOOL WINAPI MoveFileA( LPCSTR fn1, LPCSTR fn2 )
1975 return MoveFileExA( fn1, fn2, MOVEFILE_COPY_ALLOWED );
1979 /**************************************************************************
1980 * CopyFileW (KERNEL32.@)
1982 BOOL WINAPI CopyFileW( LPCWSTR source, LPCWSTR dest, BOOL fail_if_exists )
1984 HANDLE h1, h2;
1985 BY_HANDLE_FILE_INFORMATION info;
1986 DWORD count;
1987 BOOL ret = FALSE;
1988 char buffer[2048];
1990 if (!source || !dest)
1992 SetLastError(ERROR_INVALID_PARAMETER);
1993 return FALSE;
1996 TRACE("%s -> %s\n", debugstr_w(source), debugstr_w(dest));
1998 if ((h1 = CreateFileW(source, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE,
1999 NULL, OPEN_EXISTING, 0, 0)) == INVALID_HANDLE_VALUE)
2001 WARN("Unable to open source %s\n", debugstr_w(source));
2002 return FALSE;
2005 if (!GetFileInformationByHandle( h1, &info ))
2007 WARN("GetFileInformationByHandle returned error for %s\n", debugstr_w(source));
2008 CloseHandle( h1 );
2009 return FALSE;
2012 if ((h2 = CreateFileW( dest, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
2013 fail_if_exists ? CREATE_NEW : CREATE_ALWAYS,
2014 info.dwFileAttributes, h1 )) == INVALID_HANDLE_VALUE)
2016 WARN("Unable to open dest %s\n", debugstr_w(dest));
2017 CloseHandle( h1 );
2018 return FALSE;
2021 while (ReadFile( h1, buffer, sizeof(buffer), &count, NULL ) && count)
2023 char *p = buffer;
2024 while (count != 0)
2026 DWORD res;
2027 if (!WriteFile( h2, p, count, &res, NULL ) || !res) goto done;
2028 p += res;
2029 count -= res;
2032 ret = TRUE;
2033 done:
2034 CloseHandle( h1 );
2035 CloseHandle( h2 );
2036 return ret;
2040 /**************************************************************************
2041 * CopyFileA (KERNEL32.@)
2043 BOOL WINAPI CopyFileA( LPCSTR source, LPCSTR dest, BOOL fail_if_exists)
2045 UNICODE_STRING sourceW, destW;
2046 BOOL ret;
2048 if (!source || !dest)
2050 SetLastError(ERROR_INVALID_PARAMETER);
2051 return FALSE;
2054 RtlCreateUnicodeStringFromAsciiz(&sourceW, source);
2055 RtlCreateUnicodeStringFromAsciiz(&destW, dest);
2057 ret = CopyFileW(sourceW.Buffer, destW.Buffer, fail_if_exists);
2059 RtlFreeUnicodeString(&sourceW);
2060 RtlFreeUnicodeString(&destW);
2061 return ret;
2065 /**************************************************************************
2066 * CopyFileExW (KERNEL32.@)
2068 * This implementation ignores most of the extra parameters passed-in into
2069 * the "ex" version of the method and calls the CopyFile method.
2070 * It will have to be fixed eventually.
2072 BOOL WINAPI CopyFileExW(LPCWSTR sourceFilename, LPCWSTR destFilename,
2073 LPPROGRESS_ROUTINE progressRoutine, LPVOID appData,
2074 LPBOOL cancelFlagPointer, DWORD copyFlags)
2077 * Interpret the only flag that CopyFile can interpret.
2079 return CopyFileW(sourceFilename, destFilename, (copyFlags & COPY_FILE_FAIL_IF_EXISTS) != 0);
2083 /**************************************************************************
2084 * CopyFileExA (KERNEL32.@)
2086 BOOL WINAPI CopyFileExA(LPCSTR sourceFilename, LPCSTR destFilename,
2087 LPPROGRESS_ROUTINE progressRoutine, LPVOID appData,
2088 LPBOOL cancelFlagPointer, DWORD copyFlags)
2090 UNICODE_STRING sourceW, destW;
2091 BOOL ret;
2093 if (!sourceFilename || !destFilename)
2095 SetLastError(ERROR_INVALID_PARAMETER);
2096 return FALSE;
2099 RtlCreateUnicodeStringFromAsciiz(&sourceW, sourceFilename);
2100 RtlCreateUnicodeStringFromAsciiz(&destW, destFilename);
2102 ret = CopyFileExW(sourceW.Buffer, destW.Buffer, progressRoutine, appData,
2103 cancelFlagPointer, copyFlags);
2105 RtlFreeUnicodeString(&sourceW);
2106 RtlFreeUnicodeString(&destW);
2107 return ret;
2111 /***********************************************************************
2112 * SetFileTime (KERNEL32.@)
2114 BOOL WINAPI SetFileTime( HANDLE hFile,
2115 const FILETIME *lpCreationTime,
2116 const FILETIME *lpLastAccessTime,
2117 const FILETIME *lpLastWriteTime )
2119 BOOL ret;
2120 SERVER_START_REQ( set_file_time )
2122 req->handle = hFile;
2123 if (lpLastAccessTime)
2124 RtlTimeToSecondsSince1970( (PLARGE_INTEGER) lpLastAccessTime, (DWORD *)&req->access_time );
2125 else
2126 req->access_time = 0; /* FIXME */
2127 if (lpLastWriteTime)
2128 RtlTimeToSecondsSince1970( (PLARGE_INTEGER) lpLastWriteTime, (DWORD *)&req->write_time );
2129 else
2130 req->write_time = 0; /* FIXME */
2131 ret = !wine_server_call_err( req );
2133 SERVER_END_REQ;
2134 return ret;
2138 /**************************************************************************
2139 * GetFileAttributesExW (KERNEL32.@)
2141 BOOL WINAPI GetFileAttributesExW(
2142 LPCWSTR lpFileName, GET_FILEEX_INFO_LEVELS fInfoLevelId,
2143 LPVOID lpFileInformation)
2145 DOS_FULL_NAME full_name;
2146 BY_HANDLE_FILE_INFORMATION info;
2148 if (!lpFileName || !lpFileInformation)
2150 SetLastError(ERROR_INVALID_PARAMETER);
2151 return FALSE;
2154 if (fInfoLevelId == GetFileExInfoStandard) {
2155 LPWIN32_FILE_ATTRIBUTE_DATA lpFad =
2156 (LPWIN32_FILE_ATTRIBUTE_DATA) lpFileInformation;
2157 if (!DOSFS_GetFullName( lpFileName, TRUE, &full_name )) return FALSE;
2158 if (!FILE_Stat( full_name.long_name, &info, NULL )) return FALSE;
2160 lpFad->dwFileAttributes = info.dwFileAttributes;
2161 lpFad->ftCreationTime = info.ftCreationTime;
2162 lpFad->ftLastAccessTime = info.ftLastAccessTime;
2163 lpFad->ftLastWriteTime = info.ftLastWriteTime;
2164 lpFad->nFileSizeHigh = info.nFileSizeHigh;
2165 lpFad->nFileSizeLow = info.nFileSizeLow;
2167 else {
2168 FIXME("invalid info level %d!\n", fInfoLevelId);
2169 return FALSE;
2172 return TRUE;
2176 /**************************************************************************
2177 * GetFileAttributesExA (KERNEL32.@)
2179 BOOL WINAPI GetFileAttributesExA(
2180 LPCSTR filename, GET_FILEEX_INFO_LEVELS fInfoLevelId,
2181 LPVOID lpFileInformation)
2183 UNICODE_STRING filenameW;
2184 BOOL ret = FALSE;
2186 if (!filename || !lpFileInformation)
2188 SetLastError(ERROR_INVALID_PARAMETER);
2189 return FALSE;
2192 if (RtlCreateUnicodeStringFromAsciiz(&filenameW, filename))
2194 ret = GetFileAttributesExW(filenameW.Buffer, fInfoLevelId, lpFileInformation);
2195 RtlFreeUnicodeString(&filenameW);
2197 else
2198 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
2199 return ret;