Localization to Portuguese of Brazil of README file.
[wine/dcerpc.git] / files / file.c
bloba53ed8d3a2c6dc09f9b2cf91ebab3ffc4a3b48ac
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 <stdio.h>
35 #include <string.h>
36 #ifdef HAVE_SYS_ERRNO_H
37 #include <sys/errno.h>
38 #endif
39 #include <sys/types.h>
40 #include <sys/stat.h>
41 #ifdef HAVE_SYS_MMAN_H
42 #include <sys/mman.h>
43 #endif
44 #ifdef HAVE_SYS_TIME_H
45 # include <sys/time.h>
46 #endif
47 #ifdef HAVE_SYS_POLL_H
48 # include <sys/poll.h>
49 #endif
50 #include <time.h>
51 #ifdef HAVE_UNISTD_H
52 # include <unistd.h>
53 #endif
54 #ifdef HAVE_UTIME_H
55 # include <utime.h>
56 #endif
58 #define NONAMELESSUNION
59 #define NONAMELESSSTRUCT
60 #include "winerror.h"
61 #include "windef.h"
62 #include "winbase.h"
63 #include "winternl.h"
64 #include "wine/winbase16.h"
65 #include "wine/server.h"
67 #include "drive.h"
68 #include "file.h"
69 #include "heap.h"
70 #include "msdos.h"
71 #include "wincon.h"
72 #include "../kernel/kernel_private.h"
74 #include "smb.h"
75 #include "wine/unicode.h"
76 #include "wine/debug.h"
78 WINE_DEFAULT_DEBUG_CHANNEL(file);
80 #if defined(MAP_ANONYMOUS) && !defined(MAP_ANON)
81 #define MAP_ANON MAP_ANONYMOUS
82 #endif
84 HANDLE dos_handles[DOS_TABLE_SIZE];
85 mode_t FILE_umask;
87 /***********************************************************************
88 * FILE_ConvertOFMode
90 * Convert OF_* mode into flags for CreateFile.
92 void FILE_ConvertOFMode( INT mode, DWORD *access, DWORD *sharing )
94 switch(mode & 0x03)
96 case OF_READ: *access = GENERIC_READ; break;
97 case OF_WRITE: *access = GENERIC_WRITE; break;
98 case OF_READWRITE: *access = GENERIC_READ | GENERIC_WRITE; break;
99 default: *access = 0; break;
101 switch(mode & 0x70)
103 case OF_SHARE_EXCLUSIVE: *sharing = 0; break;
104 case OF_SHARE_DENY_WRITE: *sharing = FILE_SHARE_READ; break;
105 case OF_SHARE_DENY_READ: *sharing = FILE_SHARE_WRITE; break;
106 case OF_SHARE_DENY_NONE:
107 case OF_SHARE_COMPAT:
108 default: *sharing = FILE_SHARE_READ | FILE_SHARE_WRITE; break;
113 /***********************************************************************
114 * FILE_strcasecmp
116 * locale-independent case conversion for file I/O
118 int FILE_strcasecmp( const char *str1, const char *str2 )
120 int ret = 0;
121 for ( ; ; str1++, str2++)
122 if ((ret = FILE_toupper(*str1) - FILE_toupper(*str2)) || !*str1) break;
123 return ret;
127 /***********************************************************************
128 * FILE_strncasecmp
130 * locale-independent case conversion for file I/O
132 int FILE_strncasecmp( const char *str1, const char *str2, int len )
134 int ret = 0;
135 for ( ; len > 0; len--, str1++, str2++)
136 if ((ret = FILE_toupper(*str1) - FILE_toupper(*str2)) || !*str1) break;
137 return ret;
141 /***********************************************************************
142 * FILE_SetDosError
144 * Set the DOS error code from errno.
146 void FILE_SetDosError(void)
148 int save_errno = errno; /* errno gets overwritten by printf */
150 TRACE("errno = %d %s\n", errno, strerror(errno));
151 switch (save_errno)
153 case EAGAIN:
154 SetLastError( ERROR_SHARING_VIOLATION );
155 break;
156 case EBADF:
157 SetLastError( ERROR_INVALID_HANDLE );
158 break;
159 case ENOSPC:
160 SetLastError( ERROR_HANDLE_DISK_FULL );
161 break;
162 case EACCES:
163 case EPERM:
164 case EROFS:
165 SetLastError( ERROR_ACCESS_DENIED );
166 break;
167 case EBUSY:
168 SetLastError( ERROR_LOCK_VIOLATION );
169 break;
170 case ENOENT:
171 SetLastError( ERROR_FILE_NOT_FOUND );
172 break;
173 case EISDIR:
174 SetLastError( ERROR_CANNOT_MAKE );
175 break;
176 case ENFILE:
177 case EMFILE:
178 SetLastError( ERROR_NO_MORE_FILES );
179 break;
180 case EEXIST:
181 SetLastError( ERROR_FILE_EXISTS );
182 break;
183 case EINVAL:
184 case ESPIPE:
185 SetLastError( ERROR_SEEK );
186 break;
187 case ENOTEMPTY:
188 SetLastError( ERROR_DIR_NOT_EMPTY );
189 break;
190 case ENOEXEC:
191 SetLastError( ERROR_BAD_FORMAT );
192 break;
193 default:
194 WARN("unknown file error: %s\n", strerror(save_errno) );
195 SetLastError( ERROR_GEN_FAILURE );
196 break;
198 errno = save_errno;
202 /***********************************************************************
203 * FILE_GetUnixHandleType
205 * Retrieve the Unix handle corresponding to a file handle.
206 * Returns -1 on failure.
208 static int FILE_GetUnixHandleType( HANDLE handle, DWORD access, enum fd_type *type, int *flags_ptr )
210 int ret, flags, fd = -1;
212 ret = wine_server_handle_to_fd( handle, access, &fd, type, &flags );
213 if (flags_ptr) *flags_ptr = flags;
214 if (ret) SetLastError( RtlNtStatusToDosError(ret) );
215 else if (((access & GENERIC_READ) && (flags & FD_FLAG_RECV_SHUTDOWN)) ||
216 ((access & GENERIC_WRITE) && (flags & FD_FLAG_SEND_SHUTDOWN)))
218 close (fd);
219 SetLastError ( ERROR_PIPE_NOT_CONNECTED );
220 return -1;
222 return fd;
225 /***********************************************************************
226 * FILE_GetUnixHandle
228 * Retrieve the Unix handle corresponding to a file handle.
229 * Returns -1 on failure.
231 int FILE_GetUnixHandle( HANDLE handle, DWORD access )
233 return FILE_GetUnixHandleType( handle, access, NULL, NULL );
236 /******************************************************************
237 * OpenConsoleW (KERNEL32.@)
239 * Undocumented
240 * Open a handle to the current process console.
241 * Returns INVALID_HANDLE_VALUE on failure.
243 HANDLE WINAPI OpenConsoleW(LPCWSTR name, DWORD access, LPSECURITY_ATTRIBUTES sa,
244 DWORD creation)
246 static const WCHAR coninW[] = {'C','O','N','I','N','$',0};
247 static const WCHAR conoutW[] = {'C','O','N','O','U','T','$',0};
248 BOOL output;
249 HANDLE ret;
251 if (strcmpW(coninW, name) == 0)
252 output = FALSE;
253 else if (strcmpW(conoutW, name) == 0)
254 output = TRUE;
255 else
257 SetLastError(ERROR_INVALID_NAME);
258 return INVALID_HANDLE_VALUE;
260 if (creation != OPEN_EXISTING)
262 SetLastError(ERROR_INVALID_PARAMETER);
263 return INVALID_HANDLE_VALUE;
266 SERVER_START_REQ( open_console )
268 req->from = output;
269 req->access = access;
270 req->share = FILE_SHARE_READ | FILE_SHARE_WRITE;
271 req->inherit = (sa && (sa->nLength>=sizeof(*sa)) && sa->bInheritHandle);
272 SetLastError(0);
273 wine_server_call_err( req );
274 ret = reply->handle;
276 SERVER_END_REQ;
277 return ret ? console_handle_map(ret) : INVALID_HANDLE_VALUE;
280 /******************************************************************
281 * VerifyConsoleIoHandle (KERNEL32.@)
283 * Undocumented
285 BOOL WINAPI VerifyConsoleIoHandle(HANDLE handle)
287 BOOL ret;
289 if (!is_console_handle(handle)) return FALSE;
290 SERVER_START_REQ(get_console_mode)
292 req->handle = console_handle_unmap(handle);
293 ret = !wine_server_call_err( req );
295 SERVER_END_REQ;
296 return ret;
299 /******************************************************************
300 * DuplicateConsoleHandle (KERNEL32.@)
302 * Undocumented
304 HANDLE WINAPI DuplicateConsoleHandle(HANDLE handle, DWORD access, BOOL inherit,
305 DWORD options)
307 HANDLE ret;
309 if (!is_console_handle(handle) ||
310 !DuplicateHandle(GetCurrentProcess(), console_handle_unmap(handle),
311 GetCurrentProcess(), &ret, access, inherit, options))
312 return INVALID_HANDLE_VALUE;
313 return console_handle_map(ret);
316 /******************************************************************
317 * CloseConsoleHandle (KERNEL32.@)
319 * Undocumented
321 BOOL WINAPI CloseConsoleHandle(HANDLE handle)
323 if (!is_console_handle(handle))
325 SetLastError(ERROR_INVALID_PARAMETER);
326 return FALSE;
328 return CloseHandle(console_handle_unmap(handle));
331 /******************************************************************
332 * GetConsoleInputWaitHandle (KERNEL32.@)
334 * Undocumented
336 HANDLE WINAPI GetConsoleInputWaitHandle(void)
338 static HANDLE console_wait_event;
340 /* FIXME: this is not thread safe */
341 if (!console_wait_event)
343 SERVER_START_REQ(get_console_wait_event)
345 if (!wine_server_call_err( req )) console_wait_event = reply->handle;
347 SERVER_END_REQ;
349 return console_wait_event;
351 /* end of FIXME */
354 /* FIXME: those routines defined as pointers are needed, because this file is
355 * currently compiled into NTDLL whereas it belongs to kernel32.
356 * this shall go away once all the DLL separation process is done
358 typedef BOOL (WINAPI* pRW)(HANDLE, const void*, DWORD, DWORD*, void*);
360 static BOOL FILE_ReadConsole(HANDLE hCon, void* buf, DWORD nb, DWORD* nr, void* p)
362 static HANDLE hKernel /* = 0 */;
363 static pRW pReadConsole /* = 0 */;
365 if ((!hKernel && !(hKernel = LoadLibraryA("kernel32"))) ||
366 (!pReadConsole &&
367 !(pReadConsole = GetProcAddress(hKernel, "ReadConsoleA"))))
369 *nr = 0;
370 return 0;
372 return (pReadConsole)(hCon, buf, nb, nr, p);
375 static BOOL FILE_WriteConsole(HANDLE hCon, const void* buf, DWORD nb, DWORD* nr, void* p)
377 static HANDLE hKernel /* = 0 */;
378 static pRW pWriteConsole /* = 0 */;
380 if ((!hKernel && !(hKernel = LoadLibraryA("kernel32"))) ||
381 (!pWriteConsole &&
382 !(pWriteConsole = GetProcAddress(hKernel, "WriteConsoleA"))))
384 *nr = 0;
385 return 0;
387 return (pWriteConsole)(hCon, buf, nb, nr, p);
389 /* end of FIXME */
391 /***********************************************************************
392 * FILE_CreateFile
394 * Implementation of CreateFile. Takes a Unix path name.
395 * Returns 0 on failure.
397 HANDLE FILE_CreateFile( LPCSTR filename, DWORD access, DWORD sharing,
398 LPSECURITY_ATTRIBUTES sa, DWORD creation,
399 DWORD attributes, HANDLE template, BOOL fail_read_only,
400 UINT drive_type )
402 unsigned int err;
403 HANDLE ret;
405 for (;;)
407 SERVER_START_REQ( create_file )
409 req->access = access;
410 req->inherit = (sa && (sa->nLength>=sizeof(*sa)) && sa->bInheritHandle);
411 req->sharing = sharing;
412 req->create = creation;
413 req->attrs = attributes;
414 req->drive_type = drive_type;
415 wine_server_add_data( req, filename, strlen(filename) );
416 SetLastError(0);
417 err = wine_server_call( req );
418 ret = reply->handle;
420 SERVER_END_REQ;
422 /* If write access failed, retry without GENERIC_WRITE */
424 if (!ret && !fail_read_only && (access & GENERIC_WRITE))
426 if ((err == STATUS_MEDIA_WRITE_PROTECTED) || (err == STATUS_ACCESS_DENIED))
428 TRACE("Write access failed for file '%s', trying without "
429 "write access\n", filename);
430 access &= ~GENERIC_WRITE;
431 continue;
435 if (err)
437 /* In the case file creation was rejected due to CREATE_NEW flag
438 * was specified and file with that name already exists, correct
439 * last error is ERROR_FILE_EXISTS and not ERROR_ALREADY_EXISTS.
440 * Note: RtlNtStatusToDosError is not the subject to blame here.
442 if (err == STATUS_OBJECT_NAME_COLLISION)
443 SetLastError( ERROR_FILE_EXISTS );
444 else
445 SetLastError( RtlNtStatusToDosError(err) );
448 if (!ret) WARN("Unable to create file '%s' (GLE %ld)\n", filename, GetLastError());
449 return ret;
454 /***********************************************************************
455 * FILE_CreateDevice
457 * Same as FILE_CreateFile but for a device
458 * Returns 0 on failure.
460 HANDLE FILE_CreateDevice( int client_id, DWORD access, LPSECURITY_ATTRIBUTES sa )
462 HANDLE ret;
463 SERVER_START_REQ( create_device )
465 req->access = access;
466 req->inherit = (sa && (sa->nLength>=sizeof(*sa)) && sa->bInheritHandle);
467 req->id = client_id;
468 SetLastError(0);
469 wine_server_call_err( req );
470 ret = reply->handle;
472 SERVER_END_REQ;
473 return ret;
476 static HANDLE FILE_OpenPipe(LPCWSTR name, DWORD access, LPSECURITY_ATTRIBUTES sa )
478 HANDLE ret;
479 DWORD len = 0;
481 if (name && (len = strlenW(name)) > MAX_PATH)
483 SetLastError( ERROR_FILENAME_EXCED_RANGE );
484 return 0;
486 SERVER_START_REQ( open_named_pipe )
488 req->access = access;
489 req->inherit = (sa && (sa->nLength>=sizeof(*sa)) && sa->bInheritHandle);
490 SetLastError(0);
491 wine_server_add_data( req, name, len * sizeof(WCHAR) );
492 wine_server_call_err( req );
493 ret = reply->handle;
495 SERVER_END_REQ;
496 TRACE("Returned %p\n",ret);
497 return ret;
500 /*************************************************************************
501 * CreateFileW [KERNEL32.@] Creates or opens a file or other object
503 * Creates or opens an object, and returns a handle that can be used to
504 * access that object.
506 * PARAMS
508 * filename [in] pointer to filename to be accessed
509 * access [in] access mode requested
510 * sharing [in] share mode
511 * sa [in] pointer to security attributes
512 * creation [in] how to create the file
513 * attributes [in] attributes for newly created file
514 * template [in] handle to file with extended attributes to copy
516 * RETURNS
517 * Success: Open handle to specified file
518 * Failure: INVALID_HANDLE_VALUE
520 * NOTES
521 * Should call SetLastError() on failure.
523 * BUGS
525 * Doesn't support character devices, template files, or a
526 * lot of the 'attributes' flags yet.
528 HANDLE WINAPI CreateFileW( LPCWSTR filename, DWORD access, DWORD sharing,
529 LPSECURITY_ATTRIBUTES sa, DWORD creation,
530 DWORD attributes, HANDLE template )
532 DOS_FULL_NAME full_name;
533 HANDLE ret;
534 static const WCHAR bkslashes_with_question_markW[] = {'\\','\\','?','\\',0};
535 static const WCHAR bkslashes_with_dotW[] = {'\\','\\','.','\\',0};
536 static const WCHAR bkslashesW[] = {'\\','\\',0};
537 static const WCHAR coninW[] = {'C','O','N','I','N','$',0};
538 static const WCHAR conoutW[] = {'C','O','N','O','U','T','$',0};
540 if (!filename)
542 SetLastError( ERROR_INVALID_PARAMETER );
543 return INVALID_HANDLE_VALUE;
545 TRACE("%s %s%s%s%s%s%s%s attributes 0x%lx\n", debugstr_w(filename),
546 ((access & GENERIC_READ)==GENERIC_READ)?"GENERIC_READ ":"",
547 ((access & GENERIC_WRITE)==GENERIC_WRITE)?"GENERIC_WRITE ":"",
548 (!access)?"QUERY_ACCESS ":"",
549 ((sharing & FILE_SHARE_READ)==FILE_SHARE_READ)?"FILE_SHARE_READ ":"",
550 ((sharing & FILE_SHARE_WRITE)==FILE_SHARE_WRITE)?"FILE_SHARE_WRITE ":"",
551 ((sharing & FILE_SHARE_DELETE)==FILE_SHARE_DELETE)?"FILE_SHARE_DELETE ":"",
552 (creation ==CREATE_NEW)?"CREATE_NEW":
553 (creation ==CREATE_ALWAYS)?"CREATE_ALWAYS ":
554 (creation ==OPEN_EXISTING)?"OPEN_EXISTING ":
555 (creation ==OPEN_ALWAYS)?"OPEN_ALWAYS ":
556 (creation ==TRUNCATE_EXISTING)?"TRUNCATE_EXISTING ":"", attributes);
558 /* If the name starts with '\\?\', ignore the first 4 chars. */
559 if (!strncmpW(filename, bkslashes_with_question_markW, 4))
561 static const WCHAR uncW[] = {'U','N','C','\\',0};
562 filename += 4;
563 if (!strncmpiW(filename, uncW, 4))
565 FIXME("UNC name (%s) not supported.\n", debugstr_w(filename) );
566 SetLastError( ERROR_PATH_NOT_FOUND );
567 return INVALID_HANDLE_VALUE;
571 if (!strncmpW(filename, bkslashes_with_dotW, 4))
573 static const WCHAR pipeW[] = {'P','I','P','E','\\',0};
574 if(!strncmpiW(filename + 4, pipeW, 5))
576 TRACE("Opening a pipe: %s\n", debugstr_w(filename));
577 ret = FILE_OpenPipe( filename, access, sa );
578 goto done;
580 else if (isalphaW(filename[4]) && filename[5] == ':' && filename[6] == '\0')
582 ret = FILE_CreateDevice( (toupperW(filename[4]) - 'A') | 0x20000, access, sa );
583 goto done;
585 else if (!DOSFS_GetDevice( filename ))
587 ret = DEVICE_Open( filename+4, access, sa );
588 goto done;
590 else
591 filename+=4; /* fall into DOSFS_Device case below */
594 /* If the name still starts with '\\', it's a UNC name. */
595 if (!strncmpW(filename, bkslashesW, 2))
597 ret = SMB_CreateFileW(filename, access, sharing, sa, creation, attributes, template );
598 goto done;
601 /* If the name contains a DOS wild card (* or ?), do no create a file */
602 if(strchrW(filename, '*') || strchrW(filename, '?'))
604 SetLastError(ERROR_BAD_PATHNAME);
605 return INVALID_HANDLE_VALUE;
608 /* Open a console for CONIN$ or CONOUT$ */
609 if (!strcmpiW(filename, coninW) || !strcmpiW(filename, conoutW))
611 ret = OpenConsoleW(filename, access, sa, creation);
612 goto done;
615 if (DOSFS_GetDevice( filename ))
617 TRACE("opening device %s\n", debugstr_w(filename) );
619 if (!(ret = DOSFS_OpenDevice( filename, access, attributes, sa )))
621 /* Do not silence this please. It is a critical error. -MM */
622 ERR("Couldn't open device %s!\n", debugstr_w(filename));
623 SetLastError( ERROR_FILE_NOT_FOUND );
625 goto done;
628 /* check for filename, don't check for last entry if creating */
629 if (!DOSFS_GetFullName( filename,
630 (creation == OPEN_EXISTING) ||
631 (creation == TRUNCATE_EXISTING),
632 &full_name )) {
633 WARN("Unable to get full filename from %s (GLE %ld)\n",
634 debugstr_w(filename), GetLastError());
635 return INVALID_HANDLE_VALUE;
638 ret = FILE_CreateFile( full_name.long_name, access, sharing,
639 sa, creation, attributes, template,
640 DRIVE_GetFlags(full_name.drive) & DRIVE_FAIL_READ_ONLY,
641 GetDriveTypeW( full_name.short_name ) );
642 done:
643 if (!ret) ret = INVALID_HANDLE_VALUE;
644 TRACE("returning %p\n", ret);
645 return ret;
650 /*************************************************************************
651 * CreateFileA (KERNEL32.@)
653 HANDLE WINAPI CreateFileA( LPCSTR filename, DWORD access, DWORD sharing,
654 LPSECURITY_ATTRIBUTES sa, DWORD creation,
655 DWORD attributes, HANDLE template)
657 UNICODE_STRING filenameW;
658 HANDLE ret = INVALID_HANDLE_VALUE;
660 if (!filename)
662 SetLastError( ERROR_INVALID_PARAMETER );
663 return INVALID_HANDLE_VALUE;
666 if (RtlCreateUnicodeStringFromAsciiz(&filenameW, filename))
668 ret = CreateFileW(filenameW.Buffer, access, sharing, sa, creation,
669 attributes, template);
670 RtlFreeUnicodeString(&filenameW);
672 else
673 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
674 return ret;
678 /***********************************************************************
679 * FILE_FillInfo
681 * Fill a file information from a struct stat.
683 static void FILE_FillInfo( struct stat *st, BY_HANDLE_FILE_INFORMATION *info )
685 if (S_ISDIR(st->st_mode))
686 info->dwFileAttributes = FILE_ATTRIBUTE_DIRECTORY;
687 else
688 info->dwFileAttributes = FILE_ATTRIBUTE_ARCHIVE;
689 if (!(st->st_mode & S_IWUSR))
690 info->dwFileAttributes |= FILE_ATTRIBUTE_READONLY;
692 RtlSecondsSince1970ToTime( st->st_mtime, (LARGE_INTEGER *)&info->ftCreationTime );
693 RtlSecondsSince1970ToTime( st->st_mtime, (LARGE_INTEGER *)&info->ftLastWriteTime );
694 RtlSecondsSince1970ToTime( st->st_atime, (LARGE_INTEGER *)&info->ftLastAccessTime );
696 info->dwVolumeSerialNumber = 0; /* FIXME */
697 info->nFileSizeHigh = 0;
698 info->nFileSizeLow = 0;
699 if (!S_ISDIR(st->st_mode)) {
700 info->nFileSizeHigh = st->st_size >> 32;
701 info->nFileSizeLow = st->st_size & 0xffffffff;
703 info->nNumberOfLinks = st->st_nlink;
704 info->nFileIndexHigh = 0;
705 info->nFileIndexLow = st->st_ino;
709 /***********************************************************************
710 * FILE_Stat
712 * Stat a Unix path name. Return TRUE if OK.
714 BOOL FILE_Stat( LPCSTR unixName, BY_HANDLE_FILE_INFORMATION *info, BOOL *is_symlink_ptr )
716 struct stat st;
717 int is_symlink;
718 LPCSTR p;
720 if (lstat( unixName, &st ) == -1)
722 FILE_SetDosError();
723 return FALSE;
725 is_symlink = S_ISLNK(st.st_mode);
726 if (is_symlink)
728 /* do a "real" stat to find out
729 about the type of the symlink destination */
730 if (stat( unixName, &st ) == -1)
732 FILE_SetDosError();
733 return FALSE;
737 /* fill in the information we gathered so far */
738 FILE_FillInfo( &st, info );
740 /* and now see if this is a hidden file, based on the name */
741 p = strrchr( unixName, '/');
742 p = p ? p + 1 : unixName;
743 if (*p == '.' && *(p+1) && (*(p+1) != '.' || *(p+2)))
745 static const WCHAR wineW[] = {'w','i','n','e',0};
746 static const WCHAR ShowDotFilesW[] = {'S','h','o','w','D','o','t','F','i','l','e','s',0};
747 static int show_dot_files = -1;
748 if (show_dot_files == -1)
749 show_dot_files = PROFILE_GetWineIniBool(wineW, ShowDotFilesW, 0);
750 if (!show_dot_files)
751 info->dwFileAttributes |= FILE_ATTRIBUTE_HIDDEN;
753 if (is_symlink_ptr) *is_symlink_ptr = is_symlink;
754 return TRUE;
758 /***********************************************************************
759 * GetFileInformationByHandle (KERNEL32.@)
761 DWORD WINAPI GetFileInformationByHandle( HANDLE hFile,
762 BY_HANDLE_FILE_INFORMATION *info )
764 DWORD ret;
765 if (!info) return 0;
767 TRACE("%p\n", hFile);
769 SERVER_START_REQ( get_file_info )
771 req->handle = hFile;
772 if ((ret = !wine_server_call_err( req )))
774 /* FIXME: which file types are supported ?
775 * Serial ports (FILE_TYPE_CHAR) are not,
776 * and MSDN also says that pipes are not supported.
777 * FILE_TYPE_REMOTE seems to be supported according to
778 * MSDN q234741.txt */
779 if ((reply->type == FILE_TYPE_DISK) || (reply->type == FILE_TYPE_REMOTE))
781 RtlSecondsSince1970ToTime( reply->write_time, (LARGE_INTEGER *)&info->ftCreationTime );
782 RtlSecondsSince1970ToTime( reply->write_time, (LARGE_INTEGER *)&info->ftLastWriteTime );
783 RtlSecondsSince1970ToTime( reply->access_time, (LARGE_INTEGER *)&info->ftLastAccessTime );
784 info->dwFileAttributes = reply->attr;
785 info->dwVolumeSerialNumber = reply->serial;
786 info->nFileSizeHigh = reply->size_high;
787 info->nFileSizeLow = reply->size_low;
788 info->nNumberOfLinks = reply->links;
789 info->nFileIndexHigh = reply->index_high;
790 info->nFileIndexLow = reply->index_low;
792 else
794 SetLastError(ERROR_NOT_SUPPORTED);
795 ret = 0;
799 SERVER_END_REQ;
800 return ret;
804 /**************************************************************************
805 * GetFileAttributesW (KERNEL32.@)
807 DWORD WINAPI GetFileAttributesW( LPCWSTR name )
809 DOS_FULL_NAME full_name;
810 BY_HANDLE_FILE_INFORMATION info;
812 if (name == NULL)
814 SetLastError( ERROR_INVALID_PARAMETER );
815 return -1;
817 if (!DOSFS_GetFullName( name, TRUE, &full_name) )
818 return -1;
819 if (!FILE_Stat( full_name.long_name, &info, NULL )) return -1;
820 return info.dwFileAttributes;
824 /**************************************************************************
825 * GetFileAttributesA (KERNEL32.@)
827 DWORD WINAPI GetFileAttributesA( LPCSTR name )
829 UNICODE_STRING nameW;
830 DWORD ret = (DWORD)-1;
832 if (!name)
834 SetLastError( ERROR_INVALID_PARAMETER );
835 return (DWORD)-1;
838 if (RtlCreateUnicodeStringFromAsciiz(&nameW, name))
840 ret = GetFileAttributesW(nameW.Buffer);
841 RtlFreeUnicodeString(&nameW);
843 else
844 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
845 return ret;
849 /**************************************************************************
850 * SetFileAttributesW (KERNEL32.@)
852 BOOL WINAPI SetFileAttributesW(LPCWSTR lpFileName, DWORD attributes)
854 struct stat buf;
855 DOS_FULL_NAME full_name;
857 if (!lpFileName)
859 SetLastError( ERROR_INVALID_PARAMETER );
860 return FALSE;
863 TRACE("(%s,%lx)\n", debugstr_w(lpFileName), attributes);
865 if (!DOSFS_GetFullName( lpFileName, TRUE, &full_name ))
866 return FALSE;
868 if(stat(full_name.long_name,&buf)==-1)
870 FILE_SetDosError();
871 return FALSE;
873 if (attributes & FILE_ATTRIBUTE_READONLY)
875 if(S_ISDIR(buf.st_mode))
876 /* FIXME */
877 WARN("FILE_ATTRIBUTE_READONLY ignored for directory.\n");
878 else
879 buf.st_mode &= ~0222; /* octal!, clear write permission bits */
880 attributes &= ~FILE_ATTRIBUTE_READONLY;
882 else
884 /* add write permission */
885 buf.st_mode |= (0600 | ((buf.st_mode & 044) >> 1)) & (~FILE_umask);
887 if (attributes & FILE_ATTRIBUTE_DIRECTORY)
889 if (!S_ISDIR(buf.st_mode))
890 FIXME("SetFileAttributes expected the file %s to be a directory\n",
891 debugstr_w(lpFileName));
892 attributes &= ~FILE_ATTRIBUTE_DIRECTORY;
894 attributes &= ~(FILE_ATTRIBUTE_NORMAL|FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_HIDDEN|FILE_ATTRIBUTE_SYSTEM);
895 if (attributes)
896 FIXME("(%s):%lx attribute(s) not implemented.\n", debugstr_w(lpFileName), attributes);
897 if (-1==chmod(full_name.long_name,buf.st_mode))
899 if (GetDriveTypeW(lpFileName) == DRIVE_CDROM)
901 SetLastError( ERROR_ACCESS_DENIED );
902 return FALSE;
906 * FIXME: We don't return FALSE here because of differences between
907 * Linux and Windows privileges. Under Linux only the owner of
908 * the file is allowed to change file attributes. Under Windows,
909 * applications expect that if you can write to a file, you can also
910 * change its attributes (see GENERIC_WRITE). We could try to be
911 * clever here but that would break multi-user installations where
912 * users share read-only DLLs. This is because some installers like
913 * to change attributes of already installed DLLs.
915 FIXME("Couldn't set file attributes for existing file \"%s\".\n"
916 "Check permissions or set VFAT \"quiet\" mount flag\n", full_name.long_name);
918 return TRUE;
922 /**************************************************************************
923 * SetFileAttributesA (KERNEL32.@)
925 BOOL WINAPI SetFileAttributesA(LPCSTR lpFileName, DWORD attributes)
927 UNICODE_STRING filenameW;
928 BOOL ret = FALSE;
930 if (!lpFileName)
932 SetLastError( ERROR_INVALID_PARAMETER );
933 return FALSE;
936 if (RtlCreateUnicodeStringFromAsciiz(&filenameW, lpFileName))
938 ret = SetFileAttributesW(filenameW.Buffer, attributes);
939 RtlFreeUnicodeString(&filenameW);
941 else
942 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
943 return ret;
947 /***********************************************************************
948 * GetFileTime (KERNEL32.@)
950 BOOL WINAPI GetFileTime( HANDLE hFile, FILETIME *lpCreationTime,
951 FILETIME *lpLastAccessTime,
952 FILETIME *lpLastWriteTime )
954 BY_HANDLE_FILE_INFORMATION info;
955 if (!GetFileInformationByHandle( hFile, &info )) return FALSE;
956 if (lpCreationTime) *lpCreationTime = info.ftCreationTime;
957 if (lpLastAccessTime) *lpLastAccessTime = info.ftLastAccessTime;
958 if (lpLastWriteTime) *lpLastWriteTime = info.ftLastWriteTime;
959 return TRUE;
963 /***********************************************************************
964 * FILE_GetTempFileName : utility for GetTempFileName
966 static UINT FILE_GetTempFileName( LPCWSTR path, LPCWSTR prefix, UINT unique,
967 LPWSTR buffer )
969 static UINT unique_temp;
970 DOS_FULL_NAME full_name;
971 int i;
972 LPWSTR p;
973 UINT num;
974 char buf[20];
976 if ( !path || !prefix || !buffer )
978 SetLastError( ERROR_INVALID_PARAMETER );
979 return 0;
982 if (!unique_temp) unique_temp = time(NULL) & 0xffff;
983 num = unique ? (unique & 0xffff) : (unique_temp++ & 0xffff);
985 strcpyW( buffer, path );
986 p = buffer + strlenW(buffer);
988 /* add a \, if there isn't one and path is more than just the drive letter ... */
989 if ( !((strlenW(buffer) == 2) && (buffer[1] == ':'))
990 && ((p == buffer) || (p[-1] != '\\'))) *p++ = '\\';
992 for (i = 3; (i > 0) && (*prefix); i--) *p++ = *prefix++;
994 sprintf( buf, "%04x.tmp", num );
995 MultiByteToWideChar(CP_ACP, 0, buf, -1, p, 20);
997 /* Now try to create it */
999 if (!unique)
1003 HANDLE handle = CreateFileW( buffer, GENERIC_WRITE, 0, NULL,
1004 CREATE_NEW, FILE_ATTRIBUTE_NORMAL, 0 );
1005 if (handle != INVALID_HANDLE_VALUE)
1006 { /* We created it */
1007 TRACE("created %s\n", debugstr_w(buffer) );
1008 CloseHandle( handle );
1009 break;
1011 if (GetLastError() != ERROR_FILE_EXISTS &&
1012 GetLastError() != ERROR_SHARING_VIOLATION)
1013 break; /* No need to go on */
1014 num++;
1015 sprintf( buf, "%04x.tmp", num );
1016 MultiByteToWideChar(CP_ACP, 0, buf, -1, p, 20);
1017 } while (num != (unique & 0xffff));
1020 /* Get the full path name */
1022 if (DOSFS_GetFullName( buffer, FALSE, &full_name ))
1024 char *slash;
1025 /* Check if we have write access in the directory */
1026 if ((slash = strrchr( full_name.long_name, '/' ))) *slash = '\0';
1027 if (access( full_name.long_name, W_OK ) == -1)
1028 WARN("returns %s, which doesn't seem to be writeable.\n",
1029 debugstr_w(buffer) );
1031 TRACE("returning %s\n", debugstr_w(buffer) );
1032 return unique ? unique : num;
1036 /***********************************************************************
1037 * GetTempFileNameA (KERNEL32.@)
1039 UINT WINAPI GetTempFileNameA( LPCSTR path, LPCSTR prefix, UINT unique,
1040 LPSTR buffer)
1042 UNICODE_STRING pathW, prefixW;
1043 WCHAR bufferW[MAX_PATH];
1044 UINT ret;
1046 if ( !path || !prefix || !buffer )
1048 SetLastError( ERROR_INVALID_PARAMETER );
1049 return 0;
1052 RtlCreateUnicodeStringFromAsciiz(&pathW, path);
1053 RtlCreateUnicodeStringFromAsciiz(&prefixW, prefix);
1055 ret = GetTempFileNameW(pathW.Buffer, prefixW.Buffer, unique, bufferW);
1056 if (ret)
1057 WideCharToMultiByte(CP_ACP, 0, bufferW, -1, buffer, MAX_PATH, NULL, NULL);
1059 RtlFreeUnicodeString(&pathW);
1060 RtlFreeUnicodeString(&prefixW);
1061 return ret;
1064 /***********************************************************************
1065 * GetTempFileNameW (KERNEL32.@)
1067 UINT WINAPI GetTempFileNameW( LPCWSTR path, LPCWSTR prefix, UINT unique,
1068 LPWSTR buffer )
1070 return FILE_GetTempFileName( path, prefix, unique, buffer );
1074 /***********************************************************************
1075 * FILE_DoOpenFile
1077 * Implementation of OpenFile16() and OpenFile32().
1079 static HFILE FILE_DoOpenFile( LPCSTR name, OFSTRUCT *ofs, UINT mode, BOOL win32 )
1081 HFILE hFileRet;
1082 HANDLE handle;
1083 FILETIME filetime;
1084 WORD filedatetime[2];
1085 DOS_FULL_NAME full_name;
1086 DWORD access, sharing;
1087 WCHAR *p;
1088 WCHAR buffer[MAX_PATH];
1089 LPWSTR nameW;
1091 if (!ofs) return HFILE_ERROR;
1093 TRACE("%s %s %s %s%s%s%s%s%s%s%s%s\n",name,
1094 ((mode & 0x3 )==OF_READ)?"OF_READ":
1095 ((mode & 0x3 )==OF_WRITE)?"OF_WRITE":
1096 ((mode & 0x3 )==OF_READWRITE)?"OF_READWRITE":"unknown",
1097 ((mode & 0x70 )==OF_SHARE_COMPAT)?"OF_SHARE_COMPAT":
1098 ((mode & 0x70 )==OF_SHARE_DENY_NONE)?"OF_SHARE_DENY_NONE":
1099 ((mode & 0x70 )==OF_SHARE_DENY_READ)?"OF_SHARE_DENY_READ":
1100 ((mode & 0x70 )==OF_SHARE_DENY_WRITE)?"OF_SHARE_DENY_WRITE":
1101 ((mode & 0x70 )==OF_SHARE_EXCLUSIVE)?"OF_SHARE_EXCLUSIVE":"unknown",
1102 ((mode & OF_PARSE )==OF_PARSE)?"OF_PARSE ":"",
1103 ((mode & OF_DELETE )==OF_DELETE)?"OF_DELETE ":"",
1104 ((mode & OF_VERIFY )==OF_VERIFY)?"OF_VERIFY ":"",
1105 ((mode & OF_SEARCH )==OF_SEARCH)?"OF_SEARCH ":"",
1106 ((mode & OF_CANCEL )==OF_CANCEL)?"OF_CANCEL ":"",
1107 ((mode & OF_CREATE )==OF_CREATE)?"OF_CREATE ":"",
1108 ((mode & OF_PROMPT )==OF_PROMPT)?"OF_PROMPT ":"",
1109 ((mode & OF_EXIST )==OF_EXIST)?"OF_EXIST ":"",
1110 ((mode & OF_REOPEN )==OF_REOPEN)?"OF_REOPEN ":""
1114 ofs->cBytes = sizeof(OFSTRUCT);
1115 ofs->nErrCode = 0;
1116 if (mode & OF_REOPEN) name = ofs->szPathName;
1118 if (!name) {
1119 ERR("called with `name' set to NULL ! Please debug.\n");
1120 return HFILE_ERROR;
1123 TRACE("%s %04x\n", name, mode );
1125 /* the watcom 10.6 IDE relies on a valid path returned in ofs->szPathName
1126 Are there any cases where getting the path here is wrong?
1127 Uwe Bonnes 1997 Apr 2 */
1128 if (!GetFullPathNameA( name, sizeof(ofs->szPathName),
1129 ofs->szPathName, NULL )) goto error;
1130 FILE_ConvertOFMode( mode, &access, &sharing );
1132 /* OF_PARSE simply fills the structure */
1134 if (mode & OF_PARSE)
1136 ofs->fFixedDisk = (GetDriveType16( ofs->szPathName[0]-'A' )
1137 != DRIVE_REMOVABLE);
1138 TRACE("(%s): OF_PARSE, res = '%s'\n",
1139 name, ofs->szPathName );
1140 return 0;
1143 /* OF_CREATE is completely different from all other options, so
1144 handle it first */
1146 if (mode & OF_CREATE)
1148 if ((handle = CreateFileA( name, GENERIC_READ | GENERIC_WRITE,
1149 sharing, NULL, CREATE_ALWAYS,
1150 FILE_ATTRIBUTE_NORMAL, 0 ))== INVALID_HANDLE_VALUE)
1151 goto error;
1152 goto success;
1155 MultiByteToWideChar(CP_ACP, 0, name, -1, buffer, MAX_PATH);
1156 nameW = buffer;
1158 /* If OF_SEARCH is set, ignore the given path */
1160 if ((mode & OF_SEARCH) && !(mode & OF_REOPEN))
1162 /* First try the file name as is */
1163 if (DOSFS_GetFullName( nameW, TRUE, &full_name )) goto found;
1164 /* Now remove the path */
1165 if (nameW[0] && (nameW[1] == ':')) nameW += 2;
1166 if ((p = strrchrW( nameW, '\\' ))) nameW = p + 1;
1167 if ((p = strrchrW( nameW, '/' ))) nameW = p + 1;
1168 if (!nameW[0]) goto not_found;
1171 /* Now look for the file */
1173 if (!DIR_SearchPath( NULL, nameW, NULL, &full_name, win32 )) goto not_found;
1175 found:
1176 TRACE("found %s = %s\n",
1177 full_name.long_name, debugstr_w(full_name.short_name) );
1178 WideCharToMultiByte(CP_ACP, 0, full_name.short_name, -1,
1179 ofs->szPathName, sizeof(ofs->szPathName), NULL, NULL);
1181 if (mode & OF_SHARE_EXCLUSIVE)
1182 /* Some InstallShield version uses OF_SHARE_EXCLUSIVE
1183 on the file <tempdir>/_ins0432._mp to determine how
1184 far installation has proceeded.
1185 _ins0432._mp is an executable and while running the
1186 application expects the open with OF_SHARE_ to fail*/
1187 /* Probable FIXME:
1188 As our loader closes the files after loading the executable,
1189 we can't find the running executable with FILE_InUse.
1190 The loader should keep the file open, as Windows does that, too.
1193 char *last = strrchr(full_name.long_name,'/');
1194 if (!last)
1195 last = full_name.long_name - 1;
1196 if (GetModuleHandle16(last+1))
1198 TRACE("Denying shared open for %s\n",full_name.long_name);
1199 return HFILE_ERROR;
1203 if (mode & OF_DELETE)
1205 if (unlink( full_name.long_name ) == -1) goto not_found;
1206 TRACE("(%s): OF_DELETE return = OK\n", name);
1207 return 1;
1210 handle = FILE_CreateFile( full_name.long_name, access, sharing,
1211 NULL, OPEN_EXISTING, 0, 0,
1212 DRIVE_GetFlags(full_name.drive) & DRIVE_FAIL_READ_ONLY,
1213 GetDriveTypeW( full_name.short_name ) );
1214 if (!handle) goto not_found;
1216 GetFileTime( handle, NULL, NULL, &filetime );
1217 FileTimeToDosDateTime( &filetime, &filedatetime[0], &filedatetime[1] );
1218 if ((mode & OF_VERIFY) && (mode & OF_REOPEN))
1220 if (ofs->Reserved1 != filedatetime[0] || ofs->Reserved2 != filedatetime[1] )
1222 CloseHandle( handle );
1223 WARN("(%s): OF_VERIFY failed\n", name );
1224 /* FIXME: what error here? */
1225 SetLastError( ERROR_FILE_NOT_FOUND );
1226 goto error;
1229 ofs->Reserved1 = filedatetime[0];
1230 ofs->Reserved2 = filedatetime[1];
1232 success: /* We get here if the open was successful */
1233 TRACE("(%s): OK, return = %p\n", name, handle );
1234 if (win32)
1236 hFileRet = (HFILE)handle;
1237 if (mode & OF_EXIST) /* Return the handle, but close it first */
1238 CloseHandle( handle );
1240 else
1242 hFileRet = Win32HandleToDosFileHandle( handle );
1243 if (hFileRet == HFILE_ERROR16) goto error;
1244 if (mode & OF_EXIST) /* Return the handle, but close it first */
1245 _lclose16( hFileRet );
1247 return hFileRet;
1249 not_found: /* We get here if the file does not exist */
1250 WARN("'%s' not found or sharing violation\n", name );
1251 SetLastError( ERROR_FILE_NOT_FOUND );
1252 /* fall through */
1254 error: /* We get here if there was an error opening the file */
1255 ofs->nErrCode = GetLastError();
1256 WARN("(%s): return = HFILE_ERROR error= %d\n",
1257 name,ofs->nErrCode );
1258 return HFILE_ERROR;
1262 /***********************************************************************
1263 * OpenFile (KERNEL.74)
1264 * OpenFileEx (KERNEL.360)
1266 HFILE16 WINAPI OpenFile16( LPCSTR name, OFSTRUCT *ofs, UINT16 mode )
1268 return FILE_DoOpenFile( name, ofs, mode, FALSE );
1272 /***********************************************************************
1273 * OpenFile (KERNEL32.@)
1275 HFILE WINAPI OpenFile( LPCSTR name, OFSTRUCT *ofs, UINT mode )
1277 return FILE_DoOpenFile( name, ofs, mode, TRUE );
1281 /***********************************************************************
1282 * FILE_InitProcessDosHandles
1284 * Allocates the default DOS handles for a process. Called either by
1285 * Win32HandleToDosFileHandle below or by the DOSVM stuff.
1287 static void FILE_InitProcessDosHandles( void )
1289 HANDLE cp = GetCurrentProcess();
1290 DuplicateHandle(cp, GetStdHandle(STD_INPUT_HANDLE), cp, &dos_handles[0],
1291 0, TRUE, DUPLICATE_SAME_ACCESS);
1292 DuplicateHandle(cp, GetStdHandle(STD_OUTPUT_HANDLE), cp, &dos_handles[1],
1293 0, TRUE, DUPLICATE_SAME_ACCESS);
1294 DuplicateHandle(cp, GetStdHandle(STD_ERROR_HANDLE), cp, &dos_handles[2],
1295 0, TRUE, DUPLICATE_SAME_ACCESS);
1296 DuplicateHandle(cp, GetStdHandle(STD_ERROR_HANDLE), cp, &dos_handles[3],
1297 0, TRUE, DUPLICATE_SAME_ACCESS);
1298 DuplicateHandle(cp, GetStdHandle(STD_ERROR_HANDLE), cp, &dos_handles[4],
1299 0, TRUE, DUPLICATE_SAME_ACCESS);
1302 /***********************************************************************
1303 * Win32HandleToDosFileHandle (KERNEL32.21)
1305 * Allocate a DOS handle for a Win32 handle. The Win32 handle is no
1306 * longer valid after this function (even on failure).
1308 * Note: this is not exactly right, since on Win95 the Win32 handles
1309 * are on top of DOS handles and we do it the other way
1310 * around. Should be good enough though.
1312 HFILE WINAPI Win32HandleToDosFileHandle( HANDLE handle )
1314 int i;
1316 if (!handle || (handle == INVALID_HANDLE_VALUE))
1317 return HFILE_ERROR;
1319 for (i = 5; i < DOS_TABLE_SIZE; i++)
1320 if (!dos_handles[i])
1322 dos_handles[i] = handle;
1323 TRACE("Got %d for h32 %p\n", i, handle );
1324 return (HFILE)i;
1326 CloseHandle( handle );
1327 SetLastError( ERROR_TOO_MANY_OPEN_FILES );
1328 return HFILE_ERROR;
1332 /***********************************************************************
1333 * DosFileHandleToWin32Handle (KERNEL32.20)
1335 * Return the Win32 handle for a DOS handle.
1337 * Note: this is not exactly right, since on Win95 the Win32 handles
1338 * are on top of DOS handles and we do it the other way
1339 * around. Should be good enough though.
1341 HANDLE WINAPI DosFileHandleToWin32Handle( HFILE handle )
1343 HFILE16 hfile = (HFILE16)handle;
1344 if (hfile < 5 && !dos_handles[hfile]) FILE_InitProcessDosHandles();
1345 if ((hfile >= DOS_TABLE_SIZE) || !dos_handles[hfile])
1347 SetLastError( ERROR_INVALID_HANDLE );
1348 return INVALID_HANDLE_VALUE;
1350 return dos_handles[hfile];
1354 /***********************************************************************
1355 * DisposeLZ32Handle (KERNEL32.22)
1357 * Note: this is not entirely correct, we should only close the
1358 * 32-bit handle and not the 16-bit one, but we cannot do
1359 * this because of the way our DOS handles are implemented.
1360 * It shouldn't break anything though.
1362 void WINAPI DisposeLZ32Handle( HANDLE handle )
1364 int i;
1366 if (!handle || (handle == INVALID_HANDLE_VALUE)) return;
1368 for (i = 5; i < DOS_TABLE_SIZE; i++)
1369 if (dos_handles[i] == handle)
1371 dos_handles[i] = 0;
1372 CloseHandle( handle );
1373 break;
1378 /***********************************************************************
1379 * FILE_Dup2
1381 * dup2() function for DOS handles.
1383 HFILE16 FILE_Dup2( HFILE16 hFile1, HFILE16 hFile2 )
1385 HANDLE new_handle;
1387 if (hFile1 < 5 && !dos_handles[hFile1]) FILE_InitProcessDosHandles();
1389 if ((hFile1 >= DOS_TABLE_SIZE) || (hFile2 >= DOS_TABLE_SIZE) || !dos_handles[hFile1])
1391 SetLastError( ERROR_INVALID_HANDLE );
1392 return HFILE_ERROR16;
1394 if (!DuplicateHandle( GetCurrentProcess(), dos_handles[hFile1],
1395 GetCurrentProcess(), &new_handle,
1396 0, FALSE, DUPLICATE_SAME_ACCESS ))
1397 return HFILE_ERROR16;
1398 if (dos_handles[hFile2]) CloseHandle( dos_handles[hFile2] );
1399 dos_handles[hFile2] = new_handle;
1400 return hFile2;
1404 /***********************************************************************
1405 * _lclose (KERNEL.81)
1407 HFILE16 WINAPI _lclose16( HFILE16 hFile )
1409 if ((hFile >= DOS_TABLE_SIZE) || !dos_handles[hFile])
1411 SetLastError( ERROR_INVALID_HANDLE );
1412 return HFILE_ERROR16;
1414 TRACE("%d (handle32=%p)\n", hFile, dos_handles[hFile] );
1415 CloseHandle( dos_handles[hFile] );
1416 dos_handles[hFile] = 0;
1417 return 0;
1421 /******************************************************************
1422 * FILE_ReadWriteApc (internal)
1426 static void WINAPI FILE_ReadWriteApc(void* apc_user, PIO_STATUS_BLOCK io_status, ULONG len)
1428 LPOVERLAPPED_COMPLETION_ROUTINE cr = (LPOVERLAPPED_COMPLETION_ROUTINE)apc_user;
1430 cr(RtlNtStatusToDosError(io_status->u.Status), len, (LPOVERLAPPED)io_status);
1433 /***********************************************************************
1434 * ReadFileEx (KERNEL32.@)
1436 BOOL WINAPI ReadFileEx(HANDLE hFile, LPVOID buffer, DWORD bytesToRead,
1437 LPOVERLAPPED overlapped,
1438 LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine)
1440 LARGE_INTEGER offset;
1441 NTSTATUS status;
1442 PIO_STATUS_BLOCK io_status;
1444 if (!overlapped)
1446 SetLastError(ERROR_INVALID_PARAMETER);
1447 return FALSE;
1450 offset.s.LowPart = overlapped->Offset;
1451 offset.s.HighPart = overlapped->OffsetHigh;
1452 io_status = (PIO_STATUS_BLOCK)overlapped;
1453 io_status->u.Status = STATUS_PENDING;
1455 status = NtReadFile(hFile, NULL, FILE_ReadWriteApc, lpCompletionRoutine,
1456 io_status, buffer, bytesToRead, &offset, NULL);
1458 if (status)
1460 SetLastError( RtlNtStatusToDosError(status) );
1461 return FALSE;
1463 return TRUE;
1466 /***********************************************************************
1467 * ReadFile (KERNEL32.@)
1469 BOOL WINAPI ReadFile( HANDLE hFile, LPVOID buffer, DWORD bytesToRead,
1470 LPDWORD bytesRead, LPOVERLAPPED overlapped )
1472 LARGE_INTEGER offset;
1473 PLARGE_INTEGER poffset = NULL;
1474 IO_STATUS_BLOCK iosb;
1475 PIO_STATUS_BLOCK io_status = &iosb;
1476 HANDLE hEvent = 0;
1477 NTSTATUS status;
1479 TRACE("%p %p %ld %p %p\n", hFile, buffer, bytesToRead,
1480 bytesRead, overlapped );
1482 if (bytesRead) *bytesRead = 0; /* Do this before anything else */
1483 if (!bytesToRead) return TRUE;
1485 if (IsBadReadPtr(buffer, bytesToRead))
1487 SetLastError(ERROR_WRITE_FAULT); /* FIXME */
1488 return FALSE;
1490 if (is_console_handle(hFile))
1491 return FILE_ReadConsole(hFile, buffer, bytesToRead, bytesRead, NULL);
1493 if (overlapped != NULL)
1495 offset.s.LowPart = overlapped->Offset;
1496 offset.s.HighPart = overlapped->OffsetHigh;
1497 poffset = &offset;
1498 hEvent = overlapped->hEvent;
1499 io_status = (PIO_STATUS_BLOCK)overlapped;
1501 io_status->u.Status = STATUS_PENDING;
1502 io_status->Information = 0;
1504 status = NtReadFile(hFile, hEvent, NULL, NULL, io_status, buffer, bytesToRead, poffset, NULL);
1506 if (status != STATUS_PENDING && bytesRead)
1507 *bytesRead = io_status->Information;
1509 if (status && status != STATUS_END_OF_FILE)
1511 SetLastError( RtlNtStatusToDosError(status) );
1512 return FALSE;
1514 return TRUE;
1518 /***********************************************************************
1519 * WriteFileEx (KERNEL32.@)
1521 BOOL WINAPI WriteFileEx(HANDLE hFile, LPCVOID buffer, DWORD bytesToWrite,
1522 LPOVERLAPPED overlapped,
1523 LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine)
1525 LARGE_INTEGER offset;
1526 NTSTATUS status;
1527 PIO_STATUS_BLOCK io_status;
1529 TRACE("%p %p %ld %p %p\n",
1530 hFile, buffer, bytesToWrite, overlapped, lpCompletionRoutine);
1532 if (overlapped == NULL)
1534 SetLastError(ERROR_INVALID_PARAMETER);
1535 return FALSE;
1537 offset.s.LowPart = overlapped->Offset;
1538 offset.s.HighPart = overlapped->OffsetHigh;
1540 io_status = (PIO_STATUS_BLOCK)overlapped;
1541 io_status->u.Status = STATUS_PENDING;
1543 status = NtWriteFile(hFile, NULL, FILE_ReadWriteApc, lpCompletionRoutine,
1544 io_status, buffer, bytesToWrite, &offset, NULL);
1546 if (status) SetLastError( RtlNtStatusToDosError(status) );
1547 return !status;
1550 /***********************************************************************
1551 * WriteFile (KERNEL32.@)
1553 BOOL WINAPI WriteFile( HANDLE hFile, LPCVOID buffer, DWORD bytesToWrite,
1554 LPDWORD bytesWritten, LPOVERLAPPED overlapped )
1556 HANDLE hEvent = NULL;
1557 LARGE_INTEGER offset;
1558 PLARGE_INTEGER poffset = NULL;
1559 NTSTATUS status;
1560 IO_STATUS_BLOCK iosb;
1561 PIO_STATUS_BLOCK piosb = &iosb;
1563 TRACE("%p %p %ld %p %p\n",
1564 hFile, buffer, bytesToWrite, bytesWritten, overlapped );
1566 if (is_console_handle(hFile))
1567 return FILE_WriteConsole(hFile, buffer, bytesToWrite, bytesWritten, NULL);
1569 if (IsBadReadPtr(buffer, bytesToWrite))
1571 SetLastError(ERROR_READ_FAULT); /* FIXME */
1572 return FALSE;
1575 if (overlapped)
1577 offset.s.LowPart = overlapped->Offset;
1578 offset.s.HighPart = overlapped->OffsetHigh;
1579 poffset = &offset;
1580 hEvent = overlapped->hEvent;
1581 piosb = (PIO_STATUS_BLOCK)overlapped;
1583 piosb->u.Status = STATUS_PENDING;
1584 piosb->Information = 0;
1586 status = NtWriteFile(hFile, hEvent, NULL, NULL, piosb,
1587 buffer, bytesToWrite, poffset, NULL);
1588 if (status)
1590 SetLastError( RtlNtStatusToDosError(status) );
1591 return FALSE;
1593 if (bytesWritten) *bytesWritten = piosb->Information;
1595 return TRUE;
1599 /***********************************************************************
1600 * SetFilePointer (KERNEL32.@)
1602 DWORD WINAPI SetFilePointer( HANDLE hFile, LONG distance, LONG *highword,
1603 DWORD method )
1605 DWORD ret = INVALID_SET_FILE_POINTER;
1607 TRACE("handle %p offset %ld high %ld origin %ld\n",
1608 hFile, distance, highword?*highword:0, method );
1610 SERVER_START_REQ( set_file_pointer )
1612 req->handle = hFile;
1613 req->low = distance;
1614 req->high = highword ? *highword : (distance >= 0) ? 0 : -1;
1615 /* FIXME: assumes 1:1 mapping between Windows and Unix seek constants */
1616 req->whence = method;
1617 SetLastError( 0 );
1618 if (!wine_server_call_err( req ))
1620 ret = reply->new_low;
1621 if (highword) *highword = reply->new_high;
1624 SERVER_END_REQ;
1625 return ret;
1629 /*************************************************************************
1630 * SetHandleCount (KERNEL32.@)
1632 UINT WINAPI SetHandleCount( UINT count )
1634 return min( 256, count );
1638 /**************************************************************************
1639 * SetEndOfFile (KERNEL32.@)
1641 BOOL WINAPI SetEndOfFile( HANDLE hFile )
1643 BOOL ret;
1644 SERVER_START_REQ( truncate_file )
1646 req->handle = hFile;
1647 ret = !wine_server_call_err( req );
1649 SERVER_END_REQ;
1650 return ret;
1654 /***********************************************************************
1655 * DeleteFileW (KERNEL32.@)
1657 BOOL WINAPI DeleteFileW( LPCWSTR path )
1659 DOS_FULL_NAME full_name;
1660 HANDLE hFile;
1662 TRACE("%s\n", debugstr_w(path) );
1663 if (!path || !*path)
1665 SetLastError(ERROR_PATH_NOT_FOUND);
1666 return FALSE;
1668 if (DOSFS_GetDevice( path ))
1670 WARN("cannot remove DOS device %s!\n", debugstr_w(path));
1671 SetLastError( ERROR_FILE_NOT_FOUND );
1672 return FALSE;
1675 if (!DOSFS_GetFullName( path, TRUE, &full_name )) return FALSE;
1677 /* check if we are allowed to delete the source */
1678 hFile = FILE_CreateFile( full_name.long_name, GENERIC_READ|GENERIC_WRITE, 0,
1679 NULL, OPEN_EXISTING, 0, 0, TRUE,
1680 GetDriveTypeW( full_name.short_name ) );
1681 if (!hFile) return FALSE;
1683 if (unlink( full_name.long_name ) == -1)
1685 FILE_SetDosError();
1686 CloseHandle(hFile);
1687 return FALSE;
1689 CloseHandle(hFile);
1690 return TRUE;
1694 /***********************************************************************
1695 * DeleteFileA (KERNEL32.@)
1697 BOOL WINAPI DeleteFileA( LPCSTR path )
1699 UNICODE_STRING pathW;
1700 BOOL ret = FALSE;
1702 if (!path)
1704 SetLastError(ERROR_INVALID_PARAMETER);
1705 return FALSE;
1708 if (RtlCreateUnicodeStringFromAsciiz(&pathW, path))
1710 ret = DeleteFileW(pathW.Buffer);
1711 RtlFreeUnicodeString(&pathW);
1713 else
1714 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1715 return ret;
1719 /***********************************************************************
1720 * GetFileType (KERNEL32.@)
1722 DWORD WINAPI GetFileType( HANDLE hFile )
1724 DWORD ret = FILE_TYPE_UNKNOWN;
1726 if (is_console_handle( hFile ))
1727 return FILE_TYPE_CHAR;
1729 SERVER_START_REQ( get_file_info )
1731 req->handle = hFile;
1732 if (!wine_server_call_err( req )) ret = reply->type;
1734 SERVER_END_REQ;
1735 return ret;
1739 /* check if a file name is for an executable file (.exe or .com) */
1740 inline static BOOL is_executable( const char *name )
1742 int len = strlen(name);
1744 if (len < 4) return FALSE;
1745 return (!strcasecmp( name + len - 4, ".exe" ) ||
1746 !strcasecmp( name + len - 4, ".com" ));
1750 /***********************************************************************
1751 * FILE_AddBootRenameEntry
1753 * Adds an entry to the registry that is loaded when windows boots and
1754 * checks if there are some files to be removed or renamed/moved.
1755 * <fn1> has to be valid and <fn2> may be NULL. If both pointers are
1756 * non-NULL then the file is moved, otherwise it is deleted. The
1757 * entry of the registrykey is always appended with two zero
1758 * terminated strings. If <fn2> is NULL then the second entry is
1759 * simply a single 0-byte. Otherwise the second filename goes
1760 * there. The entries are prepended with \??\ before the path and the
1761 * second filename gets also a '!' as the first character if
1762 * MOVEFILE_REPLACE_EXISTING is set. After the final string another
1763 * 0-byte follows to indicate the end of the strings.
1764 * i.e.:
1765 * \??\D:\test\file1[0]
1766 * !\??\D:\test\file1_renamed[0]
1767 * \??\D:\Test|delete[0]
1768 * [0] <- file is to be deleted, second string empty
1769 * \??\D:\test\file2[0]
1770 * !\??\D:\test\file2_renamed[0]
1771 * [0] <- indicates end of strings
1773 * or:
1774 * \??\D:\test\file1[0]
1775 * !\??\D:\test\file1_renamed[0]
1776 * \??\D:\Test|delete[0]
1777 * [0] <- file is to be deleted, second string empty
1778 * [0] <- indicates end of strings
1781 static BOOL FILE_AddBootRenameEntry( LPCWSTR fn1, LPCWSTR fn2, DWORD flags )
1783 static const WCHAR PreString[] = {'\\','?','?','\\',0};
1784 static const WCHAR ValueName[] = {'P','e','n','d','i','n','g',
1785 'F','i','l','e','R','e','n','a','m','e',
1786 'O','p','e','r','a','t','i','o','n','s',0};
1787 static const WCHAR SessionW[] = {'M','a','c','h','i','n','e','\\',
1788 'S','y','s','t','e','m','\\',
1789 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
1790 'C','o','n','t','r','o','l','\\',
1791 'S','e','s','s','i','o','n',' ','M','a','n','a','g','e','r',0};
1792 static const int info_size = FIELD_OFFSET( KEY_VALUE_PARTIAL_INFORMATION, Data );
1794 OBJECT_ATTRIBUTES attr;
1795 UNICODE_STRING nameW;
1796 KEY_VALUE_PARTIAL_INFORMATION *info;
1797 BOOL rc = FALSE;
1798 HKEY Reboot = 0;
1799 DWORD len0, len1, len2;
1800 DWORD DataSize = 0;
1801 BYTE *Buffer = NULL;
1802 WCHAR *p;
1804 attr.Length = sizeof(attr);
1805 attr.RootDirectory = 0;
1806 attr.ObjectName = &nameW;
1807 attr.Attributes = 0;
1808 attr.SecurityDescriptor = NULL;
1809 attr.SecurityQualityOfService = NULL;
1810 RtlInitUnicodeString( &nameW, SessionW );
1812 if (NtCreateKey( &Reboot, KEY_ALL_ACCESS, &attr, 0, NULL, 0, NULL ) != STATUS_SUCCESS)
1814 WARN("Error creating key for reboot managment [%s]\n",
1815 "SYSTEM\\CurrentControlSet\\Control\\Session Manager");
1816 return FALSE;
1819 len0 = strlenW(PreString);
1820 len1 = strlenW(fn1) + len0 + 1;
1821 if (fn2)
1823 len2 = strlenW(fn2) + len0 + 1;
1824 if (flags & MOVEFILE_REPLACE_EXISTING) len2++; /* Plus 1 because of the leading '!' */
1826 else len2 = 1; /* minimum is the 0 characters for the empty second string */
1828 /* convert characters to bytes */
1829 len0 *= sizeof(WCHAR);
1830 len1 *= sizeof(WCHAR);
1831 len2 *= sizeof(WCHAR);
1833 RtlInitUnicodeString( &nameW, ValueName );
1835 /* First we check if the key exists and if so how many bytes it already contains. */
1836 if (NtQueryValueKey( Reboot, &nameW, KeyValuePartialInformation,
1837 NULL, 0, &DataSize ) == STATUS_BUFFER_OVERFLOW)
1839 if (!(Buffer = HeapAlloc( GetProcessHeap(), 0, DataSize + len1 + len2 + sizeof(WCHAR) )))
1840 goto Quit;
1841 if (NtQueryValueKey( Reboot, &nameW, KeyValuePartialInformation,
1842 Buffer, DataSize, &DataSize )) goto Quit;
1843 info = (KEY_VALUE_PARTIAL_INFORMATION *)Buffer;
1844 if (info->Type != REG_MULTI_SZ) goto Quit;
1845 if (DataSize > sizeof(info)) DataSize -= sizeof(WCHAR); /* remove terminating null (will be added back later) */
1847 else
1849 DataSize = info_size;
1850 if (!(Buffer = HeapAlloc( GetProcessHeap(), 0, DataSize + len1 + len2 + sizeof(WCHAR) )))
1851 goto Quit;
1854 p = (WCHAR *)(Buffer + DataSize);
1855 strcpyW( p, PreString );
1856 strcatW( p, fn1 );
1857 DataSize += len1;
1858 if (fn2)
1860 p = (WCHAR *)(Buffer + DataSize);
1861 if (flags & MOVEFILE_REPLACE_EXISTING)
1862 *p++ = '!';
1863 strcpyW( p, PreString );
1864 strcatW( p, fn2 );
1865 DataSize += len2;
1867 else
1869 p = (WCHAR *)(Buffer + DataSize);
1870 *p = 0;
1871 DataSize += sizeof(WCHAR);
1874 /* add final null */
1875 p = (WCHAR *)(Buffer + DataSize);
1876 *p = 0;
1877 DataSize += sizeof(WCHAR);
1879 rc = !NtSetValueKey(Reboot, &nameW, 0, REG_MULTI_SZ, Buffer + info_size, DataSize - info_size);
1881 Quit:
1882 if (Reboot) NtClose(Reboot);
1883 if (Buffer) HeapFree( GetProcessHeap(), 0, Buffer );
1884 return(rc);
1888 /**************************************************************************
1889 * MoveFileExW (KERNEL32.@)
1891 BOOL WINAPI MoveFileExW( LPCWSTR fn1, LPCWSTR fn2, DWORD flag )
1893 DOS_FULL_NAME full_name1, full_name2;
1894 HANDLE hFile;
1895 DWORD attr = INVALID_FILE_ATTRIBUTES;
1897 TRACE("(%s,%s,%04lx)\n", debugstr_w(fn1), debugstr_w(fn2), flag);
1899 /* FIXME: <Gerhard W. Gruber>sparhawk@gmx.at
1900 In case of W9x and lesser this function should return 120 (ERROR_CALL_NOT_IMPLEMENTED)
1901 to be really compatible. Most programs wont have any problems though. In case
1902 you encounter one, this is what you should return here. I don't know what's up
1903 with NT 3.5. Is this function available there or not?
1904 Does anybody really care about 3.5? :)
1907 /* Filename1 has to be always set to a valid path. Filename2 may be NULL
1908 if the source file has to be deleted.
1910 if (!fn1) {
1911 SetLastError(ERROR_INVALID_PARAMETER);
1912 return FALSE;
1915 /* This function has to be run through in order to process the name properly.
1916 If the BOOTDELAY flag is set, the file doesn't need to exist though. At least
1917 that is the behaviour on NT 4.0. The operation accepts the filenames as
1918 they are given but it can't reply with a reasonable returncode. Success
1919 means in that case success for entering the values into the registry.
1921 if(!DOSFS_GetFullName( fn1, TRUE, &full_name1 ))
1923 if(!(flag & MOVEFILE_DELAY_UNTIL_REBOOT))
1924 return FALSE;
1927 if (fn2) /* !fn2 means delete fn1 */
1929 if (DOSFS_GetFullName( fn2, TRUE, &full_name2 ))
1931 if(!(flag & MOVEFILE_DELAY_UNTIL_REBOOT))
1933 /* target exists, check if we may overwrite */
1934 if (!(flag & MOVEFILE_REPLACE_EXISTING))
1936 SetLastError( ERROR_FILE_EXISTS );
1937 return FALSE;
1941 else
1943 if (!DOSFS_GetFullName( fn2, FALSE, &full_name2 ))
1945 if(!(flag & MOVEFILE_DELAY_UNTIL_REBOOT))
1946 return FALSE;
1950 /* Source name and target path are valid */
1952 if (flag & MOVEFILE_DELAY_UNTIL_REBOOT)
1954 return FILE_AddBootRenameEntry( fn1, fn2, flag );
1957 attr = GetFileAttributesW( fn1 );
1958 if ( attr == INVALID_FILE_ATTRIBUTES ) return FALSE;
1960 /* check if we are allowed to rename the source */
1961 hFile = FILE_CreateFile( full_name1.long_name, 0, 0,
1962 NULL, OPEN_EXISTING, 0, 0, TRUE,
1963 GetDriveTypeW( full_name1.short_name ) );
1964 if (!hFile)
1966 if (GetLastError() != ERROR_ACCESS_DENIED) return FALSE;
1967 if ( !(attr & FILE_ATTRIBUTE_DIRECTORY) ) return FALSE;
1968 /* if it's a directory we can continue */
1970 else CloseHandle(hFile);
1972 /* check, if we are allowed to delete the destination,
1973 ** (but the file not being there is fine) */
1974 hFile = FILE_CreateFile( full_name2.long_name, GENERIC_READ|GENERIC_WRITE, 0,
1975 NULL, OPEN_EXISTING, 0, 0, TRUE,
1976 GetDriveTypeW( full_name2.short_name ) );
1977 if(!hFile && GetLastError() != ERROR_FILE_NOT_FOUND) return FALSE;
1978 CloseHandle(hFile);
1980 if (full_name1.drive != full_name2.drive)
1982 if (!(flag & MOVEFILE_COPY_ALLOWED))
1984 SetLastError( ERROR_NOT_SAME_DEVICE );
1985 return FALSE;
1987 else if ( attr & FILE_ATTRIBUTE_DIRECTORY )
1989 /* Strange, but that's what Windows returns */
1990 SetLastError ( ERROR_ACCESS_DENIED );
1991 return FALSE;
1994 if (rename( full_name1.long_name, full_name2.long_name ) == -1)
1995 /* Try copy/delete unless it's a directory. */
1996 /* FIXME: This does not handle the (unlikely) case that the two locations
1997 are on the same Wine drive, but on different Unix file systems. */
1999 if ( attr & FILE_ATTRIBUTE_DIRECTORY )
2001 FILE_SetDosError();
2002 return FALSE;
2004 else
2006 if ( ! CopyFileW( fn1, fn2, !(flag & MOVEFILE_REPLACE_EXISTING) ))
2007 return FALSE;
2008 if ( ! DeleteFileW ( fn1 ) )
2009 return FALSE;
2012 if (is_executable( full_name1.long_name ) != is_executable( full_name2.long_name ))
2014 struct stat fstat;
2015 if (stat( full_name2.long_name, &fstat ) != -1)
2017 if (is_executable( full_name2.long_name ))
2018 /* set executable bit where read bit is set */
2019 fstat.st_mode |= (fstat.st_mode & 0444) >> 2;
2020 else
2021 fstat.st_mode &= ~0111;
2022 chmod( full_name2.long_name, fstat.st_mode );
2025 return TRUE;
2027 else /* fn2 == NULL means delete source */
2029 if (flag & MOVEFILE_DELAY_UNTIL_REBOOT)
2031 if (flag & MOVEFILE_COPY_ALLOWED) {
2032 WARN("Illegal flag\n");
2033 SetLastError( ERROR_GEN_FAILURE );
2034 return FALSE;
2037 return FILE_AddBootRenameEntry( fn1, NULL, flag );
2040 if (unlink( full_name1.long_name ) == -1)
2042 FILE_SetDosError();
2043 return FALSE;
2045 return TRUE; /* successfully deleted */
2049 /**************************************************************************
2050 * MoveFileExA (KERNEL32.@)
2052 BOOL WINAPI MoveFileExA( LPCSTR fn1, LPCSTR fn2, DWORD flag )
2054 UNICODE_STRING fn1W, fn2W;
2055 BOOL ret;
2057 if (!fn1)
2059 SetLastError(ERROR_INVALID_PARAMETER);
2060 return FALSE;
2063 RtlCreateUnicodeStringFromAsciiz(&fn1W, fn1);
2064 if (fn2) RtlCreateUnicodeStringFromAsciiz(&fn2W, fn2);
2065 else fn2W.Buffer = NULL;
2067 ret = MoveFileExW( fn1W.Buffer, fn2W.Buffer, flag );
2069 RtlFreeUnicodeString(&fn1W);
2070 RtlFreeUnicodeString(&fn2W);
2071 return ret;
2075 /**************************************************************************
2076 * MoveFileW (KERNEL32.@)
2078 * Move file or directory
2080 BOOL WINAPI MoveFileW( LPCWSTR fn1, LPCWSTR fn2 )
2082 return MoveFileExW( fn1, fn2, MOVEFILE_COPY_ALLOWED );
2086 /**************************************************************************
2087 * MoveFileA (KERNEL32.@)
2089 BOOL WINAPI MoveFileA( LPCSTR fn1, LPCSTR fn2 )
2091 return MoveFileExA( fn1, fn2, MOVEFILE_COPY_ALLOWED );
2095 /**************************************************************************
2096 * CopyFileW (KERNEL32.@)
2098 BOOL WINAPI CopyFileW( LPCWSTR source, LPCWSTR dest, BOOL fail_if_exists )
2100 HANDLE h1, h2;
2101 BY_HANDLE_FILE_INFORMATION info;
2102 DWORD count;
2103 BOOL ret = FALSE;
2104 char buffer[2048];
2106 if (!source || !dest)
2108 SetLastError(ERROR_INVALID_PARAMETER);
2109 return FALSE;
2112 TRACE("%s -> %s\n", debugstr_w(source), debugstr_w(dest));
2114 if ((h1 = CreateFileW(source, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE,
2115 NULL, OPEN_EXISTING, 0, 0)) == INVALID_HANDLE_VALUE)
2117 WARN("Unable to open source %s\n", debugstr_w(source));
2118 return FALSE;
2121 if (!GetFileInformationByHandle( h1, &info ))
2123 WARN("GetFileInformationByHandle returned error for %s\n", debugstr_w(source));
2124 CloseHandle( h1 );
2125 return FALSE;
2128 if ((h2 = CreateFileW( dest, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
2129 fail_if_exists ? CREATE_NEW : CREATE_ALWAYS,
2130 info.dwFileAttributes, h1 )) == INVALID_HANDLE_VALUE)
2132 WARN("Unable to open dest %s\n", debugstr_w(dest));
2133 CloseHandle( h1 );
2134 return FALSE;
2137 while (ReadFile( h1, buffer, sizeof(buffer), &count, NULL ) && count)
2139 char *p = buffer;
2140 while (count != 0)
2142 DWORD res;
2143 if (!WriteFile( h2, p, count, &res, NULL ) || !res) goto done;
2144 p += res;
2145 count -= res;
2148 ret = TRUE;
2149 done:
2150 CloseHandle( h1 );
2151 CloseHandle( h2 );
2152 return ret;
2156 /**************************************************************************
2157 * CopyFileA (KERNEL32.@)
2159 BOOL WINAPI CopyFileA( LPCSTR source, LPCSTR dest, BOOL fail_if_exists)
2161 UNICODE_STRING sourceW, destW;
2162 BOOL ret;
2164 if (!source || !dest)
2166 SetLastError(ERROR_INVALID_PARAMETER);
2167 return FALSE;
2170 RtlCreateUnicodeStringFromAsciiz(&sourceW, source);
2171 RtlCreateUnicodeStringFromAsciiz(&destW, dest);
2173 ret = CopyFileW(sourceW.Buffer, destW.Buffer, fail_if_exists);
2175 RtlFreeUnicodeString(&sourceW);
2176 RtlFreeUnicodeString(&destW);
2177 return ret;
2181 /**************************************************************************
2182 * CopyFileExW (KERNEL32.@)
2184 * This implementation ignores most of the extra parameters passed-in into
2185 * the "ex" version of the method and calls the CopyFile method.
2186 * It will have to be fixed eventually.
2188 BOOL WINAPI CopyFileExW(LPCWSTR sourceFilename, LPCWSTR destFilename,
2189 LPPROGRESS_ROUTINE progressRoutine, LPVOID appData,
2190 LPBOOL cancelFlagPointer, DWORD copyFlags)
2193 * Interpret the only flag that CopyFile can interpret.
2195 return CopyFileW(sourceFilename, destFilename, (copyFlags & COPY_FILE_FAIL_IF_EXISTS) != 0);
2199 /**************************************************************************
2200 * CopyFileExA (KERNEL32.@)
2202 BOOL WINAPI CopyFileExA(LPCSTR sourceFilename, LPCSTR destFilename,
2203 LPPROGRESS_ROUTINE progressRoutine, LPVOID appData,
2204 LPBOOL cancelFlagPointer, DWORD copyFlags)
2206 UNICODE_STRING sourceW, destW;
2207 BOOL ret;
2209 if (!sourceFilename || !destFilename)
2211 SetLastError(ERROR_INVALID_PARAMETER);
2212 return FALSE;
2215 RtlCreateUnicodeStringFromAsciiz(&sourceW, sourceFilename);
2216 RtlCreateUnicodeStringFromAsciiz(&destW, destFilename);
2218 ret = CopyFileExW(sourceW.Buffer, destW.Buffer, progressRoutine, appData,
2219 cancelFlagPointer, copyFlags);
2221 RtlFreeUnicodeString(&sourceW);
2222 RtlFreeUnicodeString(&destW);
2223 return ret;
2227 /***********************************************************************
2228 * SetFileTime (KERNEL32.@)
2230 BOOL WINAPI SetFileTime( HANDLE hFile,
2231 const FILETIME *lpCreationTime,
2232 const FILETIME *lpLastAccessTime,
2233 const FILETIME *lpLastWriteTime )
2235 BOOL ret;
2236 SERVER_START_REQ( set_file_time )
2238 req->handle = hFile;
2239 if (lpLastAccessTime)
2240 RtlTimeToSecondsSince1970( (PLARGE_INTEGER) lpLastAccessTime, (DWORD *)&req->access_time );
2241 else
2242 req->access_time = 0; /* FIXME */
2243 if (lpLastWriteTime)
2244 RtlTimeToSecondsSince1970( (PLARGE_INTEGER) lpLastWriteTime, (DWORD *)&req->write_time );
2245 else
2246 req->write_time = 0; /* FIXME */
2247 ret = !wine_server_call_err( req );
2249 SERVER_END_REQ;
2250 return ret;
2254 /**************************************************************************
2255 * GetFileAttributesExW (KERNEL32.@)
2257 BOOL WINAPI GetFileAttributesExW(
2258 LPCWSTR lpFileName, GET_FILEEX_INFO_LEVELS fInfoLevelId,
2259 LPVOID lpFileInformation)
2261 DOS_FULL_NAME full_name;
2262 BY_HANDLE_FILE_INFORMATION info;
2264 if (!lpFileName || !lpFileInformation)
2266 SetLastError(ERROR_INVALID_PARAMETER);
2267 return FALSE;
2270 if (fInfoLevelId == GetFileExInfoStandard) {
2271 LPWIN32_FILE_ATTRIBUTE_DATA lpFad =
2272 (LPWIN32_FILE_ATTRIBUTE_DATA) lpFileInformation;
2273 if (!DOSFS_GetFullName( lpFileName, TRUE, &full_name )) return FALSE;
2274 if (!FILE_Stat( full_name.long_name, &info, NULL )) return FALSE;
2276 lpFad->dwFileAttributes = info.dwFileAttributes;
2277 lpFad->ftCreationTime = info.ftCreationTime;
2278 lpFad->ftLastAccessTime = info.ftLastAccessTime;
2279 lpFad->ftLastWriteTime = info.ftLastWriteTime;
2280 lpFad->nFileSizeHigh = info.nFileSizeHigh;
2281 lpFad->nFileSizeLow = info.nFileSizeLow;
2283 else {
2284 FIXME("invalid info level %d!\n", fInfoLevelId);
2285 return FALSE;
2288 return TRUE;
2292 /**************************************************************************
2293 * GetFileAttributesExA (KERNEL32.@)
2295 BOOL WINAPI GetFileAttributesExA(
2296 LPCSTR filename, GET_FILEEX_INFO_LEVELS fInfoLevelId,
2297 LPVOID lpFileInformation)
2299 UNICODE_STRING filenameW;
2300 BOOL ret = FALSE;
2302 if (!filename || !lpFileInformation)
2304 SetLastError(ERROR_INVALID_PARAMETER);
2305 return FALSE;
2308 if (RtlCreateUnicodeStringFromAsciiz(&filenameW, filename))
2310 ret = GetFileAttributesExW(filenameW.Buffer, fInfoLevelId, lpFileInformation);
2311 RtlFreeUnicodeString(&filenameW);
2313 else
2314 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
2315 return ret;