Get the ldconfig check to work for bash shells.
[wine/dibdrv.git] / files / file.c
blob07ea93a607c178ab3e100770a9da52e25095fc8b
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 "wine/server.h"
56 #include "drive.h"
57 #include "file.h"
58 #include "async.h"
59 #include "heap.h"
60 #include "msdos.h"
61 #include "wincon.h"
63 #include "smb.h"
64 #include "wine/debug.h"
66 WINE_DEFAULT_DEBUG_CHANNEL(file);
68 #if defined(MAP_ANONYMOUS) && !defined(MAP_ANON)
69 #define MAP_ANON MAP_ANONYMOUS
70 #endif
72 /* Size of per-process table of DOS handles */
73 #define DOS_TABLE_SIZE 256
75 /* Macro to derive file offset from OVERLAPPED struct */
76 #define OVERLAPPED_OFFSET(overlapped) ((off_t) (overlapped)->Offset + ((off_t) (overlapped)->OffsetHigh << 32))
78 static HANDLE dos_handles[DOS_TABLE_SIZE];
80 mode_t FILE_umask;
82 extern HANDLE WINAPI FILE_SmbOpen(LPCSTR name);
84 /***********************************************************************
85 * Asynchronous file I/O *
87 static DWORD fileio_get_async_status (const async_private *ovp);
88 static DWORD fileio_get_async_count (const async_private *ovp);
89 static void fileio_set_async_status (async_private *ovp, const DWORD status);
90 static void CALLBACK fileio_call_completion_func (ULONG_PTR data);
91 static void fileio_async_cleanup (async_private *ovp);
93 static async_ops fileio_async_ops =
95 fileio_get_async_status, /* get_status */
96 fileio_set_async_status, /* set_status */
97 fileio_get_async_count, /* get_count */
98 fileio_call_completion_func, /* call_completion */
99 fileio_async_cleanup /* cleanup */
102 static async_ops fileio_nocomp_async_ops =
104 fileio_get_async_status, /* get_status */
105 fileio_set_async_status, /* set_status */
106 fileio_get_async_count, /* get_count */
107 NULL, /* call_completion */
108 fileio_async_cleanup /* cleanup */
111 typedef struct async_fileio
113 struct async_private async;
114 LPOVERLAPPED lpOverlapped;
115 LPOVERLAPPED_COMPLETION_ROUTINE completion_func;
116 char *buffer;
117 int count;
118 } async_fileio;
120 static DWORD fileio_get_async_status (const struct async_private *ovp)
122 return ((async_fileio*) ovp)->lpOverlapped->Internal;
125 static void fileio_set_async_status (async_private *ovp, const DWORD status)
127 ((async_fileio*) ovp)->lpOverlapped->Internal = status;
130 static DWORD fileio_get_async_count (const struct async_private *ovp)
132 async_fileio *fileio = (async_fileio*) ovp;
133 DWORD ret = fileio->count - fileio->lpOverlapped->InternalHigh;
134 return (ret < 0 ? 0 : ret);
137 static void CALLBACK fileio_call_completion_func (ULONG_PTR data)
139 async_fileio *ovp = (async_fileio*) data;
140 TRACE ("data: %p\n", ovp);
142 ovp->completion_func( ovp->lpOverlapped->Internal,
143 ovp->lpOverlapped->InternalHigh,
144 ovp->lpOverlapped );
146 fileio_async_cleanup ( &ovp->async );
149 static void fileio_async_cleanup ( struct async_private *ovp )
151 HeapFree ( GetProcessHeap(), 0, ovp );
154 /***********************************************************************
155 * FILE_ConvertOFMode
157 * Convert OF_* mode into flags for CreateFile.
159 static void FILE_ConvertOFMode( INT mode, DWORD *access, DWORD *sharing )
161 switch(mode & 0x03)
163 case OF_READ: *access = GENERIC_READ; break;
164 case OF_WRITE: *access = GENERIC_WRITE; break;
165 case OF_READWRITE: *access = GENERIC_READ | GENERIC_WRITE; break;
166 default: *access = 0; break;
168 switch(mode & 0x70)
170 case OF_SHARE_EXCLUSIVE: *sharing = 0; break;
171 case OF_SHARE_DENY_WRITE: *sharing = FILE_SHARE_READ; break;
172 case OF_SHARE_DENY_READ: *sharing = FILE_SHARE_WRITE; break;
173 case OF_SHARE_DENY_NONE:
174 case OF_SHARE_COMPAT:
175 default: *sharing = FILE_SHARE_READ | FILE_SHARE_WRITE; break;
180 /***********************************************************************
181 * FILE_strcasecmp
183 * locale-independent case conversion for file I/O
185 int FILE_strcasecmp( const char *str1, const char *str2 )
187 for (;;)
189 int ret = FILE_toupper(*str1) - FILE_toupper(*str2);
190 if (ret || !*str1) return ret;
191 str1++;
192 str2++;
197 /***********************************************************************
198 * FILE_strncasecmp
200 * locale-independent case conversion for file I/O
202 int FILE_strncasecmp( const char *str1, const char *str2, int len )
204 int ret = 0;
205 for ( ; len > 0; len--, str1++, str2++)
206 if ((ret = FILE_toupper(*str1) - FILE_toupper(*str2)) || !*str1) break;
207 return ret;
211 /***********************************************************************
212 * FILE_SetDosError
214 * Set the DOS error code from errno.
216 void FILE_SetDosError(void)
218 int save_errno = errno; /* errno gets overwritten by printf */
220 TRACE("errno = %d %s\n", errno, strerror(errno));
221 switch (save_errno)
223 case EAGAIN:
224 SetLastError( ERROR_SHARING_VIOLATION );
225 break;
226 case EBADF:
227 SetLastError( ERROR_INVALID_HANDLE );
228 break;
229 case ENOSPC:
230 SetLastError( ERROR_HANDLE_DISK_FULL );
231 break;
232 case EACCES:
233 case EPERM:
234 case EROFS:
235 SetLastError( ERROR_ACCESS_DENIED );
236 break;
237 case EBUSY:
238 SetLastError( ERROR_LOCK_VIOLATION );
239 break;
240 case ENOENT:
241 SetLastError( ERROR_FILE_NOT_FOUND );
242 break;
243 case EISDIR:
244 SetLastError( ERROR_CANNOT_MAKE );
245 break;
246 case ENFILE:
247 case EMFILE:
248 SetLastError( ERROR_NO_MORE_FILES );
249 break;
250 case EEXIST:
251 SetLastError( ERROR_FILE_EXISTS );
252 break;
253 case EINVAL:
254 case ESPIPE:
255 SetLastError( ERROR_SEEK );
256 break;
257 case ENOTEMPTY:
258 SetLastError( ERROR_DIR_NOT_EMPTY );
259 break;
260 case ENOEXEC:
261 SetLastError( ERROR_BAD_FORMAT );
262 break;
263 default:
264 WARN("unknown file error: %s\n", strerror(save_errno) );
265 SetLastError( ERROR_GEN_FAILURE );
266 break;
268 errno = save_errno;
272 /***********************************************************************
273 * FILE_DupUnixHandle
275 * Duplicate a Unix handle into a task handle.
276 * Returns 0 on failure.
278 HANDLE FILE_DupUnixHandle( int fd, DWORD access, BOOL inherit )
280 HANDLE ret;
282 wine_server_send_fd( fd );
284 SERVER_START_REQ( alloc_file_handle )
286 req->access = access;
287 req->inherit = inherit;
288 req->fd = fd;
289 wine_server_call( req );
290 ret = reply->handle;
292 SERVER_END_REQ;
293 return ret;
297 /***********************************************************************
298 * FILE_GetUnixHandleType
300 * Retrieve the Unix handle corresponding to a file handle.
301 * Returns -1 on failure.
303 static int FILE_GetUnixHandleType( HANDLE handle, DWORD access, enum fd_type *type, int *flags )
305 int ret, fd = -1;
307 ret = wine_server_handle_to_fd( handle, access, &fd, type, flags );
308 if (ret) SetLastError( RtlNtStatusToDosError(ret) );
309 return fd;
312 /***********************************************************************
313 * FILE_GetUnixHandle
315 * Retrieve the Unix handle corresponding to a file handle.
316 * Returns -1 on failure.
318 int FILE_GetUnixHandle( HANDLE handle, DWORD access )
320 return FILE_GetUnixHandleType( handle, access, NULL, NULL );
323 /*************************************************************************
324 * FILE_OpenConsole
326 * Open a handle to the current process console.
327 * Returns 0 on failure.
329 static HANDLE FILE_OpenConsole( BOOL output, DWORD access, DWORD sharing, LPSECURITY_ATTRIBUTES sa )
331 HANDLE ret;
333 SERVER_START_REQ( open_console )
335 req->from = output;
336 req->access = access;
337 req->share = sharing;
338 req->inherit = (sa && (sa->nLength>=sizeof(*sa)) && sa->bInheritHandle);
339 SetLastError(0);
340 wine_server_call_err( req );
341 ret = reply->handle;
343 SERVER_END_REQ;
344 return ret;
348 /***********************************************************************
349 * FILE_CreateFile
351 * Implementation of CreateFile. Takes a Unix path name.
352 * Returns 0 on failure.
354 HANDLE FILE_CreateFile( LPCSTR filename, DWORD access, DWORD sharing,
355 LPSECURITY_ATTRIBUTES sa, DWORD creation,
356 DWORD attributes, HANDLE template, BOOL fail_read_only,
357 UINT drive_type )
359 unsigned int err;
360 HANDLE ret;
362 for (;;)
364 SERVER_START_REQ( create_file )
366 req->access = access;
367 req->inherit = (sa && (sa->nLength>=sizeof(*sa)) && sa->bInheritHandle);
368 req->sharing = sharing;
369 req->create = creation;
370 req->attrs = attributes;
371 req->drive_type = drive_type;
372 wine_server_add_data( req, filename, strlen(filename) );
373 SetLastError(0);
374 err = wine_server_call( req );
375 ret = reply->handle;
377 SERVER_END_REQ;
379 /* If write access failed, retry without GENERIC_WRITE */
381 if (!ret && !fail_read_only && (access & GENERIC_WRITE))
383 if ((err == STATUS_MEDIA_WRITE_PROTECTED) || (err == STATUS_ACCESS_DENIED))
385 TRACE("Write access failed for file '%s', trying without "
386 "write access\n", filename);
387 access &= ~GENERIC_WRITE;
388 continue;
392 if (err) SetLastError( RtlNtStatusToDosError(err) );
394 if (!ret) WARN("Unable to create file '%s' (GLE %ld)\n", filename, GetLastError());
395 return ret;
400 /***********************************************************************
401 * FILE_CreateDevice
403 * Same as FILE_CreateFile but for a device
404 * Returns 0 on failure.
406 HANDLE FILE_CreateDevice( int client_id, DWORD access, LPSECURITY_ATTRIBUTES sa )
408 HANDLE ret;
409 SERVER_START_REQ( create_device )
411 req->access = access;
412 req->inherit = (sa && (sa->nLength>=sizeof(*sa)) && sa->bInheritHandle);
413 req->id = client_id;
414 SetLastError(0);
415 wine_server_call_err( req );
416 ret = reply->handle;
418 SERVER_END_REQ;
419 return ret;
422 static HANDLE FILE_OpenPipe(LPCSTR name, DWORD access)
424 WCHAR buffer[MAX_PATH];
425 HANDLE ret;
426 DWORD len = 0;
428 if (name && !(len = MultiByteToWideChar( CP_ACP, 0, name, strlen(name), buffer, MAX_PATH )))
430 SetLastError( ERROR_FILENAME_EXCED_RANGE );
431 return 0;
433 SERVER_START_REQ( open_named_pipe )
435 req->access = access;
436 SetLastError(0);
437 wine_server_add_data( req, buffer, len * sizeof(WCHAR) );
438 wine_server_call_err( req );
439 ret = reply->handle;
441 SERVER_END_REQ;
442 TRACE("Returned %d\n",ret);
443 return ret;
446 /*************************************************************************
447 * CreateFileA [KERNEL32.@] Creates or opens a file or other object
449 * Creates or opens an object, and returns a handle that can be used to
450 * access that object.
452 * PARAMS
454 * filename [in] pointer to filename to be accessed
455 * access [in] access mode requested
456 * sharing [in] share mode
457 * sa [in] pointer to security attributes
458 * creation [in] how to create the file
459 * attributes [in] attributes for newly created file
460 * template [in] handle to file with extended attributes to copy
462 * RETURNS
463 * Success: Open handle to specified file
464 * Failure: INVALID_HANDLE_VALUE
466 * NOTES
467 * Should call SetLastError() on failure.
469 * BUGS
471 * Doesn't support character devices, template files, or a
472 * lot of the 'attributes' flags yet.
474 HANDLE WINAPI CreateFileA( LPCSTR filename, DWORD access, DWORD sharing,
475 LPSECURITY_ATTRIBUTES sa, DWORD creation,
476 DWORD attributes, HANDLE template )
478 DOS_FULL_NAME full_name;
479 HANDLE ret;
481 if (!filename)
483 SetLastError( ERROR_INVALID_PARAMETER );
484 return INVALID_HANDLE_VALUE;
486 TRACE("%s %s%s%s%s%s%s%s\n",filename,
487 ((access & GENERIC_READ)==GENERIC_READ)?"GENERIC_READ ":"",
488 ((access & GENERIC_WRITE)==GENERIC_WRITE)?"GENERIC_WRITE ":"",
489 (!access)?"QUERY_ACCESS ":"",
490 ((sharing & FILE_SHARE_READ)==FILE_SHARE_READ)?"FILE_SHARE_READ ":"",
491 ((sharing & FILE_SHARE_WRITE)==FILE_SHARE_WRITE)?"FILE_SHARE_WRITE ":"",
492 ((sharing & FILE_SHARE_DELETE)==FILE_SHARE_DELETE)?"FILE_SHARE_DELETE ":"",
493 (creation ==CREATE_NEW)?"CREATE_NEW":
494 (creation ==CREATE_ALWAYS)?"CREATE_ALWAYS ":
495 (creation ==OPEN_EXISTING)?"OPEN_EXISTING ":
496 (creation ==OPEN_ALWAYS)?"OPEN_ALWAYS ":
497 (creation ==TRUNCATE_EXISTING)?"TRUNCATE_EXISTING ":"");
499 /* If the name starts with '\\?\', ignore the first 4 chars. */
500 if (!strncmp(filename, "\\\\?\\", 4))
502 filename += 4;
503 if (!strncmp(filename, "UNC\\", 4))
505 FIXME("UNC name (%s) not supported.\n", filename );
506 SetLastError( ERROR_PATH_NOT_FOUND );
507 return INVALID_HANDLE_VALUE;
511 if (!strncmp(filename, "\\\\.\\", 4)) {
512 if(!strncasecmp(&filename[4],"pipe\\",5))
514 TRACE("Opening a pipe: %s\n",filename);
515 ret = FILE_OpenPipe(filename,access);
516 goto done;
518 else if (isalpha(filename[4]) && filename[5] == ':' && filename[6] == '\0')
520 ret = FILE_CreateDevice( (toupper(filename[4]) - 'A') | 0x20000, access, sa );
521 goto done;
523 else if (!DOSFS_GetDevice( filename ))
525 ret = DEVICE_Open( filename+4, access, sa );
526 goto done;
528 else
529 filename+=4; /* fall into DOSFS_Device case below */
532 /* If the name still starts with '\\', it's a UNC name. */
533 if (!strncmp(filename, "\\\\", 2))
535 ret = SMB_CreateFileA(filename, access, sharing, sa, creation, attributes, template );
536 goto done;
539 /* If the name contains a DOS wild card (* or ?), do no create a file */
540 if(strchr(filename,'*') || strchr(filename,'?'))
541 return INVALID_HANDLE_VALUE;
543 /* Open a console for CONIN$ or CONOUT$ */
544 if (!strcasecmp(filename, "CONIN$"))
546 ret = FILE_OpenConsole( FALSE, access, sharing, sa );
547 goto done;
549 if (!strcasecmp(filename, "CONOUT$"))
551 ret = FILE_OpenConsole( TRUE, access, sharing, sa );
552 goto done;
555 if (DOSFS_GetDevice( filename ))
557 TRACE("opening device '%s'\n", filename );
559 if (!(ret = DOSFS_OpenDevice( filename, access, attributes, sa )))
561 /* Do not silence this please. It is a critical error. -MM */
562 ERR("Couldn't open device '%s'!\n",filename);
563 SetLastError( ERROR_FILE_NOT_FOUND );
565 goto done;
568 /* check for filename, don't check for last entry if creating */
569 if (!DOSFS_GetFullName( filename,
570 (creation == OPEN_EXISTING) ||
571 (creation == TRUNCATE_EXISTING),
572 &full_name )) {
573 WARN("Unable to get full filename from '%s' (GLE %ld)\n",
574 filename, GetLastError());
575 return INVALID_HANDLE_VALUE;
578 ret = FILE_CreateFile( full_name.long_name, access, sharing,
579 sa, creation, attributes, template,
580 DRIVE_GetFlags(full_name.drive) & DRIVE_FAIL_READ_ONLY,
581 GetDriveTypeA( full_name.short_name ) );
582 done:
583 if (!ret) ret = INVALID_HANDLE_VALUE;
584 return ret;
589 /*************************************************************************
590 * CreateFileW (KERNEL32.@)
592 HANDLE WINAPI CreateFileW( LPCWSTR filename, DWORD access, DWORD sharing,
593 LPSECURITY_ATTRIBUTES sa, DWORD creation,
594 DWORD attributes, HANDLE template)
596 LPSTR afn = HEAP_strdupWtoA( GetProcessHeap(), 0, filename );
597 HANDLE res = CreateFileA( afn, access, sharing, sa, creation, attributes, template );
598 HeapFree( GetProcessHeap(), 0, afn );
599 return res;
603 /***********************************************************************
604 * FILE_FillInfo
606 * Fill a file information from a struct stat.
608 static void FILE_FillInfo( struct stat *st, BY_HANDLE_FILE_INFORMATION *info )
610 if (S_ISDIR(st->st_mode))
611 info->dwFileAttributes = FILE_ATTRIBUTE_DIRECTORY;
612 else
613 info->dwFileAttributes = FILE_ATTRIBUTE_ARCHIVE;
614 if (!(st->st_mode & S_IWUSR))
615 info->dwFileAttributes |= FILE_ATTRIBUTE_READONLY;
617 RtlSecondsSince1970ToTime( st->st_mtime, &info->ftCreationTime );
618 RtlSecondsSince1970ToTime( st->st_mtime, &info->ftLastWriteTime );
619 RtlSecondsSince1970ToTime( st->st_atime, &info->ftLastAccessTime );
621 info->dwVolumeSerialNumber = 0; /* FIXME */
622 info->nFileSizeHigh = 0;
623 info->nFileSizeLow = 0;
624 if (!S_ISDIR(st->st_mode)) {
625 info->nFileSizeHigh = st->st_size >> 32;
626 info->nFileSizeLow = st->st_size & 0xffffffff;
628 info->nNumberOfLinks = st->st_nlink;
629 info->nFileIndexHigh = 0;
630 info->nFileIndexLow = st->st_ino;
634 /***********************************************************************
635 * FILE_Stat
637 * Stat a Unix path name. Return TRUE if OK.
639 BOOL FILE_Stat( LPCSTR unixName, BY_HANDLE_FILE_INFORMATION *info )
641 struct stat st;
643 if (lstat( unixName, &st ) == -1)
645 FILE_SetDosError();
646 return FALSE;
648 if (!S_ISLNK(st.st_mode)) FILE_FillInfo( &st, info );
649 else
651 /* do a "real" stat to find out
652 about the type of the symlink destination */
653 if (stat( unixName, &st ) == -1)
655 FILE_SetDosError();
656 return FALSE;
658 FILE_FillInfo( &st, info );
659 info->dwFileAttributes |= FILE_ATTRIBUTE_SYMLINK;
661 return TRUE;
665 /***********************************************************************
666 * GetFileInformationByHandle (KERNEL32.@)
668 DWORD WINAPI GetFileInformationByHandle( HANDLE hFile,
669 BY_HANDLE_FILE_INFORMATION *info )
671 DWORD ret;
672 if (!info) return 0;
674 SERVER_START_REQ( get_file_info )
676 req->handle = hFile;
677 if ((ret = !wine_server_call_err( req )))
679 /* FIXME: which file types are supported ?
680 * Serial ports (FILE_TYPE_CHAR) are not,
681 * and MSDN also says that pipes are not supported.
682 * FILE_TYPE_REMOTE seems to be supported according to
683 * MSDN q234741.txt */
684 if ((reply->type == FILE_TYPE_DISK) || (reply->type == FILE_TYPE_REMOTE))
686 RtlSecondsSince1970ToTime( reply->write_time, &info->ftCreationTime );
687 RtlSecondsSince1970ToTime( reply->write_time, &info->ftLastWriteTime );
688 RtlSecondsSince1970ToTime( reply->access_time, &info->ftLastAccessTime );
689 info->dwFileAttributes = reply->attr;
690 info->dwVolumeSerialNumber = reply->serial;
691 info->nFileSizeHigh = reply->size_high;
692 info->nFileSizeLow = reply->size_low;
693 info->nNumberOfLinks = reply->links;
694 info->nFileIndexHigh = reply->index_high;
695 info->nFileIndexLow = reply->index_low;
697 else
699 SetLastError(ERROR_NOT_SUPPORTED);
700 ret = 0;
704 SERVER_END_REQ;
705 return ret;
709 /**************************************************************************
710 * GetFileAttributes (KERNEL.420)
712 DWORD WINAPI GetFileAttributes16( LPCSTR name )
714 return GetFileAttributesA( name );
718 /**************************************************************************
719 * GetFileAttributesA (KERNEL32.@)
721 DWORD WINAPI GetFileAttributesA( LPCSTR name )
723 DOS_FULL_NAME full_name;
724 BY_HANDLE_FILE_INFORMATION info;
726 if (name == NULL)
728 SetLastError( ERROR_INVALID_PARAMETER );
729 return -1;
731 if (!DOSFS_GetFullName( name, TRUE, &full_name) )
732 return -1;
733 if (!FILE_Stat( full_name.long_name, &info )) return -1;
734 return info.dwFileAttributes;
738 /**************************************************************************
739 * GetFileAttributesW (KERNEL32.@)
741 DWORD WINAPI GetFileAttributesW( LPCWSTR name )
743 LPSTR nameA = HEAP_strdupWtoA( GetProcessHeap(), 0, name );
744 DWORD res = GetFileAttributesA( nameA );
745 HeapFree( GetProcessHeap(), 0, nameA );
746 return res;
750 /**************************************************************************
751 * SetFileAttributes (KERNEL.421)
753 BOOL16 WINAPI SetFileAttributes16( LPCSTR lpFileName, DWORD attributes )
755 return SetFileAttributesA( lpFileName, attributes );
759 /**************************************************************************
760 * SetFileAttributesA (KERNEL32.@)
762 BOOL WINAPI SetFileAttributesA(LPCSTR lpFileName, DWORD attributes)
764 struct stat buf;
765 DOS_FULL_NAME full_name;
767 if (!DOSFS_GetFullName( lpFileName, TRUE, &full_name ))
768 return FALSE;
770 TRACE("(%s,%lx)\n",lpFileName,attributes);
771 if (attributes & FILE_ATTRIBUTE_NORMAL) {
772 attributes &= ~FILE_ATTRIBUTE_NORMAL;
773 if (attributes)
774 FIXME("(%s):%lx illegal combination with FILE_ATTRIBUTE_NORMAL.\n", lpFileName,attributes);
776 if(stat(full_name.long_name,&buf)==-1)
778 FILE_SetDosError();
779 return FALSE;
781 if (attributes & FILE_ATTRIBUTE_READONLY)
783 if(S_ISDIR(buf.st_mode))
784 /* FIXME */
785 WARN("FILE_ATTRIBUTE_READONLY ignored for directory.\n");
786 else
787 buf.st_mode &= ~0222; /* octal!, clear write permission bits */
788 attributes &= ~FILE_ATTRIBUTE_READONLY;
790 else
792 /* add write permission */
793 buf.st_mode |= (0600 | ((buf.st_mode & 044) >> 1)) & (~FILE_umask);
795 if (attributes & FILE_ATTRIBUTE_DIRECTORY)
797 if (!S_ISDIR(buf.st_mode))
798 FIXME("SetFileAttributes expected the file '%s' to be a directory",
799 lpFileName);
800 attributes &= ~FILE_ATTRIBUTE_DIRECTORY;
802 attributes &= ~(FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_HIDDEN|FILE_ATTRIBUTE_SYSTEM);
803 if (attributes)
804 FIXME("(%s):%lx attribute(s) not implemented.\n", lpFileName,attributes);
805 if (-1==chmod(full_name.long_name,buf.st_mode))
807 if(GetDriveTypeA(lpFileName) == DRIVE_CDROM) {
808 SetLastError( ERROR_ACCESS_DENIED );
809 return FALSE;
813 * FIXME: We don't return FALSE here because of differences between
814 * Linux and Windows privileges. Under Linux only the owner of
815 * the file is allowed to change file attributes. Under Windows,
816 * applications expect that if you can write to a file, you can also
817 * change its attributes (see GENERIC_WRITE). We could try to be
818 * clever here but that would break multi-user installations where
819 * users share read-only DLLs. This is because some installers like
820 * to change attributes of already installed DLLs.
822 FIXME("Couldn't set file attributes for existing file \"%s\".\n"
823 "Check permissions or set VFAT \"quiet\" mount flag\n", full_name.long_name);
825 return TRUE;
829 /**************************************************************************
830 * SetFileAttributesW (KERNEL32.@)
832 BOOL WINAPI SetFileAttributesW(LPCWSTR lpFileName, DWORD attributes)
834 BOOL res;
835 DWORD len = WideCharToMultiByte( CP_ACP, 0, lpFileName, -1, NULL, 0, NULL, NULL );
836 LPSTR afn = HeapAlloc( GetProcessHeap(), 0, len );
838 WideCharToMultiByte( CP_ACP, 0, lpFileName, -1, afn, len, NULL, NULL );
839 res = SetFileAttributesA( afn, attributes );
840 HeapFree( GetProcessHeap(), 0, afn );
841 return res;
845 /***********************************************************************
846 * GetFileSize (KERNEL32.@)
848 DWORD WINAPI GetFileSize( HANDLE hFile, LPDWORD filesizehigh )
850 BY_HANDLE_FILE_INFORMATION info;
851 if (!GetFileInformationByHandle( hFile, &info )) return -1;
852 if (filesizehigh) *filesizehigh = info.nFileSizeHigh;
853 return info.nFileSizeLow;
857 /***********************************************************************
858 * GetFileTime (KERNEL32.@)
860 BOOL WINAPI GetFileTime( HANDLE hFile, FILETIME *lpCreationTime,
861 FILETIME *lpLastAccessTime,
862 FILETIME *lpLastWriteTime )
864 BY_HANDLE_FILE_INFORMATION info;
865 if (!GetFileInformationByHandle( hFile, &info )) return FALSE;
866 if (lpCreationTime) *lpCreationTime = info.ftCreationTime;
867 if (lpLastAccessTime) *lpLastAccessTime = info.ftLastAccessTime;
868 if (lpLastWriteTime) *lpLastWriteTime = info.ftLastWriteTime;
869 return TRUE;
872 /***********************************************************************
873 * CompareFileTime (KERNEL32.@)
875 INT WINAPI CompareFileTime( LPFILETIME x, LPFILETIME y )
877 if (!x || !y) return -1;
879 if (x->dwHighDateTime > y->dwHighDateTime)
880 return 1;
881 if (x->dwHighDateTime < y->dwHighDateTime)
882 return -1;
883 if (x->dwLowDateTime > y->dwLowDateTime)
884 return 1;
885 if (x->dwLowDateTime < y->dwLowDateTime)
886 return -1;
887 return 0;
890 /***********************************************************************
891 * FILE_GetTempFileName : utility for GetTempFileName
893 static UINT FILE_GetTempFileName( LPCSTR path, LPCSTR prefix, UINT unique,
894 LPSTR buffer, BOOL isWin16 )
896 static UINT unique_temp;
897 DOS_FULL_NAME full_name;
898 int i;
899 LPSTR p;
900 UINT num;
902 if ( !path || !prefix || !buffer ) return 0;
904 if (!unique_temp) unique_temp = time(NULL) & 0xffff;
905 num = unique ? (unique & 0xffff) : (unique_temp++ & 0xffff);
907 strcpy( buffer, path );
908 p = buffer + strlen(buffer);
910 /* add a \, if there isn't one and path is more than just the drive letter ... */
911 if ( !((strlen(buffer) == 2) && (buffer[1] == ':'))
912 && ((p == buffer) || (p[-1] != '\\'))) *p++ = '\\';
914 if (isWin16) *p++ = '~';
915 for (i = 3; (i > 0) && (*prefix); i--) *p++ = *prefix++;
916 sprintf( p, "%04x.tmp", num );
918 /* Now try to create it */
920 if (!unique)
924 HFILE handle = CreateFileA( buffer, GENERIC_WRITE, 0, NULL,
925 CREATE_NEW, FILE_ATTRIBUTE_NORMAL, 0 );
926 if (handle != INVALID_HANDLE_VALUE)
927 { /* We created it */
928 TRACE("created %s\n",
929 buffer);
930 CloseHandle( handle );
931 break;
933 if (GetLastError() != ERROR_FILE_EXISTS)
934 break; /* No need to go on */
935 num++;
936 sprintf( p, "%04x.tmp", num );
937 } while (num != (unique & 0xffff));
940 /* Get the full path name */
942 if (DOSFS_GetFullName( buffer, FALSE, &full_name ))
944 /* Check if we have write access in the directory */
945 if ((p = strrchr( full_name.long_name, '/' ))) *p = '\0';
946 if (access( full_name.long_name, W_OK ) == -1)
947 WARN("returns '%s', which doesn't seem to be writeable.\n",
948 buffer);
950 TRACE("returning %s\n", buffer );
951 return unique ? unique : num;
955 /***********************************************************************
956 * GetTempFileNameA (KERNEL32.@)
958 UINT WINAPI GetTempFileNameA( LPCSTR path, LPCSTR prefix, UINT unique,
959 LPSTR buffer)
961 return FILE_GetTempFileName(path, prefix, unique, buffer, FALSE);
964 /***********************************************************************
965 * GetTempFileNameW (KERNEL32.@)
967 UINT WINAPI GetTempFileNameW( LPCWSTR path, LPCWSTR prefix, UINT unique,
968 LPWSTR buffer )
970 LPSTR patha,prefixa;
971 char buffera[144];
972 UINT ret;
974 if (!path) return 0;
975 patha = HEAP_strdupWtoA( GetProcessHeap(), 0, path );
976 prefixa = HEAP_strdupWtoA( GetProcessHeap(), 0, prefix );
977 ret = FILE_GetTempFileName( patha, prefixa, unique, buffera, FALSE );
978 MultiByteToWideChar( CP_ACP, 0, buffera, -1, buffer, MAX_PATH );
979 HeapFree( GetProcessHeap(), 0, patha );
980 HeapFree( GetProcessHeap(), 0, prefixa );
981 return ret;
985 /***********************************************************************
986 * GetTempFileName (KERNEL.97)
988 UINT16 WINAPI GetTempFileName16( BYTE drive, LPCSTR prefix, UINT16 unique,
989 LPSTR buffer )
991 char temppath[144];
993 if (!(drive & ~TF_FORCEDRIVE)) /* drive 0 means current default drive */
994 drive |= DRIVE_GetCurrentDrive() + 'A';
996 if ((drive & TF_FORCEDRIVE) &&
997 !DRIVE_IsValid( toupper(drive & ~TF_FORCEDRIVE) - 'A' ))
999 drive &= ~TF_FORCEDRIVE;
1000 WARN("invalid drive %d specified\n", drive );
1003 if (drive & TF_FORCEDRIVE)
1004 sprintf(temppath,"%c:", drive & ~TF_FORCEDRIVE );
1005 else
1006 GetTempPathA( 132, temppath );
1007 return (UINT16)FILE_GetTempFileName( temppath, prefix, unique, buffer, TRUE );
1010 /***********************************************************************
1011 * FILE_DoOpenFile
1013 * Implementation of OpenFile16() and OpenFile32().
1015 static HFILE FILE_DoOpenFile( LPCSTR name, OFSTRUCT *ofs, UINT mode,
1016 BOOL win32 )
1018 HFILE hFileRet;
1019 FILETIME filetime;
1020 WORD filedatetime[2];
1021 DOS_FULL_NAME full_name;
1022 DWORD access, sharing;
1023 char *p;
1025 if (!ofs) return HFILE_ERROR;
1027 TRACE("%s %s %s %s%s%s%s%s%s%s%s%s\n",name,
1028 ((mode & 0x3 )==OF_READ)?"OF_READ":
1029 ((mode & 0x3 )==OF_WRITE)?"OF_WRITE":
1030 ((mode & 0x3 )==OF_READWRITE)?"OF_READWRITE":"unknown",
1031 ((mode & 0x70 )==OF_SHARE_COMPAT)?"OF_SHARE_COMPAT":
1032 ((mode & 0x70 )==OF_SHARE_DENY_NONE)?"OF_SHARE_DENY_NONE":
1033 ((mode & 0x70 )==OF_SHARE_DENY_READ)?"OF_SHARE_DENY_READ":
1034 ((mode & 0x70 )==OF_SHARE_DENY_WRITE)?"OF_SHARE_DENY_WRITE":
1035 ((mode & 0x70 )==OF_SHARE_EXCLUSIVE)?"OF_SHARE_EXCLUSIVE":"unknown",
1036 ((mode & OF_PARSE )==OF_PARSE)?"OF_PARSE ":"",
1037 ((mode & OF_DELETE )==OF_DELETE)?"OF_DELETE ":"",
1038 ((mode & OF_VERIFY )==OF_VERIFY)?"OF_VERIFY ":"",
1039 ((mode & OF_SEARCH )==OF_SEARCH)?"OF_SEARCH ":"",
1040 ((mode & OF_CANCEL )==OF_CANCEL)?"OF_CANCEL ":"",
1041 ((mode & OF_CREATE )==OF_CREATE)?"OF_CREATE ":"",
1042 ((mode & OF_PROMPT )==OF_PROMPT)?"OF_PROMPT ":"",
1043 ((mode & OF_EXIST )==OF_EXIST)?"OF_EXIST ":"",
1044 ((mode & OF_REOPEN )==OF_REOPEN)?"OF_REOPEN ":""
1048 ofs->cBytes = sizeof(OFSTRUCT);
1049 ofs->nErrCode = 0;
1050 if (mode & OF_REOPEN) name = ofs->szPathName;
1052 if (!name) {
1053 ERR("called with `name' set to NULL ! Please debug.\n");
1054 return HFILE_ERROR;
1057 TRACE("%s %04x\n", name, mode );
1059 /* the watcom 10.6 IDE relies on a valid path returned in ofs->szPathName
1060 Are there any cases where getting the path here is wrong?
1061 Uwe Bonnes 1997 Apr 2 */
1062 if (!GetFullPathNameA( name, sizeof(ofs->szPathName),
1063 ofs->szPathName, NULL )) goto error;
1064 FILE_ConvertOFMode( mode, &access, &sharing );
1066 /* OF_PARSE simply fills the structure */
1068 if (mode & OF_PARSE)
1070 ofs->fFixedDisk = (GetDriveType16( ofs->szPathName[0]-'A' )
1071 != DRIVE_REMOVABLE);
1072 TRACE("(%s): OF_PARSE, res = '%s'\n",
1073 name, ofs->szPathName );
1074 return 0;
1077 /* OF_CREATE is completely different from all other options, so
1078 handle it first */
1080 if (mode & OF_CREATE)
1082 if ((hFileRet = CreateFileA( name, GENERIC_READ | GENERIC_WRITE,
1083 sharing, NULL, CREATE_ALWAYS,
1084 FILE_ATTRIBUTE_NORMAL, 0 ))== INVALID_HANDLE_VALUE)
1085 goto error;
1086 goto success;
1089 /* If OF_SEARCH is set, ignore the given path */
1091 if ((mode & OF_SEARCH) && !(mode & OF_REOPEN))
1093 /* First try the file name as is */
1094 if (DOSFS_GetFullName( name, TRUE, &full_name )) goto found;
1095 /* Now remove the path */
1096 if (name[0] && (name[1] == ':')) name += 2;
1097 if ((p = strrchr( name, '\\' ))) name = p + 1;
1098 if ((p = strrchr( name, '/' ))) name = p + 1;
1099 if (!name[0]) goto not_found;
1102 /* Now look for the file */
1104 if (!DIR_SearchPath( NULL, name, NULL, &full_name, win32 )) goto not_found;
1106 found:
1107 TRACE("found %s = %s\n",
1108 full_name.long_name, full_name.short_name );
1109 lstrcpynA( ofs->szPathName, full_name.short_name,
1110 sizeof(ofs->szPathName) );
1112 if (mode & OF_SHARE_EXCLUSIVE)
1113 /* Some InstallShield version uses OF_SHARE_EXCLUSIVE
1114 on the file <tempdir>/_ins0432._mp to determine how
1115 far installation has proceeded.
1116 _ins0432._mp is an executable and while running the
1117 application expects the open with OF_SHARE_ to fail*/
1118 /* Probable FIXME:
1119 As our loader closes the files after loading the executable,
1120 we can't find the running executable with FILE_InUse.
1121 The loader should keep the file open, as Windows does that, too.
1124 char *last = strrchr(full_name.long_name,'/');
1125 if (!last)
1126 last = full_name.long_name - 1;
1127 if (GetModuleHandle16(last+1))
1129 TRACE("Denying shared open for %s\n",full_name.long_name);
1130 return HFILE_ERROR;
1134 if (mode & OF_DELETE)
1136 if (unlink( full_name.long_name ) == -1) goto not_found;
1137 TRACE("(%s): OF_DELETE return = OK\n", name);
1138 return 1;
1141 hFileRet = FILE_CreateFile( full_name.long_name, access, sharing,
1142 NULL, OPEN_EXISTING, 0, 0,
1143 DRIVE_GetFlags(full_name.drive) & DRIVE_FAIL_READ_ONLY,
1144 GetDriveTypeA( full_name.short_name ) );
1145 if (!hFileRet) goto not_found;
1147 GetFileTime( hFileRet, NULL, NULL, &filetime );
1148 FileTimeToDosDateTime( &filetime, &filedatetime[0], &filedatetime[1] );
1149 if ((mode & OF_VERIFY) && (mode & OF_REOPEN))
1151 if (memcmp( ofs->reserved, filedatetime, sizeof(ofs->reserved) ))
1153 CloseHandle( hFileRet );
1154 WARN("(%s): OF_VERIFY failed\n", name );
1155 /* FIXME: what error here? */
1156 SetLastError( ERROR_FILE_NOT_FOUND );
1157 goto error;
1160 memcpy( ofs->reserved, filedatetime, sizeof(ofs->reserved) );
1162 success: /* We get here if the open was successful */
1163 TRACE("(%s): OK, return = %d\n", name, hFileRet );
1164 if (win32)
1166 if (mode & OF_EXIST) /* Return the handle, but close it first */
1167 CloseHandle( hFileRet );
1169 else
1171 hFileRet = Win32HandleToDosFileHandle( hFileRet );
1172 if (hFileRet == HFILE_ERROR16) goto error;
1173 if (mode & OF_EXIST) /* Return the handle, but close it first */
1174 _lclose16( hFileRet );
1176 return hFileRet;
1178 not_found: /* We get here if the file does not exist */
1179 WARN("'%s' not found or sharing violation\n", name );
1180 SetLastError( ERROR_FILE_NOT_FOUND );
1181 /* fall through */
1183 error: /* We get here if there was an error opening the file */
1184 ofs->nErrCode = GetLastError();
1185 WARN("(%s): return = HFILE_ERROR error= %d\n",
1186 name,ofs->nErrCode );
1187 return HFILE_ERROR;
1191 /***********************************************************************
1192 * OpenFile (KERNEL.74)
1193 * OpenFileEx (KERNEL.360)
1195 HFILE16 WINAPI OpenFile16( LPCSTR name, OFSTRUCT *ofs, UINT16 mode )
1197 return FILE_DoOpenFile( name, ofs, mode, FALSE );
1201 /***********************************************************************
1202 * OpenFile (KERNEL32.@)
1204 HFILE WINAPI OpenFile( LPCSTR name, OFSTRUCT *ofs, UINT mode )
1206 return FILE_DoOpenFile( name, ofs, mode, TRUE );
1210 /***********************************************************************
1211 * FILE_InitProcessDosHandles
1213 * Allocates the default DOS handles for a process. Called either by
1214 * Win32HandleToDosFileHandle below or by the DOSVM stuff.
1216 static void FILE_InitProcessDosHandles( void )
1218 dos_handles[0] = GetStdHandle(STD_INPUT_HANDLE);
1219 dos_handles[1] = GetStdHandle(STD_OUTPUT_HANDLE);
1220 dos_handles[2] = GetStdHandle(STD_ERROR_HANDLE);
1221 dos_handles[3] = GetStdHandle(STD_ERROR_HANDLE);
1222 dos_handles[4] = GetStdHandle(STD_ERROR_HANDLE);
1225 /***********************************************************************
1226 * Win32HandleToDosFileHandle (KERNEL32.21)
1228 * Allocate a DOS handle for a Win32 handle. The Win32 handle is no
1229 * longer valid after this function (even on failure).
1231 * Note: this is not exactly right, since on Win95 the Win32 handles
1232 * are on top of DOS handles and we do it the other way
1233 * around. Should be good enough though.
1235 HFILE WINAPI Win32HandleToDosFileHandle( HANDLE handle )
1237 int i;
1239 if (!handle || (handle == INVALID_HANDLE_VALUE))
1240 return HFILE_ERROR;
1242 for (i = 5; i < DOS_TABLE_SIZE; i++)
1243 if (!dos_handles[i])
1245 dos_handles[i] = handle;
1246 TRACE("Got %d for h32 %d\n", i, handle );
1247 return (HFILE)i;
1249 CloseHandle( handle );
1250 SetLastError( ERROR_TOO_MANY_OPEN_FILES );
1251 return HFILE_ERROR;
1255 /***********************************************************************
1256 * DosFileHandleToWin32Handle (KERNEL32.20)
1258 * Return the Win32 handle for a DOS handle.
1260 * Note: this is not exactly right, since on Win95 the Win32 handles
1261 * are on top of DOS handles and we do it the other way
1262 * around. Should be good enough though.
1264 HANDLE WINAPI DosFileHandleToWin32Handle( HFILE handle )
1266 HFILE16 hfile = (HFILE16)handle;
1267 if (hfile < 5 && !dos_handles[hfile]) FILE_InitProcessDosHandles();
1268 if ((hfile >= DOS_TABLE_SIZE) || !dos_handles[hfile])
1270 SetLastError( ERROR_INVALID_HANDLE );
1271 return INVALID_HANDLE_VALUE;
1273 return dos_handles[hfile];
1277 /***********************************************************************
1278 * DisposeLZ32Handle (KERNEL32.22)
1280 * Note: this is not entirely correct, we should only close the
1281 * 32-bit handle and not the 16-bit one, but we cannot do
1282 * this because of the way our DOS handles are implemented.
1283 * It shouldn't break anything though.
1285 void WINAPI DisposeLZ32Handle( HANDLE handle )
1287 int i;
1289 if (!handle || (handle == INVALID_HANDLE_VALUE)) return;
1291 for (i = 5; i < DOS_TABLE_SIZE; i++)
1292 if (dos_handles[i] == handle)
1294 dos_handles[i] = 0;
1295 CloseHandle( handle );
1296 break;
1301 /***********************************************************************
1302 * FILE_Dup2
1304 * dup2() function for DOS handles.
1306 HFILE16 FILE_Dup2( HFILE16 hFile1, HFILE16 hFile2 )
1308 HANDLE new_handle;
1310 if (hFile1 < 5 && !dos_handles[hFile1]) FILE_InitProcessDosHandles();
1312 if ((hFile1 >= DOS_TABLE_SIZE) || (hFile2 >= DOS_TABLE_SIZE) || !dos_handles[hFile1])
1314 SetLastError( ERROR_INVALID_HANDLE );
1315 return HFILE_ERROR16;
1317 if (hFile2 < 5)
1319 FIXME("stdio handle closed, need proper conversion\n" );
1320 SetLastError( ERROR_INVALID_HANDLE );
1321 return HFILE_ERROR16;
1323 if (!DuplicateHandle( GetCurrentProcess(), dos_handles[hFile1],
1324 GetCurrentProcess(), &new_handle,
1325 0, FALSE, DUPLICATE_SAME_ACCESS ))
1326 return HFILE_ERROR16;
1327 if (dos_handles[hFile2]) CloseHandle( dos_handles[hFile2] );
1328 dos_handles[hFile2] = new_handle;
1329 return hFile2;
1333 /***********************************************************************
1334 * _lclose (KERNEL.81)
1336 HFILE16 WINAPI _lclose16( HFILE16 hFile )
1338 if (hFile < 5)
1340 FIXME("stdio handle closed, need proper conversion\n" );
1341 SetLastError( ERROR_INVALID_HANDLE );
1342 return HFILE_ERROR16;
1344 if ((hFile >= DOS_TABLE_SIZE) || !dos_handles[hFile])
1346 SetLastError( ERROR_INVALID_HANDLE );
1347 return HFILE_ERROR16;
1349 TRACE("%d (handle32=%d)\n", hFile, dos_handles[hFile] );
1350 CloseHandle( dos_handles[hFile] );
1351 dos_handles[hFile] = 0;
1352 return 0;
1356 /***********************************************************************
1357 * _lclose (KERNEL32.@)
1359 HFILE WINAPI _lclose( HFILE hFile )
1361 TRACE("handle %d\n", hFile );
1362 return CloseHandle( hFile ) ? 0 : HFILE_ERROR;
1365 /***********************************************************************
1366 * GetOverlappedResult (KERNEL32.@)
1368 * Check the result of an Asynchronous data transfer from a file.
1370 * RETURNS
1371 * TRUE on success
1372 * FALSE on failure
1374 * If successful (and relevant) lpTransferred will hold the number of
1375 * bytes transferred during the async operation.
1377 * BUGS
1379 * Currently only works for WaitCommEvent, ReadFile, WriteFile
1380 * with communications ports.
1383 BOOL WINAPI GetOverlappedResult(
1384 HANDLE hFile, /* [in] handle of file to check on */
1385 LPOVERLAPPED lpOverlapped, /* [in/out] pointer to overlapped */
1386 LPDWORD lpTransferred, /* [in/out] number of bytes transferred */
1387 BOOL bWait /* [in] wait for the transfer to complete ? */
1389 DWORD r;
1391 TRACE("(%d %p %p %x)\n", hFile, lpOverlapped, lpTransferred, bWait);
1393 if(lpOverlapped==NULL)
1395 ERR("lpOverlapped was null\n");
1396 return FALSE;
1398 if(!lpOverlapped->hEvent)
1400 ERR("lpOverlapped->hEvent was null\n");
1401 return FALSE;
1404 do {
1405 TRACE("waiting on %p\n",lpOverlapped);
1406 r = WaitForSingleObjectEx(lpOverlapped->hEvent, bWait?INFINITE:0, TRUE);
1407 TRACE("wait on %p returned %ld\n",lpOverlapped,r);
1408 } while (r==STATUS_USER_APC);
1410 if(lpTransferred)
1411 *lpTransferred = lpOverlapped->InternalHigh;
1413 SetLastError ( lpOverlapped->Internal == STATUS_PENDING ?
1414 ERROR_IO_INCOMPLETE : lpOverlapped->Internal );
1416 return (r==WAIT_OBJECT_0);
1419 /***********************************************************************
1420 * CancelIo (KERNEL32.@)
1422 BOOL WINAPI CancelIo(HANDLE handle)
1424 async_private *ovp,*t;
1426 TRACE("handle = %x\n",handle);
1428 for (ovp = NtCurrentTeb()->pending_list; ovp; ovp = t)
1430 t = ovp->next;
1431 if ( ovp->handle == handle )
1432 cancel_async ( ovp );
1434 WaitForMultipleObjectsEx(0,NULL,FALSE,1,TRUE);
1435 return TRUE;
1438 /***********************************************************************
1439 * FILE_AsyncReadService (INTERNAL)
1441 * This function is called while the client is waiting on the
1442 * server, so we can't make any server calls here.
1444 static void FILE_AsyncReadService(async_private *ovp)
1446 async_fileio *fileio = (async_fileio*) ovp;
1447 LPOVERLAPPED lpOverlapped = fileio->lpOverlapped;
1448 int result, r;
1449 int already = lpOverlapped->InternalHigh;
1451 TRACE("%p %p\n", lpOverlapped, fileio->buffer );
1453 /* check to see if the data is ready (non-blocking) */
1455 result = pread (ovp->fd, &fileio->buffer[already], fileio->count - already,
1456 OVERLAPPED_OFFSET (lpOverlapped) + already);
1457 if ((result < 0) && (errno == ESPIPE))
1458 result = read (ovp->fd, &fileio->buffer[already], fileio->count - already);
1460 if ( (result<0) && ((errno == EAGAIN) || (errno == EINTR)))
1462 TRACE("Deferred read %d\n",errno);
1463 r = STATUS_PENDING;
1464 goto async_end;
1467 /* check to see if the transfer is complete */
1468 if(result<0)
1470 TRACE("read returned errno %d\n",errno);
1471 r = STATUS_UNSUCCESSFUL;
1472 goto async_end;
1475 lpOverlapped->InternalHigh += result;
1476 TRACE("read %d more bytes %ld/%d so far\n",result,lpOverlapped->InternalHigh,fileio->count);
1478 if(lpOverlapped->InternalHigh < fileio->count)
1479 r = STATUS_PENDING;
1480 else
1481 r = STATUS_SUCCESS;
1483 async_end:
1484 lpOverlapped->Internal = r;
1487 /***********************************************************************
1488 * FILE_ReadFileEx (INTERNAL)
1490 static BOOL FILE_ReadFileEx(HANDLE hFile, LPVOID buffer, DWORD bytesToRead,
1491 LPOVERLAPPED overlapped,
1492 LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine,
1493 HANDLE hEvent)
1495 async_fileio *ovp;
1496 int fd;
1497 int flags;
1498 enum fd_type type;
1500 TRACE("file %d to buf %p num %ld %p func %p\n",
1501 hFile, buffer, bytesToRead, overlapped, lpCompletionRoutine);
1503 /* check that there is an overlapped struct */
1504 if (overlapped==NULL)
1506 SetLastError(ERROR_INVALID_PARAMETER);
1507 return FALSE;
1510 fd = FILE_GetUnixHandleType ( hFile, GENERIC_READ, &type, &flags);
1511 if ( fd < 0 )
1513 WARN ( "Couldn't get FD\n" );
1514 SetLastError ( ERROR_INVALID_PARAMETER );
1515 return FALSE;
1518 ovp = (async_fileio*) HeapAlloc(GetProcessHeap(), 0, sizeof (async_fileio));
1519 if(!ovp)
1521 TRACE("HeapAlloc Failed\n");
1522 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1523 goto error;
1526 ovp->async.ops = ( lpCompletionRoutine ? &fileio_async_ops : &fileio_nocomp_async_ops );
1527 ovp->async.handle = hFile;
1528 ovp->async.fd = fd;
1529 ovp->async.type = ASYNC_TYPE_READ;
1530 ovp->async.func = FILE_AsyncReadService;
1531 ovp->async.event = hEvent;
1532 ovp->lpOverlapped = overlapped;
1533 ovp->count = bytesToRead;
1534 ovp->completion_func = lpCompletionRoutine;
1535 ovp->buffer = buffer;
1537 return !register_new_async (&ovp->async);
1539 error:
1540 close (fd);
1541 return FALSE;
1545 /***********************************************************************
1546 * ReadFileEx (KERNEL32.@)
1548 BOOL WINAPI ReadFileEx(HANDLE hFile, LPVOID buffer, DWORD bytesToRead,
1549 LPOVERLAPPED overlapped,
1550 LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine)
1552 overlapped->InternalHigh = 0;
1553 return FILE_ReadFileEx(hFile,buffer,bytesToRead,overlapped,lpCompletionRoutine, INVALID_HANDLE_VALUE);
1556 static BOOL FILE_TimeoutRead(HANDLE hFile, LPVOID buffer, DWORD bytesToRead, LPDWORD bytesRead)
1558 OVERLAPPED ov;
1559 BOOL r = FALSE;
1561 TRACE("%d %p %ld %p\n", hFile, buffer, bytesToRead, bytesRead );
1563 ZeroMemory(&ov, sizeof (OVERLAPPED));
1564 if(STATUS_SUCCESS==NtCreateEvent(&ov.hEvent, SYNCHRONIZE, NULL, 0, 0))
1566 if(FILE_ReadFileEx(hFile, buffer, bytesToRead, &ov, NULL, ov.hEvent))
1568 r = GetOverlappedResult(hFile, &ov, bytesRead, TRUE);
1571 CloseHandle(ov.hEvent);
1572 return r;
1575 /***********************************************************************
1576 * ReadFile (KERNEL32.@)
1578 BOOL WINAPI ReadFile( HANDLE hFile, LPVOID buffer, DWORD bytesToRead,
1579 LPDWORD bytesRead, LPOVERLAPPED overlapped )
1581 int unix_handle, result, flags;
1582 enum fd_type type;
1584 TRACE("%d %p %ld %p %p\n", hFile, buffer, bytesToRead,
1585 bytesRead, overlapped );
1587 if (bytesRead) *bytesRead = 0; /* Do this before anything else */
1588 if (!bytesToRead) return TRUE;
1590 unix_handle = FILE_GetUnixHandleType( hFile, GENERIC_READ, &type, &flags );
1592 if (flags & FD_FLAG_OVERLAPPED)
1594 if (unix_handle == -1) return FALSE;
1595 if ( (overlapped==NULL) || NtResetEvent( overlapped->hEvent, NULL ) )
1597 TRACE("Overlapped not specified or invalid event flag\n");
1598 close(unix_handle);
1599 SetLastError(ERROR_INVALID_PARAMETER);
1600 return FALSE;
1603 close(unix_handle);
1604 overlapped->InternalHigh = 0;
1606 if(!FILE_ReadFileEx(hFile, buffer, bytesToRead, overlapped, NULL, overlapped->hEvent))
1607 return FALSE;
1609 if ( !GetOverlappedResult (hFile, overlapped, bytesRead, FALSE) )
1611 if ( GetLastError() == ERROR_IO_INCOMPLETE )
1612 SetLastError ( ERROR_IO_PENDING );
1613 return FALSE;
1616 return TRUE;
1618 if (flags & FD_FLAG_TIMEOUT)
1620 close(unix_handle);
1621 return FILE_TimeoutRead(hFile, buffer, bytesToRead, bytesRead);
1623 switch(type)
1625 case FD_TYPE_SMB:
1626 return SMB_ReadFile(hFile, buffer, bytesToRead, bytesRead, NULL);
1627 case FD_TYPE_CONSOLE:
1628 return ReadConsoleA(hFile, buffer, bytesToRead, bytesRead, NULL);
1630 default:
1631 /* normal unix files */
1632 if (unix_handle == -1)
1633 return FALSE;
1634 if (overlapped)
1636 close(unix_handle);
1637 SetLastError(ERROR_INVALID_PARAMETER);
1638 return FALSE;
1640 break;
1643 /* code for synchronous reads */
1644 while ((result = read( unix_handle, buffer, bytesToRead )) == -1)
1646 if ((errno == EAGAIN) || (errno == EINTR)) continue;
1647 if ((errno == EFAULT) && !IsBadWritePtr( buffer, bytesToRead )) continue;
1648 FILE_SetDosError();
1649 break;
1651 close( unix_handle );
1652 if (result == -1) return FALSE;
1653 if (bytesRead) *bytesRead = result;
1654 return TRUE;
1658 /***********************************************************************
1659 * FILE_AsyncWriteService (INTERNAL)
1661 * This function is called while the client is waiting on the
1662 * server, so we can't make any server calls here.
1664 static void FILE_AsyncWriteService(struct async_private *ovp)
1666 async_fileio *fileio = (async_fileio *) ovp;
1667 LPOVERLAPPED lpOverlapped = fileio->lpOverlapped;
1668 int result, r;
1669 int already = lpOverlapped->InternalHigh;
1671 TRACE("(%p %p)\n",lpOverlapped,fileio->buffer);
1673 /* write some data (non-blocking) */
1675 result = pwrite(ovp->fd, &fileio->buffer[already], fileio->count - already,
1676 OVERLAPPED_OFFSET (lpOverlapped) + already);
1677 if ((result < 0) && (errno == ESPIPE))
1678 result = write(ovp->fd, &fileio->buffer[already], fileio->count - already);
1680 if ( (result<0) && ((errno == EAGAIN) || (errno == EINTR)))
1682 r = STATUS_PENDING;
1683 goto async_end;
1686 /* check to see if the transfer is complete */
1687 if(result<0)
1689 r = STATUS_UNSUCCESSFUL;
1690 goto async_end;
1693 lpOverlapped->InternalHigh += result;
1695 TRACE("wrote %d more bytes %ld/%d so far\n",result,lpOverlapped->InternalHigh,fileio->count);
1697 if(lpOverlapped->InternalHigh < fileio->count)
1698 r = STATUS_PENDING;
1699 else
1700 r = STATUS_SUCCESS;
1702 async_end:
1703 lpOverlapped->Internal = r;
1706 /***********************************************************************
1707 * FILE_WriteFileEx
1709 static BOOL FILE_WriteFileEx(HANDLE hFile, LPCVOID buffer, DWORD bytesToWrite,
1710 LPOVERLAPPED overlapped,
1711 LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine,
1712 HANDLE hEvent)
1714 async_fileio *ovp;
1715 int fd;
1716 int flags;
1717 enum fd_type type;
1719 TRACE("file %d to buf %p num %ld %p func %p stub\n",
1720 hFile, buffer, bytesToWrite, overlapped, lpCompletionRoutine);
1722 if (overlapped == NULL)
1724 SetLastError(ERROR_INVALID_PARAMETER);
1725 return FALSE;
1728 fd = FILE_GetUnixHandleType ( hFile, GENERIC_WRITE, &type, &flags );
1729 if ( fd < 0 )
1731 TRACE( "Couldn't get FD\n" );
1732 return FALSE;
1735 ovp = (async_fileio*) HeapAlloc(GetProcessHeap(), 0, sizeof (async_fileio));
1736 if(!ovp)
1738 TRACE("HeapAlloc Failed\n");
1739 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1740 goto error;
1743 ovp->async.ops = &fileio_async_ops;
1744 ovp->async.handle = hFile;
1745 ovp->async.fd = FILE_GetUnixHandle( hFile, GENERIC_WRITE );
1746 ovp->async.type = ASYNC_TYPE_WRITE;
1747 ovp->async.func = FILE_AsyncWriteService;
1748 ovp->lpOverlapped = overlapped;
1749 ovp->async.event = hEvent;
1750 ovp->buffer = (LPVOID) buffer;
1751 ovp->count = bytesToWrite;
1752 ovp->completion_func = lpCompletionRoutine;
1754 return !register_new_async (&ovp->async);
1756 error:
1757 close (fd);
1758 return FALSE;
1761 /***********************************************************************
1762 * WriteFileEx (KERNEL32.@)
1764 BOOL WINAPI WriteFileEx(HANDLE hFile, LPCVOID buffer, DWORD bytesToWrite,
1765 LPOVERLAPPED overlapped,
1766 LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine)
1768 overlapped->InternalHigh = 0;
1770 return FILE_WriteFileEx(hFile, buffer, bytesToWrite, overlapped, lpCompletionRoutine, INVALID_HANDLE_VALUE);
1773 /***********************************************************************
1774 * WriteFile (KERNEL32.@)
1776 BOOL WINAPI WriteFile( HANDLE hFile, LPCVOID buffer, DWORD bytesToWrite,
1777 LPDWORD bytesWritten, LPOVERLAPPED overlapped )
1779 int unix_handle, result, flags;
1780 enum fd_type type;
1782 TRACE("%d %p %ld %p %p\n", hFile, buffer, bytesToWrite,
1783 bytesWritten, overlapped );
1785 if (bytesWritten) *bytesWritten = 0; /* Do this before anything else */
1786 if (!bytesToWrite) return TRUE;
1788 unix_handle = FILE_GetUnixHandleType( hFile, GENERIC_WRITE, &type, &flags );
1790 if (flags & FD_FLAG_OVERLAPPED)
1792 if (unix_handle == -1) return FALSE;
1793 if ( (overlapped==NULL) || NtResetEvent( overlapped->hEvent, NULL ) )
1795 TRACE("Overlapped not specified or invalid event flag\n");
1796 close(unix_handle);
1797 SetLastError(ERROR_INVALID_PARAMETER);
1798 return FALSE;
1801 close(unix_handle);
1802 overlapped->InternalHigh = 0;
1804 if(!FILE_WriteFileEx(hFile, buffer, bytesToWrite, overlapped, NULL, overlapped->hEvent))
1805 return FALSE;
1807 if ( !GetOverlappedResult (hFile, overlapped, bytesWritten, FALSE) )
1809 if ( GetLastError() == ERROR_IO_INCOMPLETE )
1810 SetLastError ( ERROR_IO_PENDING );
1811 return FALSE;
1814 return TRUE;
1817 switch(type)
1819 case FD_TYPE_CONSOLE:
1820 TRACE("%d %s %ld %p %p\n", hFile, debugstr_an(buffer, bytesToWrite), bytesToWrite,
1821 bytesWritten, overlapped );
1822 return WriteConsoleA(hFile, buffer, bytesToWrite, bytesWritten, NULL);
1823 default:
1824 if (unix_handle == -1)
1825 return FALSE;
1828 /* synchronous file write */
1829 while ((result = write( unix_handle, buffer, bytesToWrite )) == -1)
1831 if ((errno == EAGAIN) || (errno == EINTR)) continue;
1832 if ((errno == EFAULT) && !IsBadReadPtr( buffer, bytesToWrite )) continue;
1833 if (errno == ENOSPC)
1834 SetLastError( ERROR_DISK_FULL );
1835 else
1836 FILE_SetDosError();
1837 break;
1839 close( unix_handle );
1840 if (result == -1) return FALSE;
1841 if (bytesWritten) *bytesWritten = result;
1842 return TRUE;
1846 /***********************************************************************
1847 * _hread (KERNEL.349)
1849 LONG WINAPI WIN16_hread( HFILE16 hFile, SEGPTR buffer, LONG count )
1851 LONG maxlen;
1853 TRACE("%d %08lx %ld\n",
1854 hFile, (DWORD)buffer, count );
1856 /* Some programs pass a count larger than the allocated buffer */
1857 maxlen = GetSelectorLimit16( SELECTOROF(buffer) ) - OFFSETOF(buffer) + 1;
1858 if (count > maxlen) count = maxlen;
1859 return _lread(DosFileHandleToWin32Handle(hFile), MapSL(buffer), count );
1863 /***********************************************************************
1864 * _lread (KERNEL.82)
1866 UINT16 WINAPI WIN16_lread( HFILE16 hFile, SEGPTR buffer, UINT16 count )
1868 return (UINT16)WIN16_hread( hFile, buffer, (LONG)count );
1872 /***********************************************************************
1873 * _lread (KERNEL32.@)
1875 UINT WINAPI _lread( HFILE handle, LPVOID buffer, UINT count )
1877 DWORD result;
1878 if (!ReadFile( handle, buffer, count, &result, NULL )) return -1;
1879 return result;
1883 /***********************************************************************
1884 * _lread16 (KERNEL.82)
1886 UINT16 WINAPI _lread16( HFILE16 hFile, LPVOID buffer, UINT16 count )
1888 return (UINT16)_lread(DosFileHandleToWin32Handle(hFile), buffer, (LONG)count );
1892 /***********************************************************************
1893 * _lcreat (KERNEL.83)
1895 HFILE16 WINAPI _lcreat16( LPCSTR path, INT16 attr )
1897 return Win32HandleToDosFileHandle( _lcreat( path, attr ) );
1901 /***********************************************************************
1902 * _lcreat (KERNEL32.@)
1904 HFILE WINAPI _lcreat( LPCSTR path, INT attr )
1906 /* Mask off all flags not explicitly allowed by the doc */
1907 attr &= FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM;
1908 TRACE("%s %02x\n", path, attr );
1909 return CreateFileA( path, GENERIC_READ | GENERIC_WRITE,
1910 FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
1911 CREATE_ALWAYS, attr, 0 );
1915 /***********************************************************************
1916 * SetFilePointer (KERNEL32.@)
1918 DWORD WINAPI SetFilePointer( HANDLE hFile, LONG distance, LONG *highword,
1919 DWORD method )
1921 DWORD ret = 0xffffffff;
1923 TRACE("handle %d offset %ld high %ld origin %ld\n",
1924 hFile, distance, highword?*highword:0, method );
1926 SERVER_START_REQ( set_file_pointer )
1928 req->handle = hFile;
1929 req->low = distance;
1930 req->high = highword ? *highword : (distance >= 0) ? 0 : -1;
1931 /* FIXME: assumes 1:1 mapping between Windows and Unix seek constants */
1932 req->whence = method;
1933 SetLastError( 0 );
1934 if (!wine_server_call_err( req ))
1936 ret = reply->new_low;
1937 if (highword) *highword = reply->new_high;
1940 SERVER_END_REQ;
1941 return ret;
1945 /***********************************************************************
1946 * _llseek (KERNEL.84)
1948 * FIXME:
1949 * Seeking before the start of the file should be allowed for _llseek16,
1950 * but cause subsequent I/O operations to fail (cf. interrupt list)
1953 LONG WINAPI _llseek16( HFILE16 hFile, LONG lOffset, INT16 nOrigin )
1955 return SetFilePointer( DosFileHandleToWin32Handle(hFile), lOffset, NULL, nOrigin );
1959 /***********************************************************************
1960 * _llseek (KERNEL32.@)
1962 LONG WINAPI _llseek( HFILE hFile, LONG lOffset, INT nOrigin )
1964 return SetFilePointer( hFile, lOffset, NULL, nOrigin );
1968 /***********************************************************************
1969 * _lopen (KERNEL.85)
1971 HFILE16 WINAPI _lopen16( LPCSTR path, INT16 mode )
1973 return Win32HandleToDosFileHandle( _lopen( path, mode ) );
1977 /***********************************************************************
1978 * _lopen (KERNEL32.@)
1980 HFILE WINAPI _lopen( LPCSTR path, INT mode )
1982 DWORD access, sharing;
1984 TRACE("('%s',%04x)\n", path, mode );
1985 FILE_ConvertOFMode( mode, &access, &sharing );
1986 return CreateFileA( path, access, sharing, NULL, OPEN_EXISTING, 0, 0 );
1990 /***********************************************************************
1991 * _lwrite (KERNEL.86)
1993 UINT16 WINAPI _lwrite16( HFILE16 hFile, LPCSTR buffer, UINT16 count )
1995 return (UINT16)_hwrite( DosFileHandleToWin32Handle(hFile), buffer, (LONG)count );
1998 /***********************************************************************
1999 * _lwrite (KERNEL32.@)
2001 UINT WINAPI _lwrite( HFILE hFile, LPCSTR buffer, UINT count )
2003 return (UINT)_hwrite( hFile, buffer, (LONG)count );
2007 /***********************************************************************
2008 * _hread16 (KERNEL.349)
2010 LONG WINAPI _hread16( HFILE16 hFile, LPVOID buffer, LONG count)
2012 return _lread( DosFileHandleToWin32Handle(hFile), buffer, count );
2016 /***********************************************************************
2017 * _hread (KERNEL32.@)
2019 LONG WINAPI _hread( HFILE hFile, LPVOID buffer, LONG count)
2021 return _lread( hFile, buffer, count );
2025 /***********************************************************************
2026 * _hwrite (KERNEL.350)
2028 LONG WINAPI _hwrite16( HFILE16 hFile, LPCSTR buffer, LONG count )
2030 return _hwrite( DosFileHandleToWin32Handle(hFile), buffer, count );
2034 /***********************************************************************
2035 * _hwrite (KERNEL32.@)
2037 * experimentation yields that _lwrite:
2038 * o truncates the file at the current position with
2039 * a 0 len write
2040 * o returns 0 on a 0 length write
2041 * o works with console handles
2044 LONG WINAPI _hwrite( HFILE handle, LPCSTR buffer, LONG count )
2046 DWORD result;
2048 TRACE("%d %p %ld\n", handle, buffer, count );
2050 if (!count)
2052 /* Expand or truncate at current position */
2053 if (!SetEndOfFile( handle )) return HFILE_ERROR;
2054 return 0;
2056 if (!WriteFile( handle, buffer, count, &result, NULL ))
2057 return HFILE_ERROR;
2058 return result;
2062 /***********************************************************************
2063 * SetHandleCount (KERNEL.199)
2065 UINT16 WINAPI SetHandleCount16( UINT16 count )
2067 return SetHandleCount( count );
2071 /*************************************************************************
2072 * SetHandleCount (KERNEL32.@)
2074 UINT WINAPI SetHandleCount( UINT count )
2076 return min( 256, count );
2080 /***********************************************************************
2081 * FlushFileBuffers (KERNEL32.@)
2083 BOOL WINAPI FlushFileBuffers( HANDLE hFile )
2085 BOOL ret;
2086 SERVER_START_REQ( flush_file )
2088 req->handle = hFile;
2089 ret = !wine_server_call_err( req );
2091 SERVER_END_REQ;
2092 return ret;
2096 /**************************************************************************
2097 * SetEndOfFile (KERNEL32.@)
2099 BOOL WINAPI SetEndOfFile( HANDLE hFile )
2101 BOOL ret;
2102 SERVER_START_REQ( truncate_file )
2104 req->handle = hFile;
2105 ret = !wine_server_call_err( req );
2107 SERVER_END_REQ;
2108 return ret;
2112 /***********************************************************************
2113 * DeleteFile (KERNEL.146)
2115 BOOL16 WINAPI DeleteFile16( LPCSTR path )
2117 return DeleteFileA( path );
2121 /***********************************************************************
2122 * DeleteFileA (KERNEL32.@)
2124 BOOL WINAPI DeleteFileA( LPCSTR path )
2126 DOS_FULL_NAME full_name;
2128 if (!path)
2130 SetLastError(ERROR_INVALID_PARAMETER);
2131 return FALSE;
2133 TRACE("'%s'\n", path );
2135 if (!*path)
2137 ERR("Empty path passed\n");
2138 return FALSE;
2140 if (DOSFS_GetDevice( path ))
2142 WARN("cannot remove DOS device '%s'!\n", path);
2143 SetLastError( ERROR_FILE_NOT_FOUND );
2144 return FALSE;
2147 if (!DOSFS_GetFullName( path, TRUE, &full_name )) return FALSE;
2148 if (unlink( full_name.long_name ) == -1)
2150 FILE_SetDosError();
2151 return FALSE;
2153 return TRUE;
2157 /***********************************************************************
2158 * DeleteFileW (KERNEL32.@)
2160 BOOL WINAPI DeleteFileW( LPCWSTR path )
2162 LPSTR xpath = HEAP_strdupWtoA( GetProcessHeap(), 0, path );
2163 BOOL ret = DeleteFileA( xpath );
2164 HeapFree( GetProcessHeap(), 0, xpath );
2165 return ret;
2169 /***********************************************************************
2170 * GetFileType (KERNEL32.@)
2172 DWORD WINAPI GetFileType( HANDLE hFile )
2174 DWORD ret = FILE_TYPE_UNKNOWN;
2175 SERVER_START_REQ( get_file_info )
2177 req->handle = hFile;
2178 if (!wine_server_call_err( req )) ret = reply->type;
2180 SERVER_END_REQ;
2181 return ret;
2185 /* check if a file name is for an executable file (.exe or .com) */
2186 inline static BOOL is_executable( const char *name )
2188 int len = strlen(name);
2190 if (len < 4) return FALSE;
2191 return (!strcasecmp( name + len - 4, ".exe" ) ||
2192 !strcasecmp( name + len - 4, ".com" ));
2196 /***********************************************************************
2197 * FILE_AddBootRenameEntry
2199 * Adds an entry to the registry that is loaded when windows boots and
2200 * checks if there are some files to be removed or renamed/moved.
2201 * <fn1> has to be valid and <fn2> may be NULL. If both pointers are
2202 * non-NULL then the file is moved, otherwise it is deleted. The
2203 * entry of the registrykey is always appended with two zero
2204 * terminated strings. If <fn2> is NULL then the second entry is
2205 * simply a single 0-byte. Otherwise the second filename goes
2206 * there. The entries are prepended with \??\ before the path and the
2207 * second filename gets also a '!' as the first character if
2208 * MOVEFILE_REPLACE_EXISTING is set. After the final string another
2209 * 0-byte follows to indicate the end of the strings.
2210 * i.e.:
2211 * \??\D:\test\file1[0]
2212 * !\??\D:\test\file1_renamed[0]
2213 * \??\D:\Test|delete[0]
2214 * [0] <- file is to be deleted, second string empty
2215 * \??\D:\test\file2[0]
2216 * !\??\D:\test\file2_renamed[0]
2217 * [0] <- indicates end of strings
2219 * or:
2220 * \??\D:\test\file1[0]
2221 * !\??\D:\test\file1_renamed[0]
2222 * \??\D:\Test|delete[0]
2223 * [0] <- file is to be deleted, second string empty
2224 * [0] <- indicates end of strings
2227 static BOOL FILE_AddBootRenameEntry( const char *fn1, const char *fn2, DWORD flags )
2229 static const char PreString[] = "\\??\\";
2230 static const char ValueName[] = "PendingFileRenameOperations";
2232 BOOL rc = FALSE;
2233 HKEY Reboot = 0;
2234 DWORD Type, len1, len2, l;
2235 DWORD DataSize = 0;
2236 BYTE *Buffer = NULL;
2238 if(RegCreateKeyA(HKEY_LOCAL_MACHINE, "SYSTEM\\CurrentControlSet\\Control\\Session Manager",
2239 &Reboot) != ERROR_SUCCESS)
2241 WARN("Error creating key for reboot managment [%s]\n",
2242 "SYSTEM\\CurrentControlSet\\Control\\Session Manager");
2243 return FALSE;
2246 l = strlen(PreString);
2247 len1 = strlen(fn1) + l + 1;
2248 if (fn2)
2250 len2 = strlen(fn2) + l + 1;
2251 if (flags & MOVEFILE_REPLACE_EXISTING) len2++; /* Plus 1 because of the leading '!' */
2253 else len2 = 1; /* minimum is the 0 byte for the empty second string */
2255 /* First we check if the key exists and if so how many bytes it already contains. */
2256 if (RegQueryValueExA(Reboot, ValueName, NULL, &Type, NULL, &DataSize) == ERROR_SUCCESS)
2258 if (Type != REG_MULTI_SZ) goto Quit;
2259 if (!(Buffer = HeapAlloc( GetProcessHeap(), 0, DataSize + len1 + len2 + 1 ))) goto Quit;
2260 if (RegQueryValueExA(Reboot, ValueName, NULL, &Type, Buffer, &DataSize) != ERROR_SUCCESS)
2261 goto Quit;
2262 if (DataSize) DataSize--; /* remove terminating null (will be added back later) */
2264 else
2266 if (!(Buffer = HeapAlloc( GetProcessHeap(), 0, len1 + len2 + 1 ))) goto Quit;
2267 DataSize = 0;
2269 sprintf( Buffer + DataSize, "%s%s", PreString, fn1 );
2270 DataSize += len1;
2271 if (fn2)
2273 sprintf( Buffer + DataSize, "%s%s%s",
2274 (flags & MOVEFILE_REPLACE_EXISTING) ? "!" : "", PreString, fn2 );
2275 DataSize += len2;
2277 else Buffer[DataSize++] = 0;
2279 Buffer[DataSize++] = 0; /* add final null */
2280 rc = !RegSetValueExA( Reboot, ValueName, 0, REG_MULTI_SZ, Buffer, DataSize );
2282 Quit:
2283 if (Reboot) RegCloseKey(Reboot);
2284 if (Buffer) HeapFree( GetProcessHeap(), 0, Buffer );
2285 return(rc);
2289 /**************************************************************************
2290 * MoveFileExA (KERNEL32.@)
2292 BOOL WINAPI MoveFileExA( LPCSTR fn1, LPCSTR fn2, DWORD flag )
2294 DOS_FULL_NAME full_name1, full_name2;
2296 TRACE("(%s,%s,%04lx)\n", fn1, fn2, flag);
2298 /* FIXME: <Gerhard W. Gruber>sparhawk@gmx.at
2299 In case of W9x and lesser this function should return 120 (ERROR_CALL_NOT_IMPLEMENTED)
2300 to be really compatible. Most programs wont have any problems though. In case
2301 you encounter one, this is what you should return here. I don't know what's up
2302 with NT 3.5. Is this function available there or not?
2303 Does anybody really care about 3.5? :)
2306 /* Filename1 has to be always set to a valid path. Filename2 may be NULL
2307 if the source file has to be deleted.
2309 if (!fn1) {
2310 SetLastError(ERROR_INVALID_PARAMETER);
2311 return FALSE;
2314 /* This function has to be run through in order to process the name properly.
2315 If the BOOTDELAY flag is set, the file doesn't need to exist though. At least
2316 that is the behaviour on NT 4.0. The operation accepts the filenames as
2317 they are given but it can't reply with a reasonable returncode. Success
2318 means in that case success for entering the values into the registry.
2320 if(!DOSFS_GetFullName( fn1, TRUE, &full_name1 ))
2322 if(!(flag & MOVEFILE_DELAY_UNTIL_REBOOT))
2323 return FALSE;
2326 if (fn2) /* !fn2 means delete fn1 */
2328 if (DOSFS_GetFullName( fn2, TRUE, &full_name2 ))
2330 if(!(flag & MOVEFILE_DELAY_UNTIL_REBOOT))
2332 /* target exists, check if we may overwrite */
2333 if (!(flag & MOVEFILE_REPLACE_EXISTING))
2335 /* FIXME: Use right error code */
2336 SetLastError( ERROR_ACCESS_DENIED );
2337 return FALSE;
2341 else
2343 if (!DOSFS_GetFullName( fn2, FALSE, &full_name2 ))
2345 if(!(flag & MOVEFILE_DELAY_UNTIL_REBOOT))
2346 return FALSE;
2350 /* Source name and target path are valid */
2352 if (flag & MOVEFILE_DELAY_UNTIL_REBOOT)
2354 /* FIXME: (bon@elektron.ikp.physik.th-darmstadt.de 970706)
2355 Perhaps we should queue these command and execute it
2356 when exiting... What about using on_exit(2)
2358 FIXME("Please move existing file '%s' to file '%s' when Wine has finished\n",
2359 fn1, fn2);
2360 return FILE_AddBootRenameEntry( fn1, fn2, flag );
2363 if (full_name1.drive != full_name2.drive)
2365 /* use copy, if allowed */
2366 if (!(flag & MOVEFILE_COPY_ALLOWED))
2368 /* FIXME: Use right error code */
2369 SetLastError( ERROR_FILE_EXISTS );
2370 return FALSE;
2372 return CopyFileA( fn1, fn2, !(flag & MOVEFILE_REPLACE_EXISTING) );
2374 if (rename( full_name1.long_name, full_name2.long_name ) == -1)
2376 FILE_SetDosError();
2377 return FALSE;
2379 if (is_executable( full_name1.long_name ) != is_executable( full_name2.long_name ))
2381 struct stat fstat;
2382 if (stat( full_name2.long_name, &fstat ) != -1)
2384 if (is_executable( full_name2.long_name ))
2385 /* set executable bit where read bit is set */
2386 fstat.st_mode |= (fstat.st_mode & 0444) >> 2;
2387 else
2388 fstat.st_mode &= ~0111;
2389 chmod( full_name2.long_name, fstat.st_mode );
2392 return TRUE;
2394 else /* fn2 == NULL means delete source */
2396 if (flag & MOVEFILE_DELAY_UNTIL_REBOOT)
2398 if (flag & MOVEFILE_COPY_ALLOWED) {
2399 WARN("Illegal flag\n");
2400 SetLastError( ERROR_GEN_FAILURE );
2401 return FALSE;
2403 /* FIXME: (bon@elektron.ikp.physik.th-darmstadt.de 970706)
2404 Perhaps we should queue these command and execute it
2405 when exiting... What about using on_exit(2)
2407 FIXME("Please delete file '%s' when Wine has finished\n", fn1);
2408 return FILE_AddBootRenameEntry( fn1, NULL, flag );
2411 if (unlink( full_name1.long_name ) == -1)
2413 FILE_SetDosError();
2414 return FALSE;
2416 return TRUE; /* successfully deleted */
2420 /**************************************************************************
2421 * MoveFileExW (KERNEL32.@)
2423 BOOL WINAPI MoveFileExW( LPCWSTR fn1, LPCWSTR fn2, DWORD flag )
2425 LPSTR afn1 = HEAP_strdupWtoA( GetProcessHeap(), 0, fn1 );
2426 LPSTR afn2 = HEAP_strdupWtoA( GetProcessHeap(), 0, fn2 );
2427 BOOL res = MoveFileExA( afn1, afn2, flag );
2428 HeapFree( GetProcessHeap(), 0, afn1 );
2429 HeapFree( GetProcessHeap(), 0, afn2 );
2430 return res;
2434 /**************************************************************************
2435 * MoveFileA (KERNEL32.@)
2437 * Move file or directory
2439 BOOL WINAPI MoveFileA( LPCSTR fn1, LPCSTR fn2 )
2441 DOS_FULL_NAME full_name1, full_name2;
2442 struct stat fstat;
2444 TRACE("(%s,%s)\n", fn1, fn2 );
2446 if (!DOSFS_GetFullName( fn1, TRUE, &full_name1 )) return FALSE;
2447 if (DOSFS_GetFullName( fn2, TRUE, &full_name2 )) {
2448 /* The new name must not already exist */
2449 SetLastError(ERROR_ALREADY_EXISTS);
2450 return FALSE;
2452 if (!DOSFS_GetFullName( fn2, FALSE, &full_name2 )) return FALSE;
2454 if (full_name1.drive == full_name2.drive) /* move */
2455 return MoveFileExA( fn1, fn2, MOVEFILE_COPY_ALLOWED );
2457 /* copy */
2458 if (stat( full_name1.long_name, &fstat ))
2460 WARN("Invalid source file %s\n",
2461 full_name1.long_name);
2462 FILE_SetDosError();
2463 return FALSE;
2465 if (S_ISDIR(fstat.st_mode)) {
2466 /* No Move for directories across file systems */
2467 /* FIXME: Use right error code */
2468 SetLastError( ERROR_GEN_FAILURE );
2469 return FALSE;
2471 return CopyFileA(fn1, fn2, TRUE); /*fail, if exist */
2475 /**************************************************************************
2476 * MoveFileW (KERNEL32.@)
2478 BOOL WINAPI MoveFileW( LPCWSTR fn1, LPCWSTR fn2 )
2480 LPSTR afn1 = HEAP_strdupWtoA( GetProcessHeap(), 0, fn1 );
2481 LPSTR afn2 = HEAP_strdupWtoA( GetProcessHeap(), 0, fn2 );
2482 BOOL res = MoveFileA( afn1, afn2 );
2483 HeapFree( GetProcessHeap(), 0, afn1 );
2484 HeapFree( GetProcessHeap(), 0, afn2 );
2485 return res;
2489 /**************************************************************************
2490 * CopyFileA (KERNEL32.@)
2492 BOOL WINAPI CopyFileA( LPCSTR source, LPCSTR dest, BOOL fail_if_exists )
2494 HFILE h1, h2;
2495 BY_HANDLE_FILE_INFORMATION info;
2496 UINT count;
2497 BOOL ret = FALSE;
2498 int mode;
2499 char buffer[2048];
2501 if ((h1 = _lopen( source, OF_READ )) == HFILE_ERROR) return FALSE;
2502 if (!GetFileInformationByHandle( h1, &info ))
2504 CloseHandle( h1 );
2505 return FALSE;
2507 mode = (info.dwFileAttributes & FILE_ATTRIBUTE_READONLY) ? 0444 : 0666;
2508 if ((h2 = CreateFileA( dest, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
2509 fail_if_exists ? CREATE_NEW : CREATE_ALWAYS,
2510 info.dwFileAttributes, h1 )) == INVALID_HANDLE_VALUE)
2512 CloseHandle( h1 );
2513 return FALSE;
2515 while ((count = _lread( h1, buffer, sizeof(buffer) )) > 0)
2517 char *p = buffer;
2518 while (count > 0)
2520 INT res = _lwrite( h2, p, count );
2521 if (res <= 0) goto done;
2522 p += res;
2523 count -= res;
2526 ret = TRUE;
2527 done:
2528 CloseHandle( h1 );
2529 CloseHandle( h2 );
2530 return ret;
2534 /**************************************************************************
2535 * CopyFileW (KERNEL32.@)
2537 BOOL WINAPI CopyFileW( LPCWSTR source, LPCWSTR dest, BOOL fail_if_exists)
2539 LPSTR sourceA = HEAP_strdupWtoA( GetProcessHeap(), 0, source );
2540 LPSTR destA = HEAP_strdupWtoA( GetProcessHeap(), 0, dest );
2541 BOOL ret = CopyFileA( sourceA, destA, fail_if_exists );
2542 HeapFree( GetProcessHeap(), 0, sourceA );
2543 HeapFree( GetProcessHeap(), 0, destA );
2544 return ret;
2548 /**************************************************************************
2549 * CopyFileExA (KERNEL32.@)
2551 * This implementation ignores most of the extra parameters passed-in into
2552 * the "ex" version of the method and calls the CopyFile method.
2553 * It will have to be fixed eventually.
2555 BOOL WINAPI CopyFileExA(LPCSTR sourceFilename,
2556 LPCSTR destFilename,
2557 LPPROGRESS_ROUTINE progressRoutine,
2558 LPVOID appData,
2559 LPBOOL cancelFlagPointer,
2560 DWORD copyFlags)
2562 BOOL failIfExists = FALSE;
2565 * Interpret the only flag that CopyFile can interpret.
2567 if ( (copyFlags & COPY_FILE_FAIL_IF_EXISTS) != 0)
2569 failIfExists = TRUE;
2572 return CopyFileA(sourceFilename, destFilename, failIfExists);
2575 /**************************************************************************
2576 * CopyFileExW (KERNEL32.@)
2578 BOOL WINAPI CopyFileExW(LPCWSTR sourceFilename,
2579 LPCWSTR destFilename,
2580 LPPROGRESS_ROUTINE progressRoutine,
2581 LPVOID appData,
2582 LPBOOL cancelFlagPointer,
2583 DWORD copyFlags)
2585 LPSTR sourceA = HEAP_strdupWtoA( GetProcessHeap(), 0, sourceFilename );
2586 LPSTR destA = HEAP_strdupWtoA( GetProcessHeap(), 0, destFilename );
2588 BOOL ret = CopyFileExA(sourceA,
2589 destA,
2590 progressRoutine,
2591 appData,
2592 cancelFlagPointer,
2593 copyFlags);
2595 HeapFree( GetProcessHeap(), 0, sourceA );
2596 HeapFree( GetProcessHeap(), 0, destA );
2598 return ret;
2602 /***********************************************************************
2603 * SetFileTime (KERNEL32.@)
2605 BOOL WINAPI SetFileTime( HANDLE hFile,
2606 const FILETIME *lpCreationTime,
2607 const FILETIME *lpLastAccessTime,
2608 const FILETIME *lpLastWriteTime )
2610 BOOL ret;
2611 SERVER_START_REQ( set_file_time )
2613 req->handle = hFile;
2614 if (lpLastAccessTime)
2615 RtlTimeToSecondsSince1970( lpLastAccessTime, (DWORD *)&req->access_time );
2616 else
2617 req->access_time = 0; /* FIXME */
2618 if (lpLastWriteTime)
2619 RtlTimeToSecondsSince1970( lpLastWriteTime, (DWORD *)&req->write_time );
2620 else
2621 req->write_time = 0; /* FIXME */
2622 ret = !wine_server_call_err( req );
2624 SERVER_END_REQ;
2625 return ret;
2629 /**************************************************************************
2630 * LockFile (KERNEL32.@)
2632 BOOL WINAPI LockFile( HANDLE hFile, DWORD dwFileOffsetLow, DWORD dwFileOffsetHigh,
2633 DWORD nNumberOfBytesToLockLow, DWORD nNumberOfBytesToLockHigh )
2635 BOOL ret;
2636 SERVER_START_REQ( lock_file )
2638 req->handle = hFile;
2639 req->offset_low = dwFileOffsetLow;
2640 req->offset_high = dwFileOffsetHigh;
2641 req->count_low = nNumberOfBytesToLockLow;
2642 req->count_high = nNumberOfBytesToLockHigh;
2643 ret = !wine_server_call_err( req );
2645 SERVER_END_REQ;
2646 return ret;
2649 /**************************************************************************
2650 * LockFileEx [KERNEL32.@]
2652 * Locks a byte range within an open file for shared or exclusive access.
2654 * RETURNS
2655 * success: TRUE
2656 * failure: FALSE
2658 * NOTES
2659 * Per Microsoft docs, the third parameter (reserved) must be set to 0.
2661 BOOL WINAPI LockFileEx( HANDLE hFile, DWORD flags, DWORD reserved,
2662 DWORD nNumberOfBytesToLockLow, DWORD nNumberOfBytesToLockHigh,
2663 LPOVERLAPPED pOverlapped )
2665 FIXME("hFile=%d,flags=%ld,reserved=%ld,lowbytes=%ld,highbytes=%ld,overlapped=%p: stub.\n",
2666 hFile, flags, reserved, nNumberOfBytesToLockLow, nNumberOfBytesToLockHigh,
2667 pOverlapped);
2668 if (reserved == 0)
2669 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
2670 else
2672 ERR("reserved == %ld: Supposed to be 0??\n", reserved);
2673 SetLastError(ERROR_INVALID_PARAMETER);
2676 return FALSE;
2680 /**************************************************************************
2681 * UnlockFile (KERNEL32.@)
2683 BOOL WINAPI UnlockFile( HANDLE hFile, DWORD dwFileOffsetLow, DWORD dwFileOffsetHigh,
2684 DWORD nNumberOfBytesToUnlockLow, DWORD nNumberOfBytesToUnlockHigh )
2686 BOOL ret;
2687 SERVER_START_REQ( unlock_file )
2689 req->handle = hFile;
2690 req->offset_low = dwFileOffsetLow;
2691 req->offset_high = dwFileOffsetHigh;
2692 req->count_low = nNumberOfBytesToUnlockLow;
2693 req->count_high = nNumberOfBytesToUnlockHigh;
2694 ret = !wine_server_call_err( req );
2696 SERVER_END_REQ;
2697 return ret;
2701 /**************************************************************************
2702 * UnlockFileEx (KERNEL32.@)
2704 BOOL WINAPI UnlockFileEx(
2705 HFILE hFile,
2706 DWORD dwReserved,
2707 DWORD nNumberOfBytesToUnlockLow,
2708 DWORD nNumberOfBytesToUnlockHigh,
2709 LPOVERLAPPED lpOverlapped
2712 FIXME("hFile=%d,reserved=%ld,lowbytes=%ld,highbytes=%ld,overlapped=%p: stub.\n",
2713 hFile, dwReserved, nNumberOfBytesToUnlockLow, nNumberOfBytesToUnlockHigh,
2714 lpOverlapped);
2715 if (dwReserved == 0)
2716 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
2717 else
2719 ERR("reserved == %ld: Supposed to be 0??\n", dwReserved);
2720 SetLastError(ERROR_INVALID_PARAMETER);
2723 return FALSE;
2727 #if 0
2729 struct DOS_FILE_LOCK {
2730 struct DOS_FILE_LOCK * next;
2731 DWORD base;
2732 DWORD len;
2733 DWORD processId;
2734 FILE_OBJECT * dos_file;
2735 /* char * unix_name;*/
2738 typedef struct DOS_FILE_LOCK DOS_FILE_LOCK;
2740 static DOS_FILE_LOCK *locks = NULL;
2741 static void DOS_RemoveFileLocks(FILE_OBJECT *file);
2744 /* Locks need to be mirrored because unix file locking is based
2745 * on the pid. Inside of wine there can be multiple WINE processes
2746 * that share the same unix pid.
2747 * Read's and writes should check these locks also - not sure
2748 * how critical that is at this point (FIXME).
2751 static BOOL DOS_AddLock(FILE_OBJECT *file, struct flock *f)
2753 DOS_FILE_LOCK *curr;
2754 DWORD processId;
2756 processId = GetCurrentProcessId();
2758 /* check if lock overlaps a current lock for the same file */
2759 #if 0
2760 for (curr = locks; curr; curr = curr->next) {
2761 if (strcmp(curr->unix_name, file->unix_name) == 0) {
2762 if ((f->l_start == curr->base) && (f->l_len == curr->len))
2763 return TRUE;/* region is identic */
2764 if ((f->l_start < (curr->base + curr->len)) &&
2765 ((f->l_start + f->l_len) > curr->base)) {
2766 /* region overlaps */
2767 return FALSE;
2771 #endif
2773 curr = HeapAlloc( GetProcessHeap(), 0, sizeof(DOS_FILE_LOCK) );
2774 curr->processId = GetCurrentProcessId();
2775 curr->base = f->l_start;
2776 curr->len = f->l_len;
2777 /* curr->unix_name = HEAP_strdupA( GetProcessHeap(), 0, file->unix_name);*/
2778 curr->next = locks;
2779 curr->dos_file = file;
2780 locks = curr;
2781 return TRUE;
2784 static void DOS_RemoveFileLocks(FILE_OBJECT *file)
2786 DWORD processId;
2787 DOS_FILE_LOCK **curr;
2788 DOS_FILE_LOCK *rem;
2790 processId = GetCurrentProcessId();
2791 curr = &locks;
2792 while (*curr) {
2793 if ((*curr)->dos_file == file) {
2794 rem = *curr;
2795 *curr = (*curr)->next;
2796 /* HeapFree( GetProcessHeap(), 0, rem->unix_name );*/
2797 HeapFree( GetProcessHeap(), 0, rem );
2799 else
2800 curr = &(*curr)->next;
2804 static BOOL DOS_RemoveLock(FILE_OBJECT *file, struct flock *f)
2806 DWORD processId;
2807 DOS_FILE_LOCK **curr;
2808 DOS_FILE_LOCK *rem;
2810 processId = GetCurrentProcessId();
2811 for (curr = &locks; *curr; curr = &(*curr)->next) {
2812 if ((*curr)->processId == processId &&
2813 (*curr)->dos_file == file &&
2814 (*curr)->base == f->l_start &&
2815 (*curr)->len == f->l_len) {
2816 /* this is the same lock */
2817 rem = *curr;
2818 *curr = (*curr)->next;
2819 /* HeapFree( GetProcessHeap(), 0, rem->unix_name );*/
2820 HeapFree( GetProcessHeap(), 0, rem );
2821 return TRUE;
2824 /* no matching lock found */
2825 return FALSE;
2829 /**************************************************************************
2830 * LockFile (KERNEL32.@)
2832 BOOL WINAPI LockFile(
2833 HFILE hFile,DWORD dwFileOffsetLow,DWORD dwFileOffsetHigh,
2834 DWORD nNumberOfBytesToLockLow,DWORD nNumberOfBytesToLockHigh )
2836 struct flock f;
2837 FILE_OBJECT *file;
2839 TRACE("handle %d offsetlow=%ld offsethigh=%ld nbyteslow=%ld nbyteshigh=%ld\n",
2840 hFile, dwFileOffsetLow, dwFileOffsetHigh,
2841 nNumberOfBytesToLockLow, nNumberOfBytesToLockHigh);
2843 if (dwFileOffsetHigh || nNumberOfBytesToLockHigh) {
2844 FIXME("Unimplemented bytes > 32bits\n");
2845 return FALSE;
2848 f.l_start = dwFileOffsetLow;
2849 f.l_len = nNumberOfBytesToLockLow;
2850 f.l_whence = SEEK_SET;
2851 f.l_pid = 0;
2852 f.l_type = F_WRLCK;
2854 if (!(file = FILE_GetFile(hFile,0,NULL))) return FALSE;
2856 /* shadow locks internally */
2857 if (!DOS_AddLock(file, &f)) {
2858 SetLastError( ERROR_LOCK_VIOLATION );
2859 return FALSE;
2862 /* FIXME: Unix locking commented out for now, doesn't work with Excel */
2863 #ifdef USE_UNIX_LOCKS
2864 if (fcntl(file->unix_handle, F_SETLK, &f) == -1) {
2865 if (errno == EACCES || errno == EAGAIN) {
2866 SetLastError( ERROR_LOCK_VIOLATION );
2868 else {
2869 FILE_SetDosError();
2871 /* remove our internal copy of the lock */
2872 DOS_RemoveLock(file, &f);
2873 return FALSE;
2875 #endif
2876 return TRUE;
2880 /**************************************************************************
2881 * UnlockFile (KERNEL32.@)
2883 BOOL WINAPI UnlockFile(
2884 HFILE hFile,DWORD dwFileOffsetLow,DWORD dwFileOffsetHigh,
2885 DWORD nNumberOfBytesToUnlockLow,DWORD nNumberOfBytesToUnlockHigh )
2887 FILE_OBJECT *file;
2888 struct flock f;
2890 TRACE("handle %d offsetlow=%ld offsethigh=%ld nbyteslow=%ld nbyteshigh=%ld\n",
2891 hFile, dwFileOffsetLow, dwFileOffsetHigh,
2892 nNumberOfBytesToUnlockLow, nNumberOfBytesToUnlockHigh);
2894 if (dwFileOffsetHigh || nNumberOfBytesToUnlockHigh) {
2895 WARN("Unimplemented bytes > 32bits\n");
2896 return FALSE;
2899 f.l_start = dwFileOffsetLow;
2900 f.l_len = nNumberOfBytesToUnlockLow;
2901 f.l_whence = SEEK_SET;
2902 f.l_pid = 0;
2903 f.l_type = F_UNLCK;
2905 if (!(file = FILE_GetFile(hFile,0,NULL))) return FALSE;
2907 DOS_RemoveLock(file, &f); /* ok if fails - may be another wine */
2909 /* FIXME: Unix locking commented out for now, doesn't work with Excel */
2910 #ifdef USE_UNIX_LOCKS
2911 if (fcntl(file->unix_handle, F_SETLK, &f) == -1) {
2912 FILE_SetDosError();
2913 return FALSE;
2915 #endif
2916 return TRUE;
2918 #endif
2920 /**************************************************************************
2921 * GetFileAttributesExA [KERNEL32.@]
2923 BOOL WINAPI GetFileAttributesExA(
2924 LPCSTR lpFileName, GET_FILEEX_INFO_LEVELS fInfoLevelId,
2925 LPVOID lpFileInformation)
2927 DOS_FULL_NAME full_name;
2928 BY_HANDLE_FILE_INFORMATION info;
2930 if (lpFileName == NULL) return FALSE;
2931 if (lpFileInformation == NULL) return FALSE;
2933 if (fInfoLevelId == GetFileExInfoStandard) {
2934 LPWIN32_FILE_ATTRIBUTE_DATA lpFad =
2935 (LPWIN32_FILE_ATTRIBUTE_DATA) lpFileInformation;
2936 if (!DOSFS_GetFullName( lpFileName, TRUE, &full_name )) return FALSE;
2937 if (!FILE_Stat( full_name.long_name, &info )) return FALSE;
2939 lpFad->dwFileAttributes = info.dwFileAttributes;
2940 lpFad->ftCreationTime = info.ftCreationTime;
2941 lpFad->ftLastAccessTime = info.ftLastAccessTime;
2942 lpFad->ftLastWriteTime = info.ftLastWriteTime;
2943 lpFad->nFileSizeHigh = info.nFileSizeHigh;
2944 lpFad->nFileSizeLow = info.nFileSizeLow;
2946 else {
2947 FIXME("invalid info level %d!\n", fInfoLevelId);
2948 return FALSE;
2951 return TRUE;
2955 /**************************************************************************
2956 * GetFileAttributesExW [KERNEL32.@]
2958 BOOL WINAPI GetFileAttributesExW(
2959 LPCWSTR lpFileName, GET_FILEEX_INFO_LEVELS fInfoLevelId,
2960 LPVOID lpFileInformation)
2962 LPSTR nameA = HEAP_strdupWtoA( GetProcessHeap(), 0, lpFileName );
2963 BOOL res =
2964 GetFileAttributesExA( nameA, fInfoLevelId, lpFileInformation);
2965 HeapFree( GetProcessHeap(), 0, nameA );
2966 return res;