Fixed some issues found by winapi_check.
[wine.git] / files / file.c
blobc10885711bad3268e1ed1665f95a5c5d29a86ca7
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 #include <sys/time.h>
45 #include <sys/poll.h>
46 #include <time.h>
47 #include <unistd.h>
48 #include <utime.h>
50 #include "winerror.h"
51 #include "windef.h"
52 #include "winbase.h"
53 #include "wine/winbase16.h"
54 #include "drive.h"
55 #include "file.h"
56 #include "heap.h"
57 #include "msdos.h"
58 #include "wincon.h"
59 #include "wine/debug.h"
61 #include "wine/server.h"
63 WINE_DEFAULT_DEBUG_CHANNEL(file);
65 #if defined(MAP_ANONYMOUS) && !defined(MAP_ANON)
66 #define MAP_ANON MAP_ANONYMOUS
67 #endif
69 /* Size of per-process table of DOS handles */
70 #define DOS_TABLE_SIZE 256
72 /* Macro to derive file offset from OVERLAPPED struct */
73 #define OVERLAPPED_OFFSET(overlapped) ((off_t) (overlapped)->Offset + ((off_t) (overlapped)->OffsetHigh << 32))
75 static HANDLE dos_handles[DOS_TABLE_SIZE];
78 /***********************************************************************
79 * FILE_ConvertOFMode
81 * Convert OF_* mode into flags for CreateFile.
83 static void FILE_ConvertOFMode( INT mode, DWORD *access, DWORD *sharing )
85 switch(mode & 0x03)
87 case OF_READ: *access = GENERIC_READ; break;
88 case OF_WRITE: *access = GENERIC_WRITE; break;
89 case OF_READWRITE: *access = GENERIC_READ | GENERIC_WRITE; break;
90 default: *access = 0; break;
92 switch(mode & 0x70)
94 case OF_SHARE_EXCLUSIVE: *sharing = 0; break;
95 case OF_SHARE_DENY_WRITE: *sharing = FILE_SHARE_READ; break;
96 case OF_SHARE_DENY_READ: *sharing = FILE_SHARE_WRITE; break;
97 case OF_SHARE_DENY_NONE:
98 case OF_SHARE_COMPAT:
99 default: *sharing = FILE_SHARE_READ | FILE_SHARE_WRITE; break;
104 /***********************************************************************
105 * FILE_strcasecmp
107 * locale-independent case conversion for file I/O
109 int FILE_strcasecmp( const char *str1, const char *str2 )
111 for (;;)
113 int ret = FILE_toupper(*str1) - FILE_toupper(*str2);
114 if (ret || !*str1) return ret;
115 str1++;
116 str2++;
121 /***********************************************************************
122 * FILE_strncasecmp
124 * locale-independent case conversion for file I/O
126 int FILE_strncasecmp( const char *str1, const char *str2, int len )
128 int ret = 0;
129 for ( ; len > 0; len--, str1++, str2++)
130 if ((ret = FILE_toupper(*str1) - FILE_toupper(*str2)) || !*str1) break;
131 return ret;
135 /***********************************************************************
136 * FILE_SetDosError
138 * Set the DOS error code from errno.
140 void FILE_SetDosError(void)
142 int save_errno = errno; /* errno gets overwritten by printf */
144 TRACE("errno = %d %s\n", errno, strerror(errno));
145 switch (save_errno)
147 case EAGAIN:
148 SetLastError( ERROR_SHARING_VIOLATION );
149 break;
150 case EBADF:
151 SetLastError( ERROR_INVALID_HANDLE );
152 break;
153 case ENOSPC:
154 SetLastError( ERROR_HANDLE_DISK_FULL );
155 break;
156 case EACCES:
157 case EPERM:
158 case EROFS:
159 SetLastError( ERROR_ACCESS_DENIED );
160 break;
161 case EBUSY:
162 SetLastError( ERROR_LOCK_VIOLATION );
163 break;
164 case ENOENT:
165 SetLastError( ERROR_FILE_NOT_FOUND );
166 break;
167 case EISDIR:
168 SetLastError( ERROR_CANNOT_MAKE );
169 break;
170 case ENFILE:
171 case EMFILE:
172 SetLastError( ERROR_NO_MORE_FILES );
173 break;
174 case EEXIST:
175 SetLastError( ERROR_FILE_EXISTS );
176 break;
177 case EINVAL:
178 case ESPIPE:
179 SetLastError( ERROR_SEEK );
180 break;
181 case ENOTEMPTY:
182 SetLastError( ERROR_DIR_NOT_EMPTY );
183 break;
184 case ENOEXEC:
185 SetLastError( ERROR_BAD_FORMAT );
186 break;
187 default:
188 WARN("unknown file error: %s\n", strerror(save_errno) );
189 SetLastError( ERROR_GEN_FAILURE );
190 break;
192 errno = save_errno;
196 /***********************************************************************
197 * FILE_DupUnixHandle
199 * Duplicate a Unix handle into a task handle.
200 * Returns 0 on failure.
202 HANDLE FILE_DupUnixHandle( int fd, DWORD access, BOOL inherit )
204 HANDLE ret;
206 wine_server_send_fd( fd );
208 SERVER_START_REQ( alloc_file_handle )
210 req->access = access;
211 req->inherit = inherit;
212 req->fd = fd;
213 wine_server_call( req );
214 ret = reply->handle;
216 SERVER_END_REQ;
217 return ret;
221 /***********************************************************************
222 * FILE_GetUnixHandleType
224 * Retrieve the Unix handle corresponding to a file handle.
225 * Returns -1 on failure.
227 static int FILE_GetUnixHandleType( HANDLE handle, DWORD access, enum fd_type *type, DWORD *flags )
229 int ret, fd = -1;
233 SERVER_START_REQ( get_handle_fd )
235 req->handle = handle;
236 req->access = access;
237 if (!(ret = wine_server_call_err( req )))
239 fd = reply->fd;
241 if (type) *type = reply->type;
242 if (flags) *flags = reply->flags;
244 SERVER_END_REQ;
245 if (ret) return -1;
247 if (fd == -1) /* it wasn't in the cache, get it from the server */
248 fd = wine_server_recv_fd( handle );
250 } while (fd == -2); /* -2 means race condition, so restart from scratch */
252 if (fd != -1)
254 if ((fd = dup(fd)) == -1)
255 SetLastError( ERROR_TOO_MANY_OPEN_FILES );
257 return fd;
260 /***********************************************************************
261 * FILE_GetUnixHandle
263 * Retrieve the Unix handle corresponding to a file handle.
264 * Returns -1 on failure.
266 int FILE_GetUnixHandle( HANDLE handle, DWORD access )
268 return FILE_GetUnixHandleType( handle, access, NULL, NULL );
271 /*************************************************************************
272 * FILE_OpenConsole
274 * Open a handle to the current process console.
275 * Returns 0 on failure.
277 static HANDLE FILE_OpenConsole( BOOL output, DWORD access, DWORD sharing, LPSECURITY_ATTRIBUTES sa )
279 HANDLE ret;
281 SERVER_START_REQ( open_console )
283 req->from = output;
284 req->access = access;
285 req->share = sharing;
286 req->inherit = (sa && (sa->nLength>=sizeof(*sa)) && sa->bInheritHandle);
287 SetLastError(0);
288 wine_server_call_err( req );
289 ret = reply->handle;
291 SERVER_END_REQ;
292 return ret;
296 /***********************************************************************
297 * FILE_CreateFile
299 * Implementation of CreateFile. Takes a Unix path name.
300 * Returns 0 on failure.
302 HANDLE FILE_CreateFile( LPCSTR filename, DWORD access, DWORD sharing,
303 LPSECURITY_ATTRIBUTES sa, DWORD creation,
304 DWORD attributes, HANDLE template, BOOL fail_read_only,
305 UINT drive_type )
307 unsigned int err;
308 HANDLE ret;
310 for (;;)
312 SERVER_START_REQ( create_file )
314 req->access = access;
315 req->inherit = (sa && (sa->nLength>=sizeof(*sa)) && sa->bInheritHandle);
316 req->sharing = sharing;
317 req->create = creation;
318 req->attrs = attributes;
319 req->drive_type = drive_type;
320 wine_server_add_data( req, filename, strlen(filename) );
321 SetLastError(0);
322 err = wine_server_call( req );
323 ret = reply->handle;
325 SERVER_END_REQ;
327 /* If write access failed, retry without GENERIC_WRITE */
329 if (!ret && !fail_read_only && (access & GENERIC_WRITE))
331 if ((err == STATUS_MEDIA_WRITE_PROTECTED) || (err == STATUS_ACCESS_DENIED))
333 TRACE("Write access failed for file '%s', trying without "
334 "write access\n", filename);
335 access &= ~GENERIC_WRITE;
336 continue;
340 if (err) SetLastError( RtlNtStatusToDosError(err) );
342 if (!ret) WARN("Unable to create file '%s' (GLE %ld)\n", filename, GetLastError());
343 return ret;
348 /***********************************************************************
349 * FILE_CreateDevice
351 * Same as FILE_CreateFile but for a device
352 * Returns 0 on failure.
354 HANDLE FILE_CreateDevice( int client_id, DWORD access, LPSECURITY_ATTRIBUTES sa )
356 HANDLE ret;
357 SERVER_START_REQ( create_device )
359 req->access = access;
360 req->inherit = (sa && (sa->nLength>=sizeof(*sa)) && sa->bInheritHandle);
361 req->id = client_id;
362 SetLastError(0);
363 wine_server_call_err( req );
364 ret = reply->handle;
366 SERVER_END_REQ;
367 return ret;
370 static HANDLE FILE_OpenPipe(LPCSTR name, DWORD access)
372 WCHAR buffer[MAX_PATH];
373 HANDLE ret;
374 DWORD len = 0;
376 if (name && !(len = MultiByteToWideChar( CP_ACP, 0, name, strlen(name), buffer, MAX_PATH )))
378 SetLastError( ERROR_FILENAME_EXCED_RANGE );
379 return 0;
381 SERVER_START_REQ( open_named_pipe )
383 req->access = access;
384 SetLastError(0);
385 wine_server_add_data( req, buffer, len * sizeof(WCHAR) );
386 wine_server_call_err( req );
387 ret = reply->handle;
389 SERVER_END_REQ;
390 TRACE("Returned %d\n",ret);
391 return ret;
394 /*************************************************************************
395 * CreateFileA [KERNEL32.@] Creates or opens a file or other object
397 * Creates or opens an object, and returns a handle that can be used to
398 * access that object.
400 * PARAMS
402 * filename [in] pointer to filename to be accessed
403 * access [in] access mode requested
404 * sharing [in] share mode
405 * sa [in] pointer to security attributes
406 * creation [in] how to create the file
407 * attributes [in] attributes for newly created file
408 * template [in] handle to file with extended attributes to copy
410 * RETURNS
411 * Success: Open handle to specified file
412 * Failure: INVALID_HANDLE_VALUE
414 * NOTES
415 * Should call SetLastError() on failure.
417 * BUGS
419 * Doesn't support character devices, template files, or a
420 * lot of the 'attributes' flags yet.
422 HANDLE WINAPI CreateFileA( LPCSTR filename, DWORD access, DWORD sharing,
423 LPSECURITY_ATTRIBUTES sa, DWORD creation,
424 DWORD attributes, HANDLE template )
426 DOS_FULL_NAME full_name;
427 HANDLE ret;
429 if (!filename)
431 SetLastError( ERROR_INVALID_PARAMETER );
432 return INVALID_HANDLE_VALUE;
434 TRACE("%s %s%s%s%s%s%s%s\n",filename,
435 ((access & GENERIC_READ)==GENERIC_READ)?"GENERIC_READ ":"",
436 ((access & GENERIC_WRITE)==GENERIC_WRITE)?"GENERIC_WRITE ":"",
437 (!access)?"QUERY_ACCESS ":"",
438 ((sharing & FILE_SHARE_READ)==FILE_SHARE_READ)?"FILE_SHARE_READ ":"",
439 ((sharing & FILE_SHARE_WRITE)==FILE_SHARE_WRITE)?"FILE_SHARE_WRITE ":"",
440 ((sharing & FILE_SHARE_DELETE)==FILE_SHARE_DELETE)?"FILE_SHARE_DELETE ":"",
441 (creation ==CREATE_NEW)?"CREATE_NEW":
442 (creation ==CREATE_ALWAYS)?"CREATE_ALWAYS ":
443 (creation ==OPEN_EXISTING)?"OPEN_EXISTING ":
444 (creation ==OPEN_ALWAYS)?"OPEN_ALWAYS ":
445 (creation ==TRUNCATE_EXISTING)?"TRUNCATE_EXISTING ":"");
447 /* If the name starts with '\\?\', ignore the first 4 chars. */
448 if (!strncmp(filename, "\\\\?\\", 4))
450 filename += 4;
451 if (!strncmp(filename, "UNC\\", 4))
453 FIXME("UNC name (%s) not supported.\n", filename );
454 SetLastError( ERROR_PATH_NOT_FOUND );
455 return INVALID_HANDLE_VALUE;
459 if (!strncmp(filename, "\\\\.\\", 4)) {
460 if(!strncasecmp(&filename[4],"pipe\\",5))
462 TRACE("Opening a pipe: %s\n",filename);
463 ret = FILE_OpenPipe(filename,access);
464 goto done;
466 else if (isalpha(filename[4]) && filename[5] == ':' && filename[6] == '\0')
468 ret = FILE_CreateDevice( (toupper(filename[4]) - 'A') | 0x20000, access, sa );
469 goto done;
471 else if (!DOSFS_GetDevice( filename ))
473 ret = DEVICE_Open( filename+4, access, sa );
474 goto done;
476 else
477 filename+=4; /* fall into DOSFS_Device case below */
480 /* If the name still starts with '\\', it's a UNC name. */
481 if (!strncmp(filename, "\\\\", 2))
483 FIXME("UNC name (%s) not supported.\n", filename );
484 SetLastError( ERROR_PATH_NOT_FOUND );
485 return INVALID_HANDLE_VALUE;
488 /* If the name contains a DOS wild card (* or ?), do no create a file */
489 if(strchr(filename,'*') || strchr(filename,'?'))
490 return INVALID_HANDLE_VALUE;
492 /* Open a console for CONIN$ or CONOUT$ */
493 if (!strcasecmp(filename, "CONIN$"))
495 ret = FILE_OpenConsole( FALSE, access, sharing, sa );
496 goto done;
498 if (!strcasecmp(filename, "CONOUT$"))
500 ret = FILE_OpenConsole( TRUE, access, sharing, sa );
501 goto done;
504 if (DOSFS_GetDevice( filename ))
506 TRACE("opening device '%s'\n", filename );
508 if (!(ret = DOSFS_OpenDevice( filename, access, attributes, sa )))
510 /* Do not silence this please. It is a critical error. -MM */
511 ERR("Couldn't open device '%s'!\n",filename);
512 SetLastError( ERROR_FILE_NOT_FOUND );
514 goto done;
517 /* check for filename, don't check for last entry if creating */
518 if (!DOSFS_GetFullName( filename,
519 (creation == OPEN_EXISTING) ||
520 (creation == TRUNCATE_EXISTING),
521 &full_name )) {
522 WARN("Unable to get full filename from '%s' (GLE %ld)\n",
523 filename, GetLastError());
524 return INVALID_HANDLE_VALUE;
527 ret = FILE_CreateFile( full_name.long_name, access, sharing,
528 sa, creation, attributes, template,
529 DRIVE_GetFlags(full_name.drive) & DRIVE_FAIL_READ_ONLY,
530 GetDriveTypeA( full_name.short_name ) );
531 done:
532 if (!ret) ret = INVALID_HANDLE_VALUE;
533 return ret;
538 /*************************************************************************
539 * CreateFileW (KERNEL32.@)
541 HANDLE WINAPI CreateFileW( LPCWSTR filename, DWORD access, DWORD sharing,
542 LPSECURITY_ATTRIBUTES sa, DWORD creation,
543 DWORD attributes, HANDLE template)
545 LPSTR afn = HEAP_strdupWtoA( GetProcessHeap(), 0, filename );
546 HANDLE res = CreateFileA( afn, access, sharing, sa, creation, attributes, template );
547 HeapFree( GetProcessHeap(), 0, afn );
548 return res;
552 /***********************************************************************
553 * FILE_FillInfo
555 * Fill a file information from a struct stat.
557 static void FILE_FillInfo( struct stat *st, BY_HANDLE_FILE_INFORMATION *info )
559 if (S_ISDIR(st->st_mode))
560 info->dwFileAttributes = FILE_ATTRIBUTE_DIRECTORY;
561 else
562 info->dwFileAttributes = FILE_ATTRIBUTE_ARCHIVE;
563 if (!(st->st_mode & S_IWUSR))
564 info->dwFileAttributes |= FILE_ATTRIBUTE_READONLY;
566 RtlSecondsSince1970ToTime( st->st_mtime, &info->ftCreationTime );
567 RtlSecondsSince1970ToTime( st->st_mtime, &info->ftLastWriteTime );
568 RtlSecondsSince1970ToTime( st->st_atime, &info->ftLastAccessTime );
570 info->dwVolumeSerialNumber = 0; /* FIXME */
571 info->nFileSizeHigh = 0;
572 info->nFileSizeLow = 0;
573 if (!S_ISDIR(st->st_mode)) {
574 info->nFileSizeHigh = st->st_size >> 32;
575 info->nFileSizeLow = st->st_size & 0xffffffff;
577 info->nNumberOfLinks = st->st_nlink;
578 info->nFileIndexHigh = 0;
579 info->nFileIndexLow = st->st_ino;
583 /***********************************************************************
584 * FILE_Stat
586 * Stat a Unix path name. Return TRUE if OK.
588 BOOL FILE_Stat( LPCSTR unixName, BY_HANDLE_FILE_INFORMATION *info )
590 struct stat st;
592 if (lstat( unixName, &st ) == -1)
594 FILE_SetDosError();
595 return FALSE;
597 if (!S_ISLNK(st.st_mode)) FILE_FillInfo( &st, info );
598 else
600 /* do a "real" stat to find out
601 about the type of the symlink destination */
602 if (stat( unixName, &st ) == -1)
604 FILE_SetDosError();
605 return FALSE;
607 FILE_FillInfo( &st, info );
608 info->dwFileAttributes |= FILE_ATTRIBUTE_SYMLINK;
610 return TRUE;
614 /***********************************************************************
615 * GetFileInformationByHandle (KERNEL32.@)
617 DWORD WINAPI GetFileInformationByHandle( HANDLE hFile,
618 BY_HANDLE_FILE_INFORMATION *info )
620 DWORD ret;
621 if (!info) return 0;
623 SERVER_START_REQ( get_file_info )
625 req->handle = hFile;
626 if ((ret = !wine_server_call_err( req )))
628 /* FIXME: which file types are supported ?
629 * Serial ports (FILE_TYPE_CHAR) are not,
630 * and MSDN also says that pipes are not supported.
631 * FILE_TYPE_REMOTE seems to be supported according to
632 * MSDN q234741.txt */
633 if ((reply->type == FILE_TYPE_DISK) || (reply->type == FILE_TYPE_REMOTE))
635 RtlSecondsSince1970ToTime( reply->write_time, &info->ftCreationTime );
636 RtlSecondsSince1970ToTime( reply->write_time, &info->ftLastWriteTime );
637 RtlSecondsSince1970ToTime( reply->access_time, &info->ftLastAccessTime );
638 info->dwFileAttributes = reply->attr;
639 info->dwVolumeSerialNumber = reply->serial;
640 info->nFileSizeHigh = reply->size_high;
641 info->nFileSizeLow = reply->size_low;
642 info->nNumberOfLinks = reply->links;
643 info->nFileIndexHigh = reply->index_high;
644 info->nFileIndexLow = reply->index_low;
646 else
648 SetLastError(ERROR_NOT_SUPPORTED);
649 ret = 0;
653 SERVER_END_REQ;
654 return ret;
658 /**************************************************************************
659 * GetFileAttributes (KERNEL.420)
661 DWORD WINAPI GetFileAttributes16( LPCSTR name )
663 return GetFileAttributesA( name );
667 /**************************************************************************
668 * GetFileAttributesA (KERNEL32.@)
670 DWORD WINAPI GetFileAttributesA( LPCSTR name )
672 DOS_FULL_NAME full_name;
673 BY_HANDLE_FILE_INFORMATION info;
675 if (name == NULL)
677 SetLastError( ERROR_INVALID_PARAMETER );
678 return -1;
680 if (!DOSFS_GetFullName( name, TRUE, &full_name) )
681 return -1;
682 if (!FILE_Stat( full_name.long_name, &info )) return -1;
683 return info.dwFileAttributes;
687 /**************************************************************************
688 * GetFileAttributesW (KERNEL32.@)
690 DWORD WINAPI GetFileAttributesW( LPCWSTR name )
692 LPSTR nameA = HEAP_strdupWtoA( GetProcessHeap(), 0, name );
693 DWORD res = GetFileAttributesA( nameA );
694 HeapFree( GetProcessHeap(), 0, nameA );
695 return res;
699 /***********************************************************************
700 * GetFileSize (KERNEL32.@)
702 DWORD WINAPI GetFileSize( HANDLE hFile, LPDWORD filesizehigh )
704 BY_HANDLE_FILE_INFORMATION info;
705 if (!GetFileInformationByHandle( hFile, &info )) return -1;
706 if (filesizehigh) *filesizehigh = info.nFileSizeHigh;
707 return info.nFileSizeLow;
711 /***********************************************************************
712 * GetFileTime (KERNEL32.@)
714 BOOL WINAPI GetFileTime( HANDLE hFile, FILETIME *lpCreationTime,
715 FILETIME *lpLastAccessTime,
716 FILETIME *lpLastWriteTime )
718 BY_HANDLE_FILE_INFORMATION info;
719 if (!GetFileInformationByHandle( hFile, &info )) return FALSE;
720 if (lpCreationTime) *lpCreationTime = info.ftCreationTime;
721 if (lpLastAccessTime) *lpLastAccessTime = info.ftLastAccessTime;
722 if (lpLastWriteTime) *lpLastWriteTime = info.ftLastWriteTime;
723 return TRUE;
726 /***********************************************************************
727 * CompareFileTime (KERNEL32.@)
729 INT WINAPI CompareFileTime( LPFILETIME x, LPFILETIME y )
731 if (!x || !y) return -1;
733 if (x->dwHighDateTime > y->dwHighDateTime)
734 return 1;
735 if (x->dwHighDateTime < y->dwHighDateTime)
736 return -1;
737 if (x->dwLowDateTime > y->dwLowDateTime)
738 return 1;
739 if (x->dwLowDateTime < y->dwLowDateTime)
740 return -1;
741 return 0;
744 /***********************************************************************
745 * FILE_GetTempFileName : utility for GetTempFileName
747 static UINT FILE_GetTempFileName( LPCSTR path, LPCSTR prefix, UINT unique,
748 LPSTR buffer, BOOL isWin16 )
750 static UINT unique_temp;
751 DOS_FULL_NAME full_name;
752 int i;
753 LPSTR p;
754 UINT num;
756 if ( !path || !prefix || !buffer ) return 0;
758 if (!unique_temp) unique_temp = time(NULL) & 0xffff;
759 num = unique ? (unique & 0xffff) : (unique_temp++ & 0xffff);
761 strcpy( buffer, path );
762 p = buffer + strlen(buffer);
764 /* add a \, if there isn't one and path is more than just the drive letter ... */
765 if ( !((strlen(buffer) == 2) && (buffer[1] == ':'))
766 && ((p == buffer) || (p[-1] != '\\'))) *p++ = '\\';
768 if (isWin16) *p++ = '~';
769 for (i = 3; (i > 0) && (*prefix); i--) *p++ = *prefix++;
770 sprintf( p, "%04x.tmp", num );
772 /* Now try to create it */
774 if (!unique)
778 HFILE handle = CreateFileA( buffer, GENERIC_WRITE, 0, NULL,
779 CREATE_NEW, FILE_ATTRIBUTE_NORMAL, 0 );
780 if (handle != INVALID_HANDLE_VALUE)
781 { /* We created it */
782 TRACE("created %s\n",
783 buffer);
784 CloseHandle( handle );
785 break;
787 if (GetLastError() != ERROR_FILE_EXISTS)
788 break; /* No need to go on */
789 num++;
790 sprintf( p, "%04x.tmp", num );
791 } while (num != (unique & 0xffff));
794 /* Get the full path name */
796 if (DOSFS_GetFullName( buffer, FALSE, &full_name ))
798 /* Check if we have write access in the directory */
799 if ((p = strrchr( full_name.long_name, '/' ))) *p = '\0';
800 if (access( full_name.long_name, W_OK ) == -1)
801 WARN("returns '%s', which doesn't seem to be writeable.\n",
802 buffer);
804 TRACE("returning %s\n", buffer );
805 return unique ? unique : num;
809 /***********************************************************************
810 * GetTempFileNameA (KERNEL32.@)
812 UINT WINAPI GetTempFileNameA( LPCSTR path, LPCSTR prefix, UINT unique,
813 LPSTR buffer)
815 return FILE_GetTempFileName(path, prefix, unique, buffer, FALSE);
818 /***********************************************************************
819 * GetTempFileNameW (KERNEL32.@)
821 UINT WINAPI GetTempFileNameW( LPCWSTR path, LPCWSTR prefix, UINT unique,
822 LPWSTR buffer )
824 LPSTR patha,prefixa;
825 char buffera[144];
826 UINT ret;
828 if (!path) return 0;
829 patha = HEAP_strdupWtoA( GetProcessHeap(), 0, path );
830 prefixa = HEAP_strdupWtoA( GetProcessHeap(), 0, prefix );
831 ret = FILE_GetTempFileName( patha, prefixa, unique, buffera, FALSE );
832 MultiByteToWideChar( CP_ACP, 0, buffera, -1, buffer, MAX_PATH );
833 HeapFree( GetProcessHeap(), 0, patha );
834 HeapFree( GetProcessHeap(), 0, prefixa );
835 return ret;
839 /***********************************************************************
840 * GetTempFileName (KERNEL.97)
842 UINT16 WINAPI GetTempFileName16( BYTE drive, LPCSTR prefix, UINT16 unique,
843 LPSTR buffer )
845 char temppath[144];
847 if (!(drive & ~TF_FORCEDRIVE)) /* drive 0 means current default drive */
848 drive |= DRIVE_GetCurrentDrive() + 'A';
850 if ((drive & TF_FORCEDRIVE) &&
851 !DRIVE_IsValid( toupper(drive & ~TF_FORCEDRIVE) - 'A' ))
853 drive &= ~TF_FORCEDRIVE;
854 WARN("invalid drive %d specified\n", drive );
857 if (drive & TF_FORCEDRIVE)
858 sprintf(temppath,"%c:", drive & ~TF_FORCEDRIVE );
859 else
860 GetTempPathA( 132, temppath );
861 return (UINT16)FILE_GetTempFileName( temppath, prefix, unique, buffer, TRUE );
864 /***********************************************************************
865 * FILE_DoOpenFile
867 * Implementation of OpenFile16() and OpenFile32().
869 static HFILE FILE_DoOpenFile( LPCSTR name, OFSTRUCT *ofs, UINT mode,
870 BOOL win32 )
872 HFILE hFileRet;
873 FILETIME filetime;
874 WORD filedatetime[2];
875 DOS_FULL_NAME full_name;
876 DWORD access, sharing;
877 char *p;
879 if (!ofs) return HFILE_ERROR;
881 TRACE("%s %s %s %s%s%s%s%s%s%s%s%s\n",name,
882 ((mode & 0x3 )==OF_READ)?"OF_READ":
883 ((mode & 0x3 )==OF_WRITE)?"OF_WRITE":
884 ((mode & 0x3 )==OF_READWRITE)?"OF_READWRITE":"unknown",
885 ((mode & 0x70 )==OF_SHARE_COMPAT)?"OF_SHARE_COMPAT":
886 ((mode & 0x70 )==OF_SHARE_DENY_NONE)?"OF_SHARE_DENY_NONE":
887 ((mode & 0x70 )==OF_SHARE_DENY_READ)?"OF_SHARE_DENY_READ":
888 ((mode & 0x70 )==OF_SHARE_DENY_WRITE)?"OF_SHARE_DENY_WRITE":
889 ((mode & 0x70 )==OF_SHARE_EXCLUSIVE)?"OF_SHARE_EXCLUSIVE":"unknown",
890 ((mode & OF_PARSE )==OF_PARSE)?"OF_PARSE ":"",
891 ((mode & OF_DELETE )==OF_DELETE)?"OF_DELETE ":"",
892 ((mode & OF_VERIFY )==OF_VERIFY)?"OF_VERIFY ":"",
893 ((mode & OF_SEARCH )==OF_SEARCH)?"OF_SEARCH ":"",
894 ((mode & OF_CANCEL )==OF_CANCEL)?"OF_CANCEL ":"",
895 ((mode & OF_CREATE )==OF_CREATE)?"OF_CREATE ":"",
896 ((mode & OF_PROMPT )==OF_PROMPT)?"OF_PROMPT ":"",
897 ((mode & OF_EXIST )==OF_EXIST)?"OF_EXIST ":"",
898 ((mode & OF_REOPEN )==OF_REOPEN)?"OF_REOPEN ":""
902 ofs->cBytes = sizeof(OFSTRUCT);
903 ofs->nErrCode = 0;
904 if (mode & OF_REOPEN) name = ofs->szPathName;
906 if (!name) {
907 ERR("called with `name' set to NULL ! Please debug.\n");
908 return HFILE_ERROR;
911 TRACE("%s %04x\n", name, mode );
913 /* the watcom 10.6 IDE relies on a valid path returned in ofs->szPathName
914 Are there any cases where getting the path here is wrong?
915 Uwe Bonnes 1997 Apr 2 */
916 if (!GetFullPathNameA( name, sizeof(ofs->szPathName),
917 ofs->szPathName, NULL )) goto error;
918 FILE_ConvertOFMode( mode, &access, &sharing );
920 /* OF_PARSE simply fills the structure */
922 if (mode & OF_PARSE)
924 ofs->fFixedDisk = (GetDriveType16( ofs->szPathName[0]-'A' )
925 != DRIVE_REMOVABLE);
926 TRACE("(%s): OF_PARSE, res = '%s'\n",
927 name, ofs->szPathName );
928 return 0;
931 /* OF_CREATE is completely different from all other options, so
932 handle it first */
934 if (mode & OF_CREATE)
936 if ((hFileRet = CreateFileA( name, GENERIC_READ | GENERIC_WRITE,
937 sharing, NULL, CREATE_ALWAYS,
938 FILE_ATTRIBUTE_NORMAL, 0 ))== INVALID_HANDLE_VALUE)
939 goto error;
940 goto success;
943 /* If OF_SEARCH is set, ignore the given path */
945 if ((mode & OF_SEARCH) && !(mode & OF_REOPEN))
947 /* First try the file name as is */
948 if (DOSFS_GetFullName( name, TRUE, &full_name )) goto found;
949 /* Now remove the path */
950 if (name[0] && (name[1] == ':')) name += 2;
951 if ((p = strrchr( name, '\\' ))) name = p + 1;
952 if ((p = strrchr( name, '/' ))) name = p + 1;
953 if (!name[0]) goto not_found;
956 /* Now look for the file */
958 if (!DIR_SearchPath( NULL, name, NULL, &full_name, win32 )) goto not_found;
960 found:
961 TRACE("found %s = %s\n",
962 full_name.long_name, full_name.short_name );
963 lstrcpynA( ofs->szPathName, full_name.short_name,
964 sizeof(ofs->szPathName) );
966 if (mode & OF_SHARE_EXCLUSIVE)
967 /* Some InstallShield version uses OF_SHARE_EXCLUSIVE
968 on the file <tempdir>/_ins0432._mp to determine how
969 far installation has proceeded.
970 _ins0432._mp is an executable and while running the
971 application expects the open with OF_SHARE_ to fail*/
972 /* Probable FIXME:
973 As our loader closes the files after loading the executable,
974 we can't find the running executable with FILE_InUse.
975 The loader should keep the file open, as Windows does that, too.
978 char *last = strrchr(full_name.long_name,'/');
979 if (!last)
980 last = full_name.long_name - 1;
981 if (GetModuleHandle16(last+1))
983 TRACE("Denying shared open for %s\n",full_name.long_name);
984 return HFILE_ERROR;
988 if (mode & OF_DELETE)
990 if (unlink( full_name.long_name ) == -1) goto not_found;
991 TRACE("(%s): OF_DELETE return = OK\n", name);
992 return 1;
995 hFileRet = FILE_CreateFile( full_name.long_name, access, sharing,
996 NULL, OPEN_EXISTING, 0, 0,
997 DRIVE_GetFlags(full_name.drive) & DRIVE_FAIL_READ_ONLY,
998 GetDriveTypeA( full_name.short_name ) );
999 if (!hFileRet) goto not_found;
1001 GetFileTime( hFileRet, NULL, NULL, &filetime );
1002 FileTimeToDosDateTime( &filetime, &filedatetime[0], &filedatetime[1] );
1003 if ((mode & OF_VERIFY) && (mode & OF_REOPEN))
1005 if (memcmp( ofs->reserved, filedatetime, sizeof(ofs->reserved) ))
1007 CloseHandle( hFileRet );
1008 WARN("(%s): OF_VERIFY failed\n", name );
1009 /* FIXME: what error here? */
1010 SetLastError( ERROR_FILE_NOT_FOUND );
1011 goto error;
1014 memcpy( ofs->reserved, filedatetime, sizeof(ofs->reserved) );
1016 success: /* We get here if the open was successful */
1017 TRACE("(%s): OK, return = %d\n", name, hFileRet );
1018 if (win32)
1020 if (mode & OF_EXIST) /* Return the handle, but close it first */
1021 CloseHandle( hFileRet );
1023 else
1025 hFileRet = Win32HandleToDosFileHandle( hFileRet );
1026 if (hFileRet == HFILE_ERROR16) goto error;
1027 if (mode & OF_EXIST) /* Return the handle, but close it first */
1028 _lclose16( hFileRet );
1030 return hFileRet;
1032 not_found: /* We get here if the file does not exist */
1033 WARN("'%s' not found or sharing violation\n", name );
1034 SetLastError( ERROR_FILE_NOT_FOUND );
1035 /* fall through */
1037 error: /* We get here if there was an error opening the file */
1038 ofs->nErrCode = GetLastError();
1039 WARN("(%s): return = HFILE_ERROR error= %d\n",
1040 name,ofs->nErrCode );
1041 return HFILE_ERROR;
1045 /***********************************************************************
1046 * OpenFile (KERNEL.74)
1047 * OpenFileEx (KERNEL.360)
1049 HFILE16 WINAPI OpenFile16( LPCSTR name, OFSTRUCT *ofs, UINT16 mode )
1051 return FILE_DoOpenFile( name, ofs, mode, FALSE );
1055 /***********************************************************************
1056 * OpenFile (KERNEL32.@)
1058 HFILE WINAPI OpenFile( LPCSTR name, OFSTRUCT *ofs, UINT mode )
1060 return FILE_DoOpenFile( name, ofs, mode, TRUE );
1064 /***********************************************************************
1065 * FILE_InitProcessDosHandles
1067 * Allocates the default DOS handles for a process. Called either by
1068 * Win32HandleToDosFileHandle below or by the DOSVM stuff.
1070 static void FILE_InitProcessDosHandles( void )
1072 dos_handles[0] = GetStdHandle(STD_INPUT_HANDLE);
1073 dos_handles[1] = GetStdHandle(STD_OUTPUT_HANDLE);
1074 dos_handles[2] = GetStdHandle(STD_ERROR_HANDLE);
1075 dos_handles[3] = GetStdHandle(STD_ERROR_HANDLE);
1076 dos_handles[4] = GetStdHandle(STD_ERROR_HANDLE);
1079 /***********************************************************************
1080 * Win32HandleToDosFileHandle (KERNEL32.21)
1082 * Allocate a DOS handle for a Win32 handle. The Win32 handle is no
1083 * longer valid after this function (even on failure).
1085 * Note: this is not exactly right, since on Win95 the Win32 handles
1086 * are on top of DOS handles and we do it the other way
1087 * around. Should be good enough though.
1089 HFILE WINAPI Win32HandleToDosFileHandle( HANDLE handle )
1091 int i;
1093 if (!handle || (handle == INVALID_HANDLE_VALUE))
1094 return HFILE_ERROR;
1096 for (i = 5; i < DOS_TABLE_SIZE; i++)
1097 if (!dos_handles[i])
1099 dos_handles[i] = handle;
1100 TRACE("Got %d for h32 %d\n", i, handle );
1101 return (HFILE)i;
1103 CloseHandle( handle );
1104 SetLastError( ERROR_TOO_MANY_OPEN_FILES );
1105 return HFILE_ERROR;
1109 /***********************************************************************
1110 * DosFileHandleToWin32Handle (KERNEL32.20)
1112 * Return the Win32 handle for a DOS handle.
1114 * Note: this is not exactly right, since on Win95 the Win32 handles
1115 * are on top of DOS handles and we do it the other way
1116 * around. Should be good enough though.
1118 HANDLE WINAPI DosFileHandleToWin32Handle( HFILE handle )
1120 HFILE16 hfile = (HFILE16)handle;
1121 if (hfile < 5 && !dos_handles[hfile]) FILE_InitProcessDosHandles();
1122 if ((hfile >= DOS_TABLE_SIZE) || !dos_handles[hfile])
1124 SetLastError( ERROR_INVALID_HANDLE );
1125 return INVALID_HANDLE_VALUE;
1127 return dos_handles[hfile];
1131 /***********************************************************************
1132 * DisposeLZ32Handle (KERNEL32.22)
1134 * Note: this is not entirely correct, we should only close the
1135 * 32-bit handle and not the 16-bit one, but we cannot do
1136 * this because of the way our DOS handles are implemented.
1137 * It shouldn't break anything though.
1139 void WINAPI DisposeLZ32Handle( HANDLE handle )
1141 int i;
1143 if (!handle || (handle == INVALID_HANDLE_VALUE)) return;
1145 for (i = 5; i < DOS_TABLE_SIZE; i++)
1146 if (dos_handles[i] == handle)
1148 dos_handles[i] = 0;
1149 CloseHandle( handle );
1150 break;
1155 /***********************************************************************
1156 * FILE_Dup2
1158 * dup2() function for DOS handles.
1160 HFILE16 FILE_Dup2( HFILE16 hFile1, HFILE16 hFile2 )
1162 HANDLE new_handle;
1164 if (hFile1 < 5 && !dos_handles[hFile1]) FILE_InitProcessDosHandles();
1166 if ((hFile1 >= DOS_TABLE_SIZE) || (hFile2 >= DOS_TABLE_SIZE) || !dos_handles[hFile1])
1168 SetLastError( ERROR_INVALID_HANDLE );
1169 return HFILE_ERROR16;
1171 if (hFile2 < 5)
1173 FIXME("stdio handle closed, need proper conversion\n" );
1174 SetLastError( ERROR_INVALID_HANDLE );
1175 return HFILE_ERROR16;
1177 if (!DuplicateHandle( GetCurrentProcess(), dos_handles[hFile1],
1178 GetCurrentProcess(), &new_handle,
1179 0, FALSE, DUPLICATE_SAME_ACCESS ))
1180 return HFILE_ERROR16;
1181 if (dos_handles[hFile2]) CloseHandle( dos_handles[hFile2] );
1182 dos_handles[hFile2] = new_handle;
1183 return hFile2;
1187 /***********************************************************************
1188 * _lclose (KERNEL.81)
1190 HFILE16 WINAPI _lclose16( HFILE16 hFile )
1192 if (hFile < 5)
1194 FIXME("stdio handle closed, need proper conversion\n" );
1195 SetLastError( ERROR_INVALID_HANDLE );
1196 return HFILE_ERROR16;
1198 if ((hFile >= DOS_TABLE_SIZE) || !dos_handles[hFile])
1200 SetLastError( ERROR_INVALID_HANDLE );
1201 return HFILE_ERROR16;
1203 TRACE("%d (handle32=%d)\n", hFile, dos_handles[hFile] );
1204 CloseHandle( dos_handles[hFile] );
1205 dos_handles[hFile] = 0;
1206 return 0;
1210 /***********************************************************************
1211 * _lclose (KERNEL32.@)
1213 HFILE WINAPI _lclose( HFILE hFile )
1215 TRACE("handle %d\n", hFile );
1216 return CloseHandle( hFile ) ? 0 : HFILE_ERROR;
1219 /***********************************************************************
1220 * GetOverlappedResult (KERNEL32.@)
1222 * Check the result of an Asynchronous data transfer from a file.
1224 * RETURNS
1225 * TRUE on success
1226 * FALSE on failure
1228 * If successful (and relevant) lpTransferred will hold the number of
1229 * bytes transferred during the async operation.
1231 * BUGS
1233 * Currently only works for WaitCommEvent, ReadFile, WriteFile
1234 * with communications ports.
1237 BOOL WINAPI GetOverlappedResult(
1238 HANDLE hFile, /* [in] handle of file to check on */
1239 LPOVERLAPPED lpOverlapped, /* [in/out] pointer to overlapped */
1240 LPDWORD lpTransferred, /* [in/out] number of bytes transferred */
1241 BOOL bWait /* [in] wait for the transfer to complete ? */
1243 DWORD r;
1245 TRACE("(%d %p %p %x)\n", hFile, lpOverlapped, lpTransferred, bWait);
1247 if(lpOverlapped==NULL)
1249 ERR("lpOverlapped was null\n");
1250 return FALSE;
1252 if(!lpOverlapped->hEvent)
1254 ERR("lpOverlapped->hEvent was null\n");
1255 return FALSE;
1258 do {
1259 TRACE("waiting on %p\n",lpOverlapped);
1260 r = WaitForSingleObjectEx(lpOverlapped->hEvent, bWait?INFINITE:0, TRUE);
1261 TRACE("wait on %p returned %ld\n",lpOverlapped,r);
1262 } while (r==STATUS_USER_APC);
1264 if(lpTransferred)
1265 *lpTransferred = lpOverlapped->InternalHigh;
1267 SetLastError(lpOverlapped->Internal);
1269 return (r==WAIT_OBJECT_0);
1273 /***********************************************************************
1274 * FILE_StartAsync (INTERNAL)
1276 * type==ASYNC_TYPE_NONE means cancel the indicated overlapped operation
1277 * lpOverlapped==NULL means all overlappeds match
1279 BOOL FILE_StartAsync(HANDLE hFile, LPOVERLAPPED lpOverlapped, DWORD type, DWORD count, DWORD status)
1281 BOOL ret;
1282 SERVER_START_REQ(register_async)
1284 req->handle = hFile;
1285 req->overlapped = lpOverlapped;
1286 req->type = type;
1287 req->count = count;
1288 req->func = check_async_list;
1289 req->status = status;
1290 ret = wine_server_call( req );
1292 SERVER_END_REQ;
1293 return !ret;
1296 /***********************************************************************
1297 * CancelIo (KERNEL32.@)
1299 BOOL WINAPI CancelIo(HANDLE handle)
1301 async_private *ovp,*t;
1303 TRACE("handle = %x\n",handle);
1305 ovp = NtCurrentTeb()->pending_list;
1306 while(ovp)
1308 t = ovp->next;
1309 if(FILE_StartAsync(handle, ovp->lpOverlapped, ovp->type, 0, STATUS_CANCELLED))
1311 TRACE("overlapped = %p\n",ovp->lpOverlapped);
1312 finish_async(ovp, STATUS_CANCELLED);
1314 ovp = t;
1316 WaitForMultipleObjectsEx(0,NULL,FALSE,1,TRUE);
1317 return TRUE;
1320 /***********************************************************************
1321 * FILE_AsyncReadService (INTERNAL)
1323 * This function is called while the client is waiting on the
1324 * server, so we can't make any server calls here.
1326 static void FILE_AsyncReadService(async_private *ovp)
1328 LPOVERLAPPED lpOverlapped = ovp->lpOverlapped;
1329 int result, r;
1330 int already = lpOverlapped->InternalHigh;
1332 TRACE("%p %p\n", lpOverlapped, ovp->buffer );
1334 /* check to see if the data is ready (non-blocking) */
1336 result = pread (ovp->fd, &ovp->buffer[already], ovp->count - already,
1337 OVERLAPPED_OFFSET (lpOverlapped) + already);
1338 if ((result < 0) && (errno == ESPIPE))
1339 result = read (ovp->fd, &ovp->buffer[already], ovp->count - already);
1341 if ( (result<0) && ((errno == EAGAIN) || (errno == EINTR)))
1343 TRACE("Deferred read %d\n",errno);
1344 r = STATUS_PENDING;
1345 goto async_end;
1348 /* check to see if the transfer is complete */
1349 if(result<0)
1351 TRACE("read returned errno %d\n",errno);
1352 r = STATUS_UNSUCCESSFUL;
1353 goto async_end;
1356 lpOverlapped->InternalHigh += result;
1357 TRACE("read %d more bytes %ld/%d so far\n",result,lpOverlapped->InternalHigh,ovp->count);
1359 if(lpOverlapped->InternalHigh < ovp->count)
1360 r = STATUS_PENDING;
1361 else
1362 r = STATUS_SUCCESS;
1364 async_end:
1365 lpOverlapped->Internal = r;
1368 /***********************************************************************
1369 * FILE_ReadFileEx (INTERNAL)
1371 static BOOL FILE_ReadFileEx(HANDLE hFile, LPVOID buffer, DWORD bytesToRead,
1372 LPOVERLAPPED overlapped,
1373 LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine)
1375 async_private *ovp;
1376 int fd;
1378 TRACE("file %d to buf %p num %ld %p func %p\n",
1379 hFile, buffer, bytesToRead, overlapped, lpCompletionRoutine);
1381 /* check that there is an overlapped struct */
1382 if (overlapped==NULL)
1384 SetLastError(ERROR_INVALID_PARAMETER);
1385 return FALSE;
1388 fd = FILE_GetUnixHandle( hFile, GENERIC_READ );
1389 if(fd<0)
1391 TRACE("Couldn't get FD\n");
1392 return FALSE;
1395 ovp = (async_private *) HeapAlloc(GetProcessHeap(), 0, sizeof (async_private));
1396 if(!ovp)
1398 TRACE("HeapAlloc Failed\n");
1399 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1400 close(fd);
1401 return FALSE;
1403 ovp->lpOverlapped = overlapped;
1404 ovp->count = bytesToRead;
1405 ovp->completion_func = lpCompletionRoutine;
1406 ovp->func = FILE_AsyncReadService;
1407 ovp->buffer = buffer;
1408 ovp->fd = fd;
1409 ovp->type = ASYNC_TYPE_READ;
1410 ovp->handle = hFile;
1412 /* hook this overlap into the pending async operation list */
1413 ovp->next = NtCurrentTeb()->pending_list;
1414 ovp->prev = NULL;
1415 if(ovp->next)
1416 ovp->next->prev = ovp;
1417 NtCurrentTeb()->pending_list = ovp;
1419 if ( !FILE_StartAsync(hFile, overlapped, ASYNC_TYPE_READ, bytesToRead, STATUS_PENDING) )
1421 /* FIXME: remove async_private and release memory */
1422 ERR("FILE_StartAsync failed\n");
1423 return FALSE;
1426 return TRUE;
1429 /***********************************************************************
1430 * ReadFileEx (KERNEL32.@)
1432 BOOL WINAPI ReadFileEx(HANDLE hFile, LPVOID buffer, DWORD bytesToRead,
1433 LPOVERLAPPED overlapped,
1434 LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine)
1436 overlapped->Internal = STATUS_PENDING;
1437 overlapped->InternalHigh = 0;
1438 return FILE_ReadFileEx(hFile,buffer,bytesToRead,overlapped,lpCompletionRoutine);
1441 static VOID CALLBACK FILE_OverlappedComplete(DWORD status, DWORD count, LPOVERLAPPED ov)
1443 NtSetEvent(ov->hEvent,NULL);
1446 static BOOL FILE_TimeoutRead(HANDLE hFile, LPVOID buffer, DWORD bytesToRead, LPDWORD bytesRead)
1448 OVERLAPPED ov;
1449 BOOL r = FALSE;
1451 TRACE("%d %p %ld %p\n", hFile, buffer, bytesToRead, bytesRead );
1453 ZeroMemory(&ov, sizeof (OVERLAPPED));
1454 if(STATUS_SUCCESS==NtCreateEvent(&ov.hEvent, SYNCHRONIZE, NULL, 0, 0))
1456 if(ReadFileEx(hFile, buffer, bytesToRead, &ov, FILE_OverlappedComplete))
1458 r = GetOverlappedResult(hFile, &ov, bytesRead, TRUE);
1461 CloseHandle(ov.hEvent);
1462 return r;
1465 /***********************************************************************
1466 * ReadFile (KERNEL32.@)
1468 BOOL WINAPI ReadFile( HANDLE hFile, LPVOID buffer, DWORD bytesToRead,
1469 LPDWORD bytesRead, LPOVERLAPPED overlapped )
1471 int unix_handle, result;
1472 enum fd_type type;
1473 DWORD flags;
1475 TRACE("%d %p %ld %p %p\n", hFile, buffer, bytesToRead,
1476 bytesRead, overlapped );
1478 if (bytesRead) *bytesRead = 0; /* Do this before anything else */
1479 if (!bytesToRead) return TRUE;
1481 unix_handle = FILE_GetUnixHandleType( hFile, GENERIC_READ, &type, &flags );
1483 if (flags & FD_FLAG_OVERLAPPED)
1485 if (unix_handle == -1) return FALSE;
1486 if ( (overlapped==NULL) || NtResetEvent( overlapped->hEvent, NULL ) )
1488 TRACE("Overlapped not specified or invalid event flag\n");
1489 close(unix_handle);
1490 SetLastError(ERROR_INVALID_PARAMETER);
1491 return FALSE;
1494 /* see if we can read some data already (this shouldn't block) */
1495 result = pread( unix_handle, buffer, bytesToRead, OVERLAPPED_OFFSET(overlapped) );
1496 if ((result < 0) && (errno == ESPIPE))
1497 result = read( unix_handle, buffer, bytesToRead );
1498 close(unix_handle);
1500 if(result<0)
1502 if( (errno!=EAGAIN) && (errno!=EINTR) &&
1503 ((errno != EFAULT) || IsBadWritePtr( buffer, bytesToRead )) )
1505 FILE_SetDosError();
1506 return FALSE;
1508 else
1509 result = 0;
1512 /* if we read enough to keep the app happy, then return now */
1513 if(result>=bytesToRead)
1515 *bytesRead = result;
1516 return TRUE;
1519 /* at last resort, do an overlapped read */
1520 overlapped->Internal = STATUS_PENDING;
1521 overlapped->InternalHigh = result;
1523 if(!FILE_ReadFileEx(hFile, buffer, bytesToRead, overlapped, FILE_OverlappedComplete))
1524 return FALSE;
1526 /* fail on return, with ERROR_IO_PENDING */
1527 SetLastError(ERROR_IO_PENDING);
1528 return FALSE;
1530 if (flags & FD_FLAG_TIMEOUT)
1532 close(unix_handle);
1533 return FILE_TimeoutRead(hFile, buffer, bytesToRead, bytesRead);
1535 switch(type)
1537 case FD_TYPE_CONSOLE:
1538 return ReadConsoleA(hFile, buffer, bytesToRead, bytesRead, NULL);
1540 default:
1541 /* normal unix files */
1542 if (unix_handle == -1)
1543 return FALSE;
1544 if (overlapped)
1546 close(unix_handle);
1547 SetLastError(ERROR_INVALID_PARAMETER);
1548 return FALSE;
1550 break;
1553 /* code for synchronous reads */
1554 while ((result = read( unix_handle, buffer, bytesToRead )) == -1)
1556 if ((errno == EAGAIN) || (errno == EINTR)) continue;
1557 if ((errno == EFAULT) && !IsBadWritePtr( buffer, bytesToRead )) continue;
1558 FILE_SetDosError();
1559 break;
1561 close( unix_handle );
1562 if (result == -1) return FALSE;
1563 if (bytesRead) *bytesRead = result;
1564 return TRUE;
1568 /***********************************************************************
1569 * FILE_AsyncWriteService (INTERNAL)
1571 * This function is called while the client is waiting on the
1572 * server, so we can't make any server calls here.
1574 static void FILE_AsyncWriteService(struct async_private *ovp)
1576 LPOVERLAPPED lpOverlapped = ovp->lpOverlapped;
1577 int result, r;
1578 int already = lpOverlapped->InternalHigh;
1580 TRACE("(%p %p)\n",lpOverlapped,ovp->buffer);
1582 /* write some data (non-blocking) */
1584 result = pwrite(ovp->fd, &ovp->buffer[already], ovp->count - already,
1585 OVERLAPPED_OFFSET (lpOverlapped) + already);
1586 if ((result < 0) && (errno == ESPIPE))
1587 result = write(ovp->fd, &ovp->buffer[already], ovp->count - already);
1589 if ( (result<0) && ((errno == EAGAIN) || (errno == EINTR)))
1591 r = STATUS_PENDING;
1592 goto async_end;
1595 /* check to see if the transfer is complete */
1596 if(result<0)
1598 r = STATUS_UNSUCCESSFUL;
1599 goto async_end;
1602 lpOverlapped->InternalHigh += result;
1604 TRACE("wrote %d more bytes %ld/%d so far\n",result,lpOverlapped->InternalHigh,ovp->count);
1606 if(lpOverlapped->InternalHigh < ovp->count)
1607 r = STATUS_PENDING;
1608 else
1609 r = STATUS_SUCCESS;
1611 async_end:
1612 lpOverlapped->Internal = r;
1615 /***********************************************************************
1616 * FILE_WriteFileEx
1618 static BOOL FILE_WriteFileEx(HANDLE hFile, LPCVOID buffer, DWORD bytesToWrite,
1619 LPOVERLAPPED overlapped,
1620 LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine)
1622 async_private *ovp;
1624 TRACE("file %d to buf %p num %ld %p func %p stub\n",
1625 hFile, buffer, bytesToWrite, overlapped, lpCompletionRoutine);
1627 if (overlapped == NULL)
1629 SetLastError(ERROR_INVALID_PARAMETER);
1630 return FALSE;
1633 overlapped->Internal = STATUS_PENDING;
1634 overlapped->InternalHigh = 0;
1636 if (!FILE_StartAsync(hFile, overlapped, ASYNC_TYPE_WRITE, bytesToWrite, STATUS_PENDING ))
1638 TRACE("FILE_StartAsync failed\n");
1639 return FALSE;
1642 ovp = (async_private*) HeapAlloc(GetProcessHeap(), 0, sizeof (async_private));
1643 if(!ovp)
1645 TRACE("HeapAlloc Failed\n");
1646 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1647 return FALSE;
1649 ovp->lpOverlapped = overlapped;
1650 ovp->func = FILE_AsyncWriteService;
1651 ovp->buffer = (LPVOID) buffer;
1652 ovp->count = bytesToWrite;
1653 ovp->completion_func = lpCompletionRoutine;
1654 ovp->fd = FILE_GetUnixHandle( hFile, GENERIC_WRITE );
1655 ovp->type = ASYNC_TYPE_WRITE;
1656 ovp->handle = hFile;
1658 if(ovp->fd <0)
1660 HeapFree(GetProcessHeap(), 0, ovp);
1661 return FALSE;
1664 /* hook this overlap into the pending async operation list */
1665 ovp->next = NtCurrentTeb()->pending_list;
1666 ovp->prev = NULL;
1667 if(ovp->next)
1668 ovp->next->prev = ovp;
1669 NtCurrentTeb()->pending_list = ovp;
1671 return TRUE;
1674 /***********************************************************************
1675 * WriteFileEx (KERNEL32.@)
1677 BOOL WINAPI WriteFileEx(HANDLE hFile, LPCVOID buffer, DWORD bytesToWrite,
1678 LPOVERLAPPED overlapped,
1679 LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine)
1681 overlapped->Internal = STATUS_PENDING;
1682 overlapped->InternalHigh = 0;
1684 return FILE_WriteFileEx(hFile, buffer, bytesToWrite, overlapped, lpCompletionRoutine);
1687 /***********************************************************************
1688 * WriteFile (KERNEL32.@)
1690 BOOL WINAPI WriteFile( HANDLE hFile, LPCVOID buffer, DWORD bytesToWrite,
1691 LPDWORD bytesWritten, LPOVERLAPPED overlapped )
1693 int unix_handle, result;
1694 enum fd_type type;
1695 DWORD flags;
1697 TRACE("%d %p %ld %p %p\n", hFile, buffer, bytesToWrite,
1698 bytesWritten, overlapped );
1700 if (bytesWritten) *bytesWritten = 0; /* Do this before anything else */
1701 if (!bytesToWrite) return TRUE;
1703 unix_handle = FILE_GetUnixHandleType( hFile, GENERIC_WRITE, &type, &flags );
1705 if (flags & FD_FLAG_OVERLAPPED)
1707 if (unix_handle == -1) return FALSE;
1708 if ( (overlapped==NULL) || NtResetEvent( overlapped->hEvent, NULL ) )
1710 TRACE("Overlapped not specified or invalid event flag\n");
1711 close(unix_handle);
1712 SetLastError(ERROR_INVALID_PARAMETER);
1713 return FALSE;
1716 /* see if we can write some data already (this shouldn't block) */
1718 result = pwrite( unix_handle, buffer, bytesToWrite, OVERLAPPED_OFFSET (overlapped) );
1719 if ((result < 0) && (errno == ESPIPE))
1720 result = write( unix_handle, buffer, bytesToWrite );
1722 close(unix_handle);
1724 if(result<0)
1726 if( (errno!=EAGAIN) && (errno!=EINTR) &&
1727 ((errno != EFAULT) || IsBadReadPtr( buffer, bytesToWrite )) )
1729 FILE_SetDosError();
1730 return FALSE;
1732 else
1733 result = 0;
1736 /* if we wrote enough to keep the app happy, then return now */
1737 if(result>=bytesToWrite)
1739 *bytesWritten = result;
1740 return TRUE;
1743 /* at last resort, do an overlapped read */
1744 overlapped->Internal = STATUS_PENDING;
1745 overlapped->InternalHigh = result;
1747 if(!FILE_WriteFileEx(hFile, buffer, bytesToWrite, overlapped, FILE_OverlappedComplete))
1748 return FALSE;
1750 /* fail on return, with ERROR_IO_PENDING */
1751 SetLastError(ERROR_IO_PENDING);
1752 return FALSE;
1755 switch(type)
1757 case FD_TYPE_CONSOLE:
1758 TRACE("%d %s %ld %p %p\n", hFile, debugstr_an(buffer, bytesToWrite), bytesToWrite,
1759 bytesWritten, overlapped );
1760 return WriteConsoleA(hFile, buffer, bytesToWrite, bytesWritten, NULL);
1761 default:
1762 if (unix_handle == -1)
1763 return FALSE;
1766 /* synchronous file write */
1767 while ((result = write( unix_handle, buffer, bytesToWrite )) == -1)
1769 if ((errno == EAGAIN) || (errno == EINTR)) continue;
1770 if ((errno == EFAULT) && !IsBadReadPtr( buffer, bytesToWrite )) continue;
1771 if (errno == ENOSPC)
1772 SetLastError( ERROR_DISK_FULL );
1773 else
1774 FILE_SetDosError();
1775 break;
1777 close( unix_handle );
1778 if (result == -1) return FALSE;
1779 if (bytesWritten) *bytesWritten = result;
1780 return TRUE;
1784 /***********************************************************************
1785 * _hread (KERNEL.349)
1787 LONG WINAPI WIN16_hread( HFILE16 hFile, SEGPTR buffer, LONG count )
1789 LONG maxlen;
1791 TRACE("%d %08lx %ld\n",
1792 hFile, (DWORD)buffer, count );
1794 /* Some programs pass a count larger than the allocated buffer */
1795 maxlen = GetSelectorLimit16( SELECTOROF(buffer) ) - OFFSETOF(buffer) + 1;
1796 if (count > maxlen) count = maxlen;
1797 return _lread(DosFileHandleToWin32Handle(hFile), MapSL(buffer), count );
1801 /***********************************************************************
1802 * _lread (KERNEL.82)
1804 UINT16 WINAPI WIN16_lread( HFILE16 hFile, SEGPTR buffer, UINT16 count )
1806 return (UINT16)WIN16_hread( hFile, buffer, (LONG)count );
1810 /***********************************************************************
1811 * _lread (KERNEL32.@)
1813 UINT WINAPI _lread( HFILE handle, LPVOID buffer, UINT count )
1815 DWORD result;
1816 if (!ReadFile( handle, buffer, count, &result, NULL )) return -1;
1817 return result;
1821 /***********************************************************************
1822 * _lread16 (KERNEL.82)
1824 UINT16 WINAPI _lread16( HFILE16 hFile, LPVOID buffer, UINT16 count )
1826 return (UINT16)_lread(DosFileHandleToWin32Handle(hFile), buffer, (LONG)count );
1830 /***********************************************************************
1831 * _lcreat (KERNEL.83)
1833 HFILE16 WINAPI _lcreat16( LPCSTR path, INT16 attr )
1835 return Win32HandleToDosFileHandle( _lcreat( path, attr ) );
1839 /***********************************************************************
1840 * _lcreat (KERNEL32.@)
1842 HFILE WINAPI _lcreat( LPCSTR path, INT attr )
1844 /* Mask off all flags not explicitly allowed by the doc */
1845 attr &= FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM;
1846 TRACE("%s %02x\n", path, attr );
1847 return CreateFileA( path, GENERIC_READ | GENERIC_WRITE,
1848 FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
1849 CREATE_ALWAYS, attr, 0 );
1853 /***********************************************************************
1854 * SetFilePointer (KERNEL32.@)
1856 DWORD WINAPI SetFilePointer( HANDLE hFile, LONG distance, LONG *highword,
1857 DWORD method )
1859 DWORD ret = 0xffffffff;
1861 TRACE("handle %d offset %ld high %ld origin %ld\n",
1862 hFile, distance, highword?*highword:0, method );
1864 SERVER_START_REQ( set_file_pointer )
1866 req->handle = hFile;
1867 req->low = distance;
1868 req->high = highword ? *highword : (distance >= 0) ? 0 : -1;
1869 /* FIXME: assumes 1:1 mapping between Windows and Unix seek constants */
1870 req->whence = method;
1871 SetLastError( 0 );
1872 if (!wine_server_call_err( req ))
1874 ret = reply->new_low;
1875 if (highword) *highword = reply->new_high;
1878 SERVER_END_REQ;
1879 return ret;
1883 /***********************************************************************
1884 * _llseek (KERNEL.84)
1886 * FIXME:
1887 * Seeking before the start of the file should be allowed for _llseek16,
1888 * but cause subsequent I/O operations to fail (cf. interrupt list)
1891 LONG WINAPI _llseek16( HFILE16 hFile, LONG lOffset, INT16 nOrigin )
1893 return SetFilePointer( DosFileHandleToWin32Handle(hFile), lOffset, NULL, nOrigin );
1897 /***********************************************************************
1898 * _llseek (KERNEL32.@)
1900 LONG WINAPI _llseek( HFILE hFile, LONG lOffset, INT nOrigin )
1902 return SetFilePointer( hFile, lOffset, NULL, nOrigin );
1906 /***********************************************************************
1907 * _lopen (KERNEL.85)
1909 HFILE16 WINAPI _lopen16( LPCSTR path, INT16 mode )
1911 return Win32HandleToDosFileHandle( _lopen( path, mode ) );
1915 /***********************************************************************
1916 * _lopen (KERNEL32.@)
1918 HFILE WINAPI _lopen( LPCSTR path, INT mode )
1920 DWORD access, sharing;
1922 TRACE("('%s',%04x)\n", path, mode );
1923 FILE_ConvertOFMode( mode, &access, &sharing );
1924 return CreateFileA( path, access, sharing, NULL, OPEN_EXISTING, 0, 0 );
1928 /***********************************************************************
1929 * _lwrite (KERNEL.86)
1931 UINT16 WINAPI _lwrite16( HFILE16 hFile, LPCSTR buffer, UINT16 count )
1933 return (UINT16)_hwrite( DosFileHandleToWin32Handle(hFile), buffer, (LONG)count );
1936 /***********************************************************************
1937 * _lwrite (KERNEL32.@)
1939 UINT WINAPI _lwrite( HFILE hFile, LPCSTR buffer, UINT count )
1941 return (UINT)_hwrite( hFile, buffer, (LONG)count );
1945 /***********************************************************************
1946 * _hread16 (KERNEL.349)
1948 LONG WINAPI _hread16( HFILE16 hFile, LPVOID buffer, LONG count)
1950 return _lread( DosFileHandleToWin32Handle(hFile), buffer, count );
1954 /***********************************************************************
1955 * _hread (KERNEL32.@)
1957 LONG WINAPI _hread( HFILE hFile, LPVOID buffer, LONG count)
1959 return _lread( hFile, buffer, count );
1963 /***********************************************************************
1964 * _hwrite (KERNEL.350)
1966 LONG WINAPI _hwrite16( HFILE16 hFile, LPCSTR buffer, LONG count )
1968 return _hwrite( DosFileHandleToWin32Handle(hFile), buffer, count );
1972 /***********************************************************************
1973 * _hwrite (KERNEL32.@)
1975 * experimentation yields that _lwrite:
1976 * o truncates the file at the current position with
1977 * a 0 len write
1978 * o returns 0 on a 0 length write
1979 * o works with console handles
1982 LONG WINAPI _hwrite( HFILE handle, LPCSTR buffer, LONG count )
1984 DWORD result;
1986 TRACE("%d %p %ld\n", handle, buffer, count );
1988 if (!count)
1990 /* Expand or truncate at current position */
1991 if (!SetEndOfFile( handle )) return HFILE_ERROR;
1992 return 0;
1994 if (!WriteFile( handle, buffer, count, &result, NULL ))
1995 return HFILE_ERROR;
1996 return result;
2000 /***********************************************************************
2001 * SetHandleCount (KERNEL.199)
2003 UINT16 WINAPI SetHandleCount16( UINT16 count )
2005 return SetHandleCount( count );
2009 /*************************************************************************
2010 * SetHandleCount (KERNEL32.@)
2012 UINT WINAPI SetHandleCount( UINT count )
2014 return min( 256, count );
2018 /***********************************************************************
2019 * FlushFileBuffers (KERNEL32.@)
2021 BOOL WINAPI FlushFileBuffers( HANDLE hFile )
2023 BOOL ret;
2024 SERVER_START_REQ( flush_file )
2026 req->handle = hFile;
2027 ret = !wine_server_call_err( req );
2029 SERVER_END_REQ;
2030 return ret;
2034 /**************************************************************************
2035 * SetEndOfFile (KERNEL32.@)
2037 BOOL WINAPI SetEndOfFile( HANDLE hFile )
2039 BOOL ret;
2040 SERVER_START_REQ( truncate_file )
2042 req->handle = hFile;
2043 ret = !wine_server_call_err( req );
2045 SERVER_END_REQ;
2046 return ret;
2050 /***********************************************************************
2051 * DeleteFile (KERNEL.146)
2053 BOOL16 WINAPI DeleteFile16( LPCSTR path )
2055 return DeleteFileA( path );
2059 /***********************************************************************
2060 * DeleteFileA (KERNEL32.@)
2062 BOOL WINAPI DeleteFileA( LPCSTR path )
2064 DOS_FULL_NAME full_name;
2066 if (!path)
2068 SetLastError(ERROR_INVALID_PARAMETER);
2069 return FALSE;
2071 TRACE("'%s'\n", path );
2073 if (!*path)
2075 ERR("Empty path passed\n");
2076 return FALSE;
2078 if (DOSFS_GetDevice( path ))
2080 WARN("cannot remove DOS device '%s'!\n", path);
2081 SetLastError( ERROR_FILE_NOT_FOUND );
2082 return FALSE;
2085 if (!DOSFS_GetFullName( path, TRUE, &full_name )) return FALSE;
2086 if (unlink( full_name.long_name ) == -1)
2088 FILE_SetDosError();
2089 return FALSE;
2091 return TRUE;
2095 /***********************************************************************
2096 * DeleteFileW (KERNEL32.@)
2098 BOOL WINAPI DeleteFileW( LPCWSTR path )
2100 LPSTR xpath = HEAP_strdupWtoA( GetProcessHeap(), 0, path );
2101 BOOL ret = DeleteFileA( xpath );
2102 HeapFree( GetProcessHeap(), 0, xpath );
2103 return ret;
2107 /***********************************************************************
2108 * GetFileType (KERNEL32.@)
2110 DWORD WINAPI GetFileType( HANDLE hFile )
2112 DWORD ret = FILE_TYPE_UNKNOWN;
2113 SERVER_START_REQ( get_file_info )
2115 req->handle = hFile;
2116 if (!wine_server_call_err( req )) ret = reply->type;
2118 SERVER_END_REQ;
2119 return ret;
2123 /* check if a file name is for an executable file (.exe or .com) */
2124 inline static BOOL is_executable( const char *name )
2126 int len = strlen(name);
2128 if (len < 4) return FALSE;
2129 return (!strcasecmp( name + len - 4, ".exe" ) ||
2130 !strcasecmp( name + len - 4, ".com" ));
2134 /***********************************************************************
2135 * FILE_AddBootRenameEntry
2137 * Adds an entry to the registry that is loaded when windows boots and
2138 * checks if there are some files to be removed or renamed/moved.
2139 * <fn1> has to be valid and <fn2> may be NULL. If both pointers are
2140 * non-NULL then the file is moved, otherwise it is deleted. The
2141 * entry of the registrykey is always appended with two zero
2142 * terminated strings. If <fn2> is NULL then the second entry is
2143 * simply a single 0-byte. Otherwise the second filename goes
2144 * there. The entries are prepended with \??\ before the path and the
2145 * second filename gets also a '!' as the first character if
2146 * MOVEFILE_REPLACE_EXISTING is set. After the final string another
2147 * 0-byte follows to indicate the end of the strings.
2148 * i.e.:
2149 * \??\D:\test\file1[0]
2150 * !\??\D:\test\file1_renamed[0]
2151 * \??\D:\Test|delete[0]
2152 * [0] <- file is to be deleted, second string empty
2153 * \??\D:\test\file2[0]
2154 * !\??\D:\test\file2_renamed[0]
2155 * [0] <- indicates end of strings
2157 * or:
2158 * \??\D:\test\file1[0]
2159 * !\??\D:\test\file1_renamed[0]
2160 * \??\D:\Test|delete[0]
2161 * [0] <- file is to be deleted, second string empty
2162 * [0] <- indicates end of strings
2165 static BOOL FILE_AddBootRenameEntry( const char *fn1, const char *fn2, DWORD flags )
2167 static const char PreString[] = "\\??\\";
2168 static const char ValueName[] = "PendingFileRenameOperations";
2170 BOOL rc = FALSE;
2171 HKEY Reboot = 0;
2172 DWORD Type, len1, len2, l;
2173 DWORD DataSize = 0;
2174 BYTE *Buffer = NULL;
2176 if(RegCreateKeyA(HKEY_LOCAL_MACHINE, "SYSTEM\\CurrentControlSet\\Control\\Session Manager",
2177 &Reboot) != ERROR_SUCCESS)
2179 WARN("Error creating key for reboot managment [%s]\n",
2180 "SYSTEM\\CurrentControlSet\\Control\\Session Manager");
2181 return FALSE;
2184 l = strlen(PreString);
2185 len1 = strlen(fn1) + l + 1;
2186 if (fn2)
2188 len2 = strlen(fn2) + l + 1;
2189 if (flags & MOVEFILE_REPLACE_EXISTING) len2++; /* Plus 1 because of the leading '!' */
2191 else len2 = 1; /* minimum is the 0 byte for the empty second string */
2193 /* First we check if the key exists and if so how many bytes it already contains. */
2194 if (RegQueryValueExA(Reboot, ValueName, NULL, &Type, NULL, &DataSize) == ERROR_SUCCESS)
2196 if (Type != REG_MULTI_SZ) goto Quit;
2197 if (!(Buffer = HeapAlloc( GetProcessHeap(), 0, DataSize + len1 + len2 + 1 ))) goto Quit;
2198 if (RegQueryValueExA(Reboot, ValueName, NULL, &Type, Buffer, &DataSize) != ERROR_SUCCESS)
2199 goto Quit;
2200 if (DataSize) DataSize--; /* remove terminating null (will be added back later) */
2202 else
2204 if (!(Buffer = HeapAlloc( GetProcessHeap(), 0, len1 + len2 + 1 ))) goto Quit;
2205 DataSize = 0;
2207 sprintf( Buffer + DataSize, "%s%s", PreString, fn1 );
2208 DataSize += len1;
2209 if (fn2)
2211 sprintf( Buffer + DataSize, "%s%s%s",
2212 (flags & MOVEFILE_REPLACE_EXISTING) ? "!" : "", PreString, fn2 );
2213 DataSize += len2;
2215 else Buffer[DataSize++] = 0;
2217 Buffer[DataSize++] = 0; /* add final null */
2218 rc = !RegSetValueExA( Reboot, ValueName, 0, REG_MULTI_SZ, Buffer, DataSize );
2220 Quit:
2221 if (Reboot) RegCloseKey(Reboot);
2222 if (Buffer) HeapFree( GetProcessHeap(), 0, Buffer );
2223 return(rc);
2227 /**************************************************************************
2228 * MoveFileExA (KERNEL32.@)
2230 BOOL WINAPI MoveFileExA( LPCSTR fn1, LPCSTR fn2, DWORD flag )
2232 DOS_FULL_NAME full_name1, full_name2;
2234 TRACE("(%s,%s,%04lx)\n", fn1, fn2, flag);
2236 /* FIXME: <Gerhard W. Gruber>sparhawk@gmx.at
2237 In case of W9x and lesser this function should return 120 (ERROR_CALL_NOT_IMPLEMENTED)
2238 to be really compatible. Most programs wont have any problems though. In case
2239 you encounter one, this is what you should return here. I don't know what's up
2240 with NT 3.5. Is this function available there or not?
2241 Does anybody really care about 3.5? :)
2244 /* Filename1 has to be always set to a valid path. Filename2 may be NULL
2245 if the source file has to be deleted.
2247 if (!fn1) {
2248 SetLastError(ERROR_INVALID_PARAMETER);
2249 return FALSE;
2252 /* This function has to be run through in order to process the name properly.
2253 If the BOOTDELAY flag is set, the file doesn't need to exist though. At least
2254 that is the behaviour on NT 4.0. The operation accepts the filenames as
2255 they are given but it can't reply with a reasonable returncode. Success
2256 means in that case success for entering the values into the registry.
2258 if(!DOSFS_GetFullName( fn1, TRUE, &full_name1 ))
2260 if(!(flag & MOVEFILE_DELAY_UNTIL_REBOOT))
2261 return FALSE;
2264 if (fn2) /* !fn2 means delete fn1 */
2266 if (DOSFS_GetFullName( fn2, TRUE, &full_name2 ))
2268 if(!(flag & MOVEFILE_DELAY_UNTIL_REBOOT))
2270 /* target exists, check if we may overwrite */
2271 if (!(flag & MOVEFILE_REPLACE_EXISTING))
2273 /* FIXME: Use right error code */
2274 SetLastError( ERROR_ACCESS_DENIED );
2275 return FALSE;
2279 else
2281 if (!DOSFS_GetFullName( fn2, FALSE, &full_name2 ))
2283 if(!(flag & MOVEFILE_DELAY_UNTIL_REBOOT))
2284 return FALSE;
2288 /* Source name and target path are valid */
2290 if (flag & MOVEFILE_DELAY_UNTIL_REBOOT)
2292 /* FIXME: (bon@elektron.ikp.physik.th-darmstadt.de 970706)
2293 Perhaps we should queue these command and execute it
2294 when exiting... What about using on_exit(2)
2296 FIXME("Please move existing file '%s' to file '%s' when Wine has finished\n",
2297 fn1, fn2);
2298 return FILE_AddBootRenameEntry( fn1, fn2, flag );
2301 if (full_name1.drive != full_name2.drive)
2303 /* use copy, if allowed */
2304 if (!(flag & MOVEFILE_COPY_ALLOWED))
2306 /* FIXME: Use right error code */
2307 SetLastError( ERROR_FILE_EXISTS );
2308 return FALSE;
2310 return CopyFileA( fn1, fn2, !(flag & MOVEFILE_REPLACE_EXISTING) );
2312 if (rename( full_name1.long_name, full_name2.long_name ) == -1)
2314 FILE_SetDosError();
2315 return FALSE;
2317 if (is_executable( full_name1.long_name ) != is_executable( full_name2.long_name ))
2319 struct stat fstat;
2320 if (stat( full_name2.long_name, &fstat ) != -1)
2322 if (is_executable( full_name2.long_name ))
2323 /* set executable bit where read bit is set */
2324 fstat.st_mode |= (fstat.st_mode & 0444) >> 2;
2325 else
2326 fstat.st_mode &= ~0111;
2327 chmod( full_name2.long_name, fstat.st_mode );
2330 return TRUE;
2332 else /* fn2 == NULL means delete source */
2334 if (flag & MOVEFILE_DELAY_UNTIL_REBOOT)
2336 if (flag & MOVEFILE_COPY_ALLOWED) {
2337 WARN("Illegal flag\n");
2338 SetLastError( ERROR_GEN_FAILURE );
2339 return FALSE;
2341 /* FIXME: (bon@elektron.ikp.physik.th-darmstadt.de 970706)
2342 Perhaps we should queue these command and execute it
2343 when exiting... What about using on_exit(2)
2345 FIXME("Please delete file '%s' when Wine has finished\n", fn1);
2346 return FILE_AddBootRenameEntry( fn1, NULL, flag );
2349 if (unlink( full_name1.long_name ) == -1)
2351 FILE_SetDosError();
2352 return FALSE;
2354 return TRUE; /* successfully deleted */
2358 /**************************************************************************
2359 * MoveFileExW (KERNEL32.@)
2361 BOOL WINAPI MoveFileExW( LPCWSTR fn1, LPCWSTR fn2, DWORD flag )
2363 LPSTR afn1 = HEAP_strdupWtoA( GetProcessHeap(), 0, fn1 );
2364 LPSTR afn2 = HEAP_strdupWtoA( GetProcessHeap(), 0, fn2 );
2365 BOOL res = MoveFileExA( afn1, afn2, flag );
2366 HeapFree( GetProcessHeap(), 0, afn1 );
2367 HeapFree( GetProcessHeap(), 0, afn2 );
2368 return res;
2372 /**************************************************************************
2373 * MoveFileA (KERNEL32.@)
2375 * Move file or directory
2377 BOOL WINAPI MoveFileA( LPCSTR fn1, LPCSTR fn2 )
2379 DOS_FULL_NAME full_name1, full_name2;
2380 struct stat fstat;
2382 TRACE("(%s,%s)\n", fn1, fn2 );
2384 if (!DOSFS_GetFullName( fn1, TRUE, &full_name1 )) return FALSE;
2385 if (DOSFS_GetFullName( fn2, TRUE, &full_name2 )) {
2386 /* The new name must not already exist */
2387 SetLastError(ERROR_ALREADY_EXISTS);
2388 return FALSE;
2390 if (!DOSFS_GetFullName( fn2, FALSE, &full_name2 )) return FALSE;
2392 if (full_name1.drive == full_name2.drive) /* move */
2393 return MoveFileExA( fn1, fn2, MOVEFILE_COPY_ALLOWED );
2395 /* copy */
2396 if (stat( full_name1.long_name, &fstat ))
2398 WARN("Invalid source file %s\n",
2399 full_name1.long_name);
2400 FILE_SetDosError();
2401 return FALSE;
2403 if (S_ISDIR(fstat.st_mode)) {
2404 /* No Move for directories across file systems */
2405 /* FIXME: Use right error code */
2406 SetLastError( ERROR_GEN_FAILURE );
2407 return FALSE;
2409 return CopyFileA(fn1, fn2, TRUE); /*fail, if exist */
2413 /**************************************************************************
2414 * MoveFileW (KERNEL32.@)
2416 BOOL WINAPI MoveFileW( LPCWSTR fn1, LPCWSTR fn2 )
2418 LPSTR afn1 = HEAP_strdupWtoA( GetProcessHeap(), 0, fn1 );
2419 LPSTR afn2 = HEAP_strdupWtoA( GetProcessHeap(), 0, fn2 );
2420 BOOL res = MoveFileA( afn1, afn2 );
2421 HeapFree( GetProcessHeap(), 0, afn1 );
2422 HeapFree( GetProcessHeap(), 0, afn2 );
2423 return res;
2427 /**************************************************************************
2428 * CopyFileA (KERNEL32.@)
2430 BOOL WINAPI CopyFileA( LPCSTR source, LPCSTR dest, BOOL fail_if_exists )
2432 HFILE h1, h2;
2433 BY_HANDLE_FILE_INFORMATION info;
2434 UINT count;
2435 BOOL ret = FALSE;
2436 int mode;
2437 char buffer[2048];
2439 if ((h1 = _lopen( source, OF_READ )) == HFILE_ERROR) return FALSE;
2440 if (!GetFileInformationByHandle( h1, &info ))
2442 CloseHandle( h1 );
2443 return FALSE;
2445 mode = (info.dwFileAttributes & FILE_ATTRIBUTE_READONLY) ? 0444 : 0666;
2446 if ((h2 = CreateFileA( dest, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
2447 fail_if_exists ? CREATE_NEW : CREATE_ALWAYS,
2448 info.dwFileAttributes, h1 )) == INVALID_HANDLE_VALUE)
2450 CloseHandle( h1 );
2451 return FALSE;
2453 while ((count = _lread( h1, buffer, sizeof(buffer) )) > 0)
2455 char *p = buffer;
2456 while (count > 0)
2458 INT res = _lwrite( h2, p, count );
2459 if (res <= 0) goto done;
2460 p += res;
2461 count -= res;
2464 ret = TRUE;
2465 done:
2466 CloseHandle( h1 );
2467 CloseHandle( h2 );
2468 return ret;
2472 /**************************************************************************
2473 * CopyFileW (KERNEL32.@)
2475 BOOL WINAPI CopyFileW( LPCWSTR source, LPCWSTR dest, BOOL fail_if_exists)
2477 LPSTR sourceA = HEAP_strdupWtoA( GetProcessHeap(), 0, source );
2478 LPSTR destA = HEAP_strdupWtoA( GetProcessHeap(), 0, dest );
2479 BOOL ret = CopyFileA( sourceA, destA, fail_if_exists );
2480 HeapFree( GetProcessHeap(), 0, sourceA );
2481 HeapFree( GetProcessHeap(), 0, destA );
2482 return ret;
2486 /**************************************************************************
2487 * CopyFileExA (KERNEL32.@)
2489 * This implementation ignores most of the extra parameters passed-in into
2490 * the "ex" version of the method and calls the CopyFile method.
2491 * It will have to be fixed eventually.
2493 BOOL WINAPI CopyFileExA(LPCSTR sourceFilename,
2494 LPCSTR destFilename,
2495 LPPROGRESS_ROUTINE progressRoutine,
2496 LPVOID appData,
2497 LPBOOL cancelFlagPointer,
2498 DWORD copyFlags)
2500 BOOL failIfExists = FALSE;
2503 * Interpret the only flag that CopyFile can interpret.
2505 if ( (copyFlags & COPY_FILE_FAIL_IF_EXISTS) != 0)
2507 failIfExists = TRUE;
2510 return CopyFileA(sourceFilename, destFilename, failIfExists);
2513 /**************************************************************************
2514 * CopyFileExW (KERNEL32.@)
2516 BOOL WINAPI CopyFileExW(LPCWSTR sourceFilename,
2517 LPCWSTR destFilename,
2518 LPPROGRESS_ROUTINE progressRoutine,
2519 LPVOID appData,
2520 LPBOOL cancelFlagPointer,
2521 DWORD copyFlags)
2523 LPSTR sourceA = HEAP_strdupWtoA( GetProcessHeap(), 0, sourceFilename );
2524 LPSTR destA = HEAP_strdupWtoA( GetProcessHeap(), 0, destFilename );
2526 BOOL ret = CopyFileExA(sourceA,
2527 destA,
2528 progressRoutine,
2529 appData,
2530 cancelFlagPointer,
2531 copyFlags);
2533 HeapFree( GetProcessHeap(), 0, sourceA );
2534 HeapFree( GetProcessHeap(), 0, destA );
2536 return ret;
2540 /***********************************************************************
2541 * SetFileTime (KERNEL32.@)
2543 BOOL WINAPI SetFileTime( HANDLE hFile,
2544 const FILETIME *lpCreationTime,
2545 const FILETIME *lpLastAccessTime,
2546 const FILETIME *lpLastWriteTime )
2548 BOOL ret;
2549 SERVER_START_REQ( set_file_time )
2551 req->handle = hFile;
2552 if (lpLastAccessTime)
2553 RtlTimeToSecondsSince1970( lpLastAccessTime, (DWORD *)&req->access_time );
2554 else
2555 req->access_time = 0; /* FIXME */
2556 if (lpLastWriteTime)
2557 RtlTimeToSecondsSince1970( lpLastWriteTime, (DWORD *)&req->write_time );
2558 else
2559 req->write_time = 0; /* FIXME */
2560 ret = !wine_server_call_err( req );
2562 SERVER_END_REQ;
2563 return ret;
2567 /**************************************************************************
2568 * LockFile (KERNEL32.@)
2570 BOOL WINAPI LockFile( HANDLE hFile, DWORD dwFileOffsetLow, DWORD dwFileOffsetHigh,
2571 DWORD nNumberOfBytesToLockLow, DWORD nNumberOfBytesToLockHigh )
2573 BOOL ret;
2574 SERVER_START_REQ( lock_file )
2576 req->handle = hFile;
2577 req->offset_low = dwFileOffsetLow;
2578 req->offset_high = dwFileOffsetHigh;
2579 req->count_low = nNumberOfBytesToLockLow;
2580 req->count_high = nNumberOfBytesToLockHigh;
2581 ret = !wine_server_call_err( req );
2583 SERVER_END_REQ;
2584 return ret;
2587 /**************************************************************************
2588 * LockFileEx [KERNEL32.@]
2590 * Locks a byte range within an open file for shared or exclusive access.
2592 * RETURNS
2593 * success: TRUE
2594 * failure: FALSE
2596 * NOTES
2597 * Per Microsoft docs, the third parameter (reserved) must be set to 0.
2599 BOOL WINAPI LockFileEx( HANDLE hFile, DWORD flags, DWORD reserved,
2600 DWORD nNumberOfBytesToLockLow, DWORD nNumberOfBytesToLockHigh,
2601 LPOVERLAPPED pOverlapped )
2603 FIXME("hFile=%d,flags=%ld,reserved=%ld,lowbytes=%ld,highbytes=%ld,overlapped=%p: stub.\n",
2604 hFile, flags, reserved, nNumberOfBytesToLockLow, nNumberOfBytesToLockHigh,
2605 pOverlapped);
2606 if (reserved == 0)
2607 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
2608 else
2610 ERR("reserved == %ld: Supposed to be 0??\n", reserved);
2611 SetLastError(ERROR_INVALID_PARAMETER);
2614 return FALSE;
2618 /**************************************************************************
2619 * UnlockFile (KERNEL32.@)
2621 BOOL WINAPI UnlockFile( HANDLE hFile, DWORD dwFileOffsetLow, DWORD dwFileOffsetHigh,
2622 DWORD nNumberOfBytesToUnlockLow, DWORD nNumberOfBytesToUnlockHigh )
2624 BOOL ret;
2625 SERVER_START_REQ( unlock_file )
2627 req->handle = hFile;
2628 req->offset_low = dwFileOffsetLow;
2629 req->offset_high = dwFileOffsetHigh;
2630 req->count_low = nNumberOfBytesToUnlockLow;
2631 req->count_high = nNumberOfBytesToUnlockHigh;
2632 ret = !wine_server_call_err( req );
2634 SERVER_END_REQ;
2635 return ret;
2639 /**************************************************************************
2640 * UnlockFileEx (KERNEL32.@)
2642 BOOL WINAPI UnlockFileEx(
2643 HFILE hFile,
2644 DWORD dwReserved,
2645 DWORD nNumberOfBytesToUnlockLow,
2646 DWORD nNumberOfBytesToUnlockHigh,
2647 LPOVERLAPPED lpOverlapped
2650 FIXME("hFile=%d,reserved=%ld,lowbytes=%ld,highbytes=%ld,overlapped=%p: stub.\n",
2651 hFile, dwReserved, nNumberOfBytesToUnlockLow, nNumberOfBytesToUnlockHigh,
2652 lpOverlapped);
2653 if (dwReserved == 0)
2654 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
2655 else
2657 ERR("reserved == %ld: Supposed to be 0??\n", dwReserved);
2658 SetLastError(ERROR_INVALID_PARAMETER);
2661 return FALSE;
2665 #if 0
2667 struct DOS_FILE_LOCK {
2668 struct DOS_FILE_LOCK * next;
2669 DWORD base;
2670 DWORD len;
2671 DWORD processId;
2672 FILE_OBJECT * dos_file;
2673 /* char * unix_name;*/
2676 typedef struct DOS_FILE_LOCK DOS_FILE_LOCK;
2678 static DOS_FILE_LOCK *locks = NULL;
2679 static void DOS_RemoveFileLocks(FILE_OBJECT *file);
2682 /* Locks need to be mirrored because unix file locking is based
2683 * on the pid. Inside of wine there can be multiple WINE processes
2684 * that share the same unix pid.
2685 * Read's and writes should check these locks also - not sure
2686 * how critical that is at this point (FIXME).
2689 static BOOL DOS_AddLock(FILE_OBJECT *file, struct flock *f)
2691 DOS_FILE_LOCK *curr;
2692 DWORD processId;
2694 processId = GetCurrentProcessId();
2696 /* check if lock overlaps a current lock for the same file */
2697 #if 0
2698 for (curr = locks; curr; curr = curr->next) {
2699 if (strcmp(curr->unix_name, file->unix_name) == 0) {
2700 if ((f->l_start == curr->base) && (f->l_len == curr->len))
2701 return TRUE;/* region is identic */
2702 if ((f->l_start < (curr->base + curr->len)) &&
2703 ((f->l_start + f->l_len) > curr->base)) {
2704 /* region overlaps */
2705 return FALSE;
2709 #endif
2711 curr = HeapAlloc( GetProcessHeap(), 0, sizeof(DOS_FILE_LOCK) );
2712 curr->processId = GetCurrentProcessId();
2713 curr->base = f->l_start;
2714 curr->len = f->l_len;
2715 /* curr->unix_name = HEAP_strdupA( GetProcessHeap(), 0, file->unix_name);*/
2716 curr->next = locks;
2717 curr->dos_file = file;
2718 locks = curr;
2719 return TRUE;
2722 static void DOS_RemoveFileLocks(FILE_OBJECT *file)
2724 DWORD processId;
2725 DOS_FILE_LOCK **curr;
2726 DOS_FILE_LOCK *rem;
2728 processId = GetCurrentProcessId();
2729 curr = &locks;
2730 while (*curr) {
2731 if ((*curr)->dos_file == file) {
2732 rem = *curr;
2733 *curr = (*curr)->next;
2734 /* HeapFree( GetProcessHeap(), 0, rem->unix_name );*/
2735 HeapFree( GetProcessHeap(), 0, rem );
2737 else
2738 curr = &(*curr)->next;
2742 static BOOL DOS_RemoveLock(FILE_OBJECT *file, struct flock *f)
2744 DWORD processId;
2745 DOS_FILE_LOCK **curr;
2746 DOS_FILE_LOCK *rem;
2748 processId = GetCurrentProcessId();
2749 for (curr = &locks; *curr; curr = &(*curr)->next) {
2750 if ((*curr)->processId == processId &&
2751 (*curr)->dos_file == file &&
2752 (*curr)->base == f->l_start &&
2753 (*curr)->len == f->l_len) {
2754 /* this is the same lock */
2755 rem = *curr;
2756 *curr = (*curr)->next;
2757 /* HeapFree( GetProcessHeap(), 0, rem->unix_name );*/
2758 HeapFree( GetProcessHeap(), 0, rem );
2759 return TRUE;
2762 /* no matching lock found */
2763 return FALSE;
2767 /**************************************************************************
2768 * LockFile (KERNEL32.@)
2770 BOOL WINAPI LockFile(
2771 HFILE hFile,DWORD dwFileOffsetLow,DWORD dwFileOffsetHigh,
2772 DWORD nNumberOfBytesToLockLow,DWORD nNumberOfBytesToLockHigh )
2774 struct flock f;
2775 FILE_OBJECT *file;
2777 TRACE("handle %d offsetlow=%ld offsethigh=%ld nbyteslow=%ld nbyteshigh=%ld\n",
2778 hFile, dwFileOffsetLow, dwFileOffsetHigh,
2779 nNumberOfBytesToLockLow, nNumberOfBytesToLockHigh);
2781 if (dwFileOffsetHigh || nNumberOfBytesToLockHigh) {
2782 FIXME("Unimplemented bytes > 32bits\n");
2783 return FALSE;
2786 f.l_start = dwFileOffsetLow;
2787 f.l_len = nNumberOfBytesToLockLow;
2788 f.l_whence = SEEK_SET;
2789 f.l_pid = 0;
2790 f.l_type = F_WRLCK;
2792 if (!(file = FILE_GetFile(hFile,0,NULL))) return FALSE;
2794 /* shadow locks internally */
2795 if (!DOS_AddLock(file, &f)) {
2796 SetLastError( ERROR_LOCK_VIOLATION );
2797 return FALSE;
2800 /* FIXME: Unix locking commented out for now, doesn't work with Excel */
2801 #ifdef USE_UNIX_LOCKS
2802 if (fcntl(file->unix_handle, F_SETLK, &f) == -1) {
2803 if (errno == EACCES || errno == EAGAIN) {
2804 SetLastError( ERROR_LOCK_VIOLATION );
2806 else {
2807 FILE_SetDosError();
2809 /* remove our internal copy of the lock */
2810 DOS_RemoveLock(file, &f);
2811 return FALSE;
2813 #endif
2814 return TRUE;
2818 /**************************************************************************
2819 * UnlockFile (KERNEL32.@)
2821 BOOL WINAPI UnlockFile(
2822 HFILE hFile,DWORD dwFileOffsetLow,DWORD dwFileOffsetHigh,
2823 DWORD nNumberOfBytesToUnlockLow,DWORD nNumberOfBytesToUnlockHigh )
2825 FILE_OBJECT *file;
2826 struct flock f;
2828 TRACE("handle %d offsetlow=%ld offsethigh=%ld nbyteslow=%ld nbyteshigh=%ld\n",
2829 hFile, dwFileOffsetLow, dwFileOffsetHigh,
2830 nNumberOfBytesToUnlockLow, nNumberOfBytesToUnlockHigh);
2832 if (dwFileOffsetHigh || nNumberOfBytesToUnlockHigh) {
2833 WARN("Unimplemented bytes > 32bits\n");
2834 return FALSE;
2837 f.l_start = dwFileOffsetLow;
2838 f.l_len = nNumberOfBytesToUnlockLow;
2839 f.l_whence = SEEK_SET;
2840 f.l_pid = 0;
2841 f.l_type = F_UNLCK;
2843 if (!(file = FILE_GetFile(hFile,0,NULL))) return FALSE;
2845 DOS_RemoveLock(file, &f); /* ok if fails - may be another wine */
2847 /* FIXME: Unix locking commented out for now, doesn't work with Excel */
2848 #ifdef USE_UNIX_LOCKS
2849 if (fcntl(file->unix_handle, F_SETLK, &f) == -1) {
2850 FILE_SetDosError();
2851 return FALSE;
2853 #endif
2854 return TRUE;
2856 #endif
2858 /**************************************************************************
2859 * GetFileAttributesExA [KERNEL32.@]
2861 BOOL WINAPI GetFileAttributesExA(
2862 LPCSTR lpFileName, GET_FILEEX_INFO_LEVELS fInfoLevelId,
2863 LPVOID lpFileInformation)
2865 DOS_FULL_NAME full_name;
2866 BY_HANDLE_FILE_INFORMATION info;
2868 if (lpFileName == NULL) return FALSE;
2869 if (lpFileInformation == NULL) return FALSE;
2871 if (fInfoLevelId == GetFileExInfoStandard) {
2872 LPWIN32_FILE_ATTRIBUTE_DATA lpFad =
2873 (LPWIN32_FILE_ATTRIBUTE_DATA) lpFileInformation;
2874 if (!DOSFS_GetFullName( lpFileName, TRUE, &full_name )) return FALSE;
2875 if (!FILE_Stat( full_name.long_name, &info )) return FALSE;
2877 lpFad->dwFileAttributes = info.dwFileAttributes;
2878 lpFad->ftCreationTime = info.ftCreationTime;
2879 lpFad->ftLastAccessTime = info.ftLastAccessTime;
2880 lpFad->ftLastWriteTime = info.ftLastWriteTime;
2881 lpFad->nFileSizeHigh = info.nFileSizeHigh;
2882 lpFad->nFileSizeLow = info.nFileSizeLow;
2884 else {
2885 FIXME("invalid info level %d!\n", fInfoLevelId);
2886 return FALSE;
2889 return TRUE;
2893 /**************************************************************************
2894 * GetFileAttributesExW [KERNEL32.@]
2896 BOOL WINAPI GetFileAttributesExW(
2897 LPCWSTR lpFileName, GET_FILEEX_INFO_LEVELS fInfoLevelId,
2898 LPVOID lpFileInformation)
2900 LPSTR nameA = HEAP_strdupWtoA( GetProcessHeap(), 0, lpFileName );
2901 BOOL res =
2902 GetFileAttributesExA( nameA, fInfoLevelId, lpFileInformation);
2903 HeapFree( GetProcessHeap(), 0, nameA );
2904 return res;