Let MCI drivers support the session instance loading mechanism (NULL
[wine.git] / files / file.c
blobef6dc52fa05d6a90d5905975f6adfe68c33f6219
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 enum fd_type fd_type;
119 } async_fileio;
121 static DWORD fileio_get_async_status (const struct async_private *ovp)
123 return ((async_fileio*) ovp)->lpOverlapped->Internal;
126 static void fileio_set_async_status (async_private *ovp, const DWORD status)
128 ((async_fileio*) ovp)->lpOverlapped->Internal = status;
131 static DWORD fileio_get_async_count (const struct async_private *ovp)
133 async_fileio *fileio = (async_fileio*) ovp;
134 DWORD ret = fileio->count - fileio->lpOverlapped->InternalHigh;
135 return (ret < 0 ? 0 : ret);
138 static void CALLBACK fileio_call_completion_func (ULONG_PTR data)
140 async_fileio *ovp = (async_fileio*) data;
141 TRACE ("data: %p\n", ovp);
143 ovp->completion_func( ovp->lpOverlapped->Internal,
144 ovp->lpOverlapped->InternalHigh,
145 ovp->lpOverlapped );
147 fileio_async_cleanup ( &ovp->async );
150 static void fileio_async_cleanup ( struct async_private *ovp )
152 HeapFree ( GetProcessHeap(), 0, ovp );
155 /***********************************************************************
156 * FILE_ConvertOFMode
158 * Convert OF_* mode into flags for CreateFile.
160 static void FILE_ConvertOFMode( INT mode, DWORD *access, DWORD *sharing )
162 switch(mode & 0x03)
164 case OF_READ: *access = GENERIC_READ; break;
165 case OF_WRITE: *access = GENERIC_WRITE; break;
166 case OF_READWRITE: *access = GENERIC_READ | GENERIC_WRITE; break;
167 default: *access = 0; break;
169 switch(mode & 0x70)
171 case OF_SHARE_EXCLUSIVE: *sharing = 0; break;
172 case OF_SHARE_DENY_WRITE: *sharing = FILE_SHARE_READ; break;
173 case OF_SHARE_DENY_READ: *sharing = FILE_SHARE_WRITE; break;
174 case OF_SHARE_DENY_NONE:
175 case OF_SHARE_COMPAT:
176 default: *sharing = FILE_SHARE_READ | FILE_SHARE_WRITE; break;
181 /***********************************************************************
182 * FILE_strcasecmp
184 * locale-independent case conversion for file I/O
186 int FILE_strcasecmp( const char *str1, const char *str2 )
188 for (;;)
190 int ret = FILE_toupper(*str1) - FILE_toupper(*str2);
191 if (ret || !*str1) return ret;
192 str1++;
193 str2++;
198 /***********************************************************************
199 * FILE_strncasecmp
201 * locale-independent case conversion for file I/O
203 int FILE_strncasecmp( const char *str1, const char *str2, int len )
205 int ret = 0;
206 for ( ; len > 0; len--, str1++, str2++)
207 if ((ret = FILE_toupper(*str1) - FILE_toupper(*str2)) || !*str1) break;
208 return ret;
212 /***********************************************************************
213 * FILE_GetNtStatus(void)
215 * Retrieve the Nt Status code from errno.
216 * Try to be consistent with FILE_SetDosError().
218 DWORD FILE_GetNtStatus(void)
220 int err = errno;
221 DWORD nt;
222 TRACE ( "errno = %d\n", errno );
223 switch ( err )
225 case EAGAIN: nt = STATUS_SHARING_VIOLATION; break;
226 case EBADF: nt = STATUS_INVALID_HANDLE; break;
227 case ENOSPC: nt = STATUS_DISK_FULL; break;
228 case EPERM:
229 case EROFS:
230 case EACCES: nt = STATUS_ACCESS_DENIED; break;
231 case ENOENT: nt = STATUS_SHARING_VIOLATION; break;
232 case EISDIR: nt = STATUS_FILE_IS_A_DIRECTORY; break;
233 case EMFILE:
234 case ENFILE: nt = STATUS_NO_MORE_FILES; break;
235 case EINVAL:
236 case ENOTEMPTY: nt = STATUS_DIRECTORY_NOT_EMPTY; break;
237 case EPIPE: nt = STATUS_PIPE_BROKEN; break;
238 case ENOEXEC: /* ?? */
239 case ESPIPE: /* ?? */
240 case EEXIST: /* ?? */
241 default:
242 FIXME ( "Converting errno %d to STATUS_UNSUCCESSFUL\n", err );
243 nt = STATUS_UNSUCCESSFUL;
245 return nt;
248 /***********************************************************************
249 * FILE_SetDosError
251 * Set the DOS error code from errno.
253 void FILE_SetDosError(void)
255 int save_errno = errno; /* errno gets overwritten by printf */
257 TRACE("errno = %d %s\n", errno, strerror(errno));
258 switch (save_errno)
260 case EAGAIN:
261 SetLastError( ERROR_SHARING_VIOLATION );
262 break;
263 case EBADF:
264 SetLastError( ERROR_INVALID_HANDLE );
265 break;
266 case ENOSPC:
267 SetLastError( ERROR_HANDLE_DISK_FULL );
268 break;
269 case EACCES:
270 case EPERM:
271 case EROFS:
272 SetLastError( ERROR_ACCESS_DENIED );
273 break;
274 case EBUSY:
275 SetLastError( ERROR_LOCK_VIOLATION );
276 break;
277 case ENOENT:
278 SetLastError( ERROR_FILE_NOT_FOUND );
279 break;
280 case EISDIR:
281 SetLastError( ERROR_CANNOT_MAKE );
282 break;
283 case ENFILE:
284 case EMFILE:
285 SetLastError( ERROR_NO_MORE_FILES );
286 break;
287 case EEXIST:
288 SetLastError( ERROR_FILE_EXISTS );
289 break;
290 case EINVAL:
291 case ESPIPE:
292 SetLastError( ERROR_SEEK );
293 break;
294 case ENOTEMPTY:
295 SetLastError( ERROR_DIR_NOT_EMPTY );
296 break;
297 case ENOEXEC:
298 SetLastError( ERROR_BAD_FORMAT );
299 break;
300 default:
301 WARN("unknown file error: %s\n", strerror(save_errno) );
302 SetLastError( ERROR_GEN_FAILURE );
303 break;
305 errno = save_errno;
309 /***********************************************************************
310 * FILE_DupUnixHandle
312 * Duplicate a Unix handle into a task handle.
313 * Returns 0 on failure.
315 HANDLE FILE_DupUnixHandle( int fd, DWORD access, BOOL inherit )
317 HANDLE ret;
319 wine_server_send_fd( fd );
321 SERVER_START_REQ( alloc_file_handle )
323 req->access = access;
324 req->inherit = inherit;
325 req->fd = fd;
326 wine_server_call( req );
327 ret = reply->handle;
329 SERVER_END_REQ;
330 return ret;
334 /***********************************************************************
335 * FILE_GetUnixHandleType
337 * Retrieve the Unix handle corresponding to a file handle.
338 * Returns -1 on failure.
340 static int FILE_GetUnixHandleType( HANDLE handle, DWORD access, enum fd_type *type, int *flags_ptr )
342 int ret, flags, fd = -1;
344 ret = wine_server_handle_to_fd( handle, access, &fd, type, &flags );
345 if (flags_ptr) *flags_ptr = flags;
346 if (ret) SetLastError( RtlNtStatusToDosError(ret) );
347 else if (((access & GENERIC_READ) && (flags & FD_FLAG_RECV_SHUTDOWN)) ||
348 ((access & GENERIC_WRITE) && (flags & FD_FLAG_SEND_SHUTDOWN)))
350 close (fd);
351 SetLastError ( ERROR_PIPE_NOT_CONNECTED );
352 return -1;
354 return fd;
357 /***********************************************************************
358 * FILE_GetUnixHandle
360 * Retrieve the Unix handle corresponding to a file handle.
361 * Returns -1 on failure.
363 int FILE_GetUnixHandle( HANDLE handle, DWORD access )
365 return FILE_GetUnixHandleType( handle, access, NULL, NULL );
368 /*************************************************************************
369 * FILE_OpenConsole
371 * Open a handle to the current process console.
372 * Returns 0 on failure.
374 static HANDLE FILE_OpenConsole( BOOL output, DWORD access, DWORD sharing, LPSECURITY_ATTRIBUTES sa )
376 HANDLE ret;
378 SERVER_START_REQ( open_console )
380 req->from = output;
381 req->access = access;
382 req->share = sharing;
383 req->inherit = (sa && (sa->nLength>=sizeof(*sa)) && sa->bInheritHandle);
384 SetLastError(0);
385 wine_server_call_err( req );
386 ret = reply->handle;
388 SERVER_END_REQ;
389 return ret;
393 /***********************************************************************
394 * FILE_CreateFile
396 * Implementation of CreateFile. Takes a Unix path name.
397 * Returns 0 on failure.
399 HANDLE FILE_CreateFile( LPCSTR filename, DWORD access, DWORD sharing,
400 LPSECURITY_ATTRIBUTES sa, DWORD creation,
401 DWORD attributes, HANDLE template, BOOL fail_read_only,
402 UINT drive_type )
404 unsigned int err;
405 HANDLE ret;
407 for (;;)
409 SERVER_START_REQ( create_file )
411 req->access = access;
412 req->inherit = (sa && (sa->nLength>=sizeof(*sa)) && sa->bInheritHandle);
413 req->sharing = sharing;
414 req->create = creation;
415 req->attrs = attributes;
416 req->drive_type = drive_type;
417 wine_server_add_data( req, filename, strlen(filename) );
418 SetLastError(0);
419 err = wine_server_call( req );
420 ret = reply->handle;
422 SERVER_END_REQ;
424 /* If write access failed, retry without GENERIC_WRITE */
426 if (!ret && !fail_read_only && (access & GENERIC_WRITE))
428 if ((err == STATUS_MEDIA_WRITE_PROTECTED) || (err == STATUS_ACCESS_DENIED))
430 TRACE("Write access failed for file '%s', trying without "
431 "write access\n", filename);
432 access &= ~GENERIC_WRITE;
433 continue;
437 if (err) SetLastError( RtlNtStatusToDosError(err) );
439 if (!ret) WARN("Unable to create file '%s' (GLE %ld)\n", filename, GetLastError());
440 return ret;
445 /***********************************************************************
446 * FILE_CreateDevice
448 * Same as FILE_CreateFile but for a device
449 * Returns 0 on failure.
451 HANDLE FILE_CreateDevice( int client_id, DWORD access, LPSECURITY_ATTRIBUTES sa )
453 HANDLE ret;
454 SERVER_START_REQ( create_device )
456 req->access = access;
457 req->inherit = (sa && (sa->nLength>=sizeof(*sa)) && sa->bInheritHandle);
458 req->id = client_id;
459 SetLastError(0);
460 wine_server_call_err( req );
461 ret = reply->handle;
463 SERVER_END_REQ;
464 return ret;
467 static HANDLE FILE_OpenPipe(LPCSTR name, DWORD access)
469 WCHAR buffer[MAX_PATH];
470 HANDLE ret;
471 DWORD len = 0;
473 if (name && !(len = MultiByteToWideChar( CP_ACP, 0, name, strlen(name), buffer, MAX_PATH )))
475 SetLastError( ERROR_FILENAME_EXCED_RANGE );
476 return 0;
478 SERVER_START_REQ( open_named_pipe )
480 req->access = access;
481 SetLastError(0);
482 wine_server_add_data( req, buffer, len * sizeof(WCHAR) );
483 wine_server_call_err( req );
484 ret = reply->handle;
486 SERVER_END_REQ;
487 TRACE("Returned %d\n",ret);
488 return ret;
491 /*************************************************************************
492 * CreateFileA [KERNEL32.@] Creates or opens a file or other object
494 * Creates or opens an object, and returns a handle that can be used to
495 * access that object.
497 * PARAMS
499 * filename [in] pointer to filename to be accessed
500 * access [in] access mode requested
501 * sharing [in] share mode
502 * sa [in] pointer to security attributes
503 * creation [in] how to create the file
504 * attributes [in] attributes for newly created file
505 * template [in] handle to file with extended attributes to copy
507 * RETURNS
508 * Success: Open handle to specified file
509 * Failure: INVALID_HANDLE_VALUE
511 * NOTES
512 * Should call SetLastError() on failure.
514 * BUGS
516 * Doesn't support character devices, template files, or a
517 * lot of the 'attributes' flags yet.
519 HANDLE WINAPI CreateFileA( LPCSTR filename, DWORD access, DWORD sharing,
520 LPSECURITY_ATTRIBUTES sa, DWORD creation,
521 DWORD attributes, HANDLE template )
523 DOS_FULL_NAME full_name;
524 HANDLE ret;
526 if (!filename)
528 SetLastError( ERROR_INVALID_PARAMETER );
529 return INVALID_HANDLE_VALUE;
531 TRACE("%s %s%s%s%s%s%s%s\n",filename,
532 ((access & GENERIC_READ)==GENERIC_READ)?"GENERIC_READ ":"",
533 ((access & GENERIC_WRITE)==GENERIC_WRITE)?"GENERIC_WRITE ":"",
534 (!access)?"QUERY_ACCESS ":"",
535 ((sharing & FILE_SHARE_READ)==FILE_SHARE_READ)?"FILE_SHARE_READ ":"",
536 ((sharing & FILE_SHARE_WRITE)==FILE_SHARE_WRITE)?"FILE_SHARE_WRITE ":"",
537 ((sharing & FILE_SHARE_DELETE)==FILE_SHARE_DELETE)?"FILE_SHARE_DELETE ":"",
538 (creation ==CREATE_NEW)?"CREATE_NEW":
539 (creation ==CREATE_ALWAYS)?"CREATE_ALWAYS ":
540 (creation ==OPEN_EXISTING)?"OPEN_EXISTING ":
541 (creation ==OPEN_ALWAYS)?"OPEN_ALWAYS ":
542 (creation ==TRUNCATE_EXISTING)?"TRUNCATE_EXISTING ":"");
544 /* If the name starts with '\\?\', ignore the first 4 chars. */
545 if (!strncmp(filename, "\\\\?\\", 4))
547 filename += 4;
548 if (!strncmp(filename, "UNC\\", 4))
550 FIXME("UNC name (%s) not supported.\n", filename );
551 SetLastError( ERROR_PATH_NOT_FOUND );
552 return INVALID_HANDLE_VALUE;
556 if (!strncmp(filename, "\\\\.\\", 4)) {
557 if(!strncasecmp(&filename[4],"pipe\\",5))
559 TRACE("Opening a pipe: %s\n",filename);
560 ret = FILE_OpenPipe(filename,access);
561 goto done;
563 else if (isalpha(filename[4]) && filename[5] == ':' && filename[6] == '\0')
565 ret = FILE_CreateDevice( (toupper(filename[4]) - 'A') | 0x20000, access, sa );
566 goto done;
568 else if (!DOSFS_GetDevice( filename ))
570 ret = DEVICE_Open( filename+4, access, sa );
571 goto done;
573 else
574 filename+=4; /* fall into DOSFS_Device case below */
577 /* If the name still starts with '\\', it's a UNC name. */
578 if (!strncmp(filename, "\\\\", 2))
580 ret = SMB_CreateFileA(filename, access, sharing, sa, creation, attributes, template );
581 goto done;
584 /* If the name contains a DOS wild card (* or ?), do no create a file */
585 if(strchr(filename,'*') || strchr(filename,'?'))
586 return INVALID_HANDLE_VALUE;
588 /* Open a console for CONIN$ or CONOUT$ */
589 if (!strcasecmp(filename, "CONIN$"))
591 ret = FILE_OpenConsole( FALSE, access, sharing, sa );
592 goto done;
594 if (!strcasecmp(filename, "CONOUT$"))
596 ret = FILE_OpenConsole( TRUE, access, sharing, sa );
597 goto done;
600 if (DOSFS_GetDevice( filename ))
602 TRACE("opening device '%s'\n", filename );
604 if (!(ret = DOSFS_OpenDevice( filename, access, attributes, sa )))
606 /* Do not silence this please. It is a critical error. -MM */
607 ERR("Couldn't open device '%s'!\n",filename);
608 SetLastError( ERROR_FILE_NOT_FOUND );
610 goto done;
613 /* check for filename, don't check for last entry if creating */
614 if (!DOSFS_GetFullName( filename,
615 (creation == OPEN_EXISTING) ||
616 (creation == TRUNCATE_EXISTING),
617 &full_name )) {
618 WARN("Unable to get full filename from '%s' (GLE %ld)\n",
619 filename, GetLastError());
620 return INVALID_HANDLE_VALUE;
623 ret = FILE_CreateFile( full_name.long_name, access, sharing,
624 sa, creation, attributes, template,
625 DRIVE_GetFlags(full_name.drive) & DRIVE_FAIL_READ_ONLY,
626 GetDriveTypeA( full_name.short_name ) );
627 done:
628 if (!ret) ret = INVALID_HANDLE_VALUE;
629 return ret;
634 /*************************************************************************
635 * CreateFileW (KERNEL32.@)
637 HANDLE WINAPI CreateFileW( LPCWSTR filename, DWORD access, DWORD sharing,
638 LPSECURITY_ATTRIBUTES sa, DWORD creation,
639 DWORD attributes, HANDLE template)
641 LPSTR afn = HEAP_strdupWtoA( GetProcessHeap(), 0, filename );
642 HANDLE res = CreateFileA( afn, access, sharing, sa, creation, attributes, template );
643 HeapFree( GetProcessHeap(), 0, afn );
644 return res;
648 /***********************************************************************
649 * FILE_FillInfo
651 * Fill a file information from a struct stat.
653 static void FILE_FillInfo( struct stat *st, BY_HANDLE_FILE_INFORMATION *info )
655 if (S_ISDIR(st->st_mode))
656 info->dwFileAttributes = FILE_ATTRIBUTE_DIRECTORY;
657 else
658 info->dwFileAttributes = FILE_ATTRIBUTE_ARCHIVE;
659 if (!(st->st_mode & S_IWUSR))
660 info->dwFileAttributes |= FILE_ATTRIBUTE_READONLY;
662 RtlSecondsSince1970ToTime( st->st_mtime, &info->ftCreationTime );
663 RtlSecondsSince1970ToTime( st->st_mtime, &info->ftLastWriteTime );
664 RtlSecondsSince1970ToTime( st->st_atime, &info->ftLastAccessTime );
666 info->dwVolumeSerialNumber = 0; /* FIXME */
667 info->nFileSizeHigh = 0;
668 info->nFileSizeLow = 0;
669 if (!S_ISDIR(st->st_mode)) {
670 info->nFileSizeHigh = st->st_size >> 32;
671 info->nFileSizeLow = st->st_size & 0xffffffff;
673 info->nNumberOfLinks = st->st_nlink;
674 info->nFileIndexHigh = 0;
675 info->nFileIndexLow = st->st_ino;
679 /***********************************************************************
680 * FILE_Stat
682 * Stat a Unix path name. Return TRUE if OK.
684 BOOL FILE_Stat( LPCSTR unixName, BY_HANDLE_FILE_INFORMATION *info )
686 struct stat st;
688 if (lstat( unixName, &st ) == -1)
690 FILE_SetDosError();
691 return FALSE;
693 if (!S_ISLNK(st.st_mode)) FILE_FillInfo( &st, info );
694 else
696 /* do a "real" stat to find out
697 about the type of the symlink destination */
698 if (stat( unixName, &st ) == -1)
700 FILE_SetDosError();
701 return FALSE;
703 FILE_FillInfo( &st, info );
704 info->dwFileAttributes |= FILE_ATTRIBUTE_SYMLINK;
706 return TRUE;
710 /***********************************************************************
711 * GetFileInformationByHandle (KERNEL32.@)
713 DWORD WINAPI GetFileInformationByHandle( HANDLE hFile,
714 BY_HANDLE_FILE_INFORMATION *info )
716 DWORD ret;
717 if (!info) return 0;
719 SERVER_START_REQ( get_file_info )
721 req->handle = hFile;
722 if ((ret = !wine_server_call_err( req )))
724 /* FIXME: which file types are supported ?
725 * Serial ports (FILE_TYPE_CHAR) are not,
726 * and MSDN also says that pipes are not supported.
727 * FILE_TYPE_REMOTE seems to be supported according to
728 * MSDN q234741.txt */
729 if ((reply->type == FILE_TYPE_DISK) || (reply->type == FILE_TYPE_REMOTE))
731 RtlSecondsSince1970ToTime( reply->write_time, &info->ftCreationTime );
732 RtlSecondsSince1970ToTime( reply->write_time, &info->ftLastWriteTime );
733 RtlSecondsSince1970ToTime( reply->access_time, &info->ftLastAccessTime );
734 info->dwFileAttributes = reply->attr;
735 info->dwVolumeSerialNumber = reply->serial;
736 info->nFileSizeHigh = reply->size_high;
737 info->nFileSizeLow = reply->size_low;
738 info->nNumberOfLinks = reply->links;
739 info->nFileIndexHigh = reply->index_high;
740 info->nFileIndexLow = reply->index_low;
742 else
744 SetLastError(ERROR_NOT_SUPPORTED);
745 ret = 0;
749 SERVER_END_REQ;
750 return ret;
754 /**************************************************************************
755 * GetFileAttributes (KERNEL.420)
757 DWORD WINAPI GetFileAttributes16( LPCSTR name )
759 return GetFileAttributesA( name );
763 /**************************************************************************
764 * GetFileAttributesA (KERNEL32.@)
766 DWORD WINAPI GetFileAttributesA( LPCSTR name )
768 DOS_FULL_NAME full_name;
769 BY_HANDLE_FILE_INFORMATION info;
771 if (name == NULL)
773 SetLastError( ERROR_INVALID_PARAMETER );
774 return -1;
776 if (!DOSFS_GetFullName( name, TRUE, &full_name) )
777 return -1;
778 if (!FILE_Stat( full_name.long_name, &info )) return -1;
779 return info.dwFileAttributes;
783 /**************************************************************************
784 * GetFileAttributesW (KERNEL32.@)
786 DWORD WINAPI GetFileAttributesW( LPCWSTR name )
788 LPSTR nameA = HEAP_strdupWtoA( GetProcessHeap(), 0, name );
789 DWORD res = GetFileAttributesA( nameA );
790 HeapFree( GetProcessHeap(), 0, nameA );
791 return res;
795 /**************************************************************************
796 * SetFileAttributes (KERNEL.421)
798 BOOL16 WINAPI SetFileAttributes16( LPCSTR lpFileName, DWORD attributes )
800 return SetFileAttributesA( lpFileName, attributes );
804 /**************************************************************************
805 * SetFileAttributesA (KERNEL32.@)
807 BOOL WINAPI SetFileAttributesA(LPCSTR lpFileName, DWORD attributes)
809 struct stat buf;
810 DOS_FULL_NAME full_name;
812 if (!DOSFS_GetFullName( lpFileName, TRUE, &full_name ))
813 return FALSE;
815 TRACE("(%s,%lx)\n",lpFileName,attributes);
816 if (attributes & FILE_ATTRIBUTE_NORMAL) {
817 attributes &= ~FILE_ATTRIBUTE_NORMAL;
818 if (attributes)
819 FIXME("(%s):%lx illegal combination with FILE_ATTRIBUTE_NORMAL.\n", lpFileName,attributes);
821 if(stat(full_name.long_name,&buf)==-1)
823 FILE_SetDosError();
824 return FALSE;
826 if (attributes & FILE_ATTRIBUTE_READONLY)
828 if(S_ISDIR(buf.st_mode))
829 /* FIXME */
830 WARN("FILE_ATTRIBUTE_READONLY ignored for directory.\n");
831 else
832 buf.st_mode &= ~0222; /* octal!, clear write permission bits */
833 attributes &= ~FILE_ATTRIBUTE_READONLY;
835 else
837 /* add write permission */
838 buf.st_mode |= (0600 | ((buf.st_mode & 044) >> 1)) & (~FILE_umask);
840 if (attributes & FILE_ATTRIBUTE_DIRECTORY)
842 if (!S_ISDIR(buf.st_mode))
843 FIXME("SetFileAttributes expected the file '%s' to be a directory",
844 lpFileName);
845 attributes &= ~FILE_ATTRIBUTE_DIRECTORY;
847 attributes &= ~(FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_HIDDEN|FILE_ATTRIBUTE_SYSTEM);
848 if (attributes)
849 FIXME("(%s):%lx attribute(s) not implemented.\n", lpFileName,attributes);
850 if (-1==chmod(full_name.long_name,buf.st_mode))
852 if(GetDriveTypeA(lpFileName) == DRIVE_CDROM) {
853 SetLastError( ERROR_ACCESS_DENIED );
854 return FALSE;
858 * FIXME: We don't return FALSE here because of differences between
859 * Linux and Windows privileges. Under Linux only the owner of
860 * the file is allowed to change file attributes. Under Windows,
861 * applications expect that if you can write to a file, you can also
862 * change its attributes (see GENERIC_WRITE). We could try to be
863 * clever here but that would break multi-user installations where
864 * users share read-only DLLs. This is because some installers like
865 * to change attributes of already installed DLLs.
867 FIXME("Couldn't set file attributes for existing file \"%s\".\n"
868 "Check permissions or set VFAT \"quiet\" mount flag\n", full_name.long_name);
870 return TRUE;
874 /**************************************************************************
875 * SetFileAttributesW (KERNEL32.@)
877 BOOL WINAPI SetFileAttributesW(LPCWSTR lpFileName, DWORD attributes)
879 BOOL res;
880 DWORD len = WideCharToMultiByte( CP_ACP, 0, lpFileName, -1, NULL, 0, NULL, NULL );
881 LPSTR afn = HeapAlloc( GetProcessHeap(), 0, len );
883 WideCharToMultiByte( CP_ACP, 0, lpFileName, -1, afn, len, NULL, NULL );
884 res = SetFileAttributesA( afn, attributes );
885 HeapFree( GetProcessHeap(), 0, afn );
886 return res;
890 /***********************************************************************
891 * GetFileSize (KERNEL32.@)
893 DWORD WINAPI GetFileSize( HANDLE hFile, LPDWORD filesizehigh )
895 BY_HANDLE_FILE_INFORMATION info;
896 if (!GetFileInformationByHandle( hFile, &info )) return -1;
897 if (filesizehigh) *filesizehigh = info.nFileSizeHigh;
898 return info.nFileSizeLow;
902 /***********************************************************************
903 * GetFileTime (KERNEL32.@)
905 BOOL WINAPI GetFileTime( HANDLE hFile, FILETIME *lpCreationTime,
906 FILETIME *lpLastAccessTime,
907 FILETIME *lpLastWriteTime )
909 BY_HANDLE_FILE_INFORMATION info;
910 if (!GetFileInformationByHandle( hFile, &info )) return FALSE;
911 if (lpCreationTime) *lpCreationTime = info.ftCreationTime;
912 if (lpLastAccessTime) *lpLastAccessTime = info.ftLastAccessTime;
913 if (lpLastWriteTime) *lpLastWriteTime = info.ftLastWriteTime;
914 return TRUE;
917 /***********************************************************************
918 * CompareFileTime (KERNEL32.@)
920 INT WINAPI CompareFileTime( LPFILETIME x, LPFILETIME y )
922 if (!x || !y) return -1;
924 if (x->dwHighDateTime > y->dwHighDateTime)
925 return 1;
926 if (x->dwHighDateTime < y->dwHighDateTime)
927 return -1;
928 if (x->dwLowDateTime > y->dwLowDateTime)
929 return 1;
930 if (x->dwLowDateTime < y->dwLowDateTime)
931 return -1;
932 return 0;
935 /***********************************************************************
936 * FILE_GetTempFileName : utility for GetTempFileName
938 static UINT FILE_GetTempFileName( LPCSTR path, LPCSTR prefix, UINT unique,
939 LPSTR buffer, BOOL isWin16 )
941 static UINT unique_temp;
942 DOS_FULL_NAME full_name;
943 int i;
944 LPSTR p;
945 UINT num;
947 if ( !path || !prefix || !buffer ) return 0;
949 if (!unique_temp) unique_temp = time(NULL) & 0xffff;
950 num = unique ? (unique & 0xffff) : (unique_temp++ & 0xffff);
952 strcpy( buffer, path );
953 p = buffer + strlen(buffer);
955 /* add a \, if there isn't one and path is more than just the drive letter ... */
956 if ( !((strlen(buffer) == 2) && (buffer[1] == ':'))
957 && ((p == buffer) || (p[-1] != '\\'))) *p++ = '\\';
959 if (isWin16) *p++ = '~';
960 for (i = 3; (i > 0) && (*prefix); i--) *p++ = *prefix++;
961 sprintf( p, "%04x.tmp", num );
963 /* Now try to create it */
965 if (!unique)
969 HFILE handle = CreateFileA( buffer, GENERIC_WRITE, 0, NULL,
970 CREATE_NEW, FILE_ATTRIBUTE_NORMAL, 0 );
971 if (handle != INVALID_HANDLE_VALUE)
972 { /* We created it */
973 TRACE("created %s\n",
974 buffer);
975 CloseHandle( handle );
976 break;
978 if (GetLastError() != ERROR_FILE_EXISTS)
979 break; /* No need to go on */
980 num++;
981 sprintf( p, "%04x.tmp", num );
982 } while (num != (unique & 0xffff));
985 /* Get the full path name */
987 if (DOSFS_GetFullName( buffer, FALSE, &full_name ))
989 /* Check if we have write access in the directory */
990 if ((p = strrchr( full_name.long_name, '/' ))) *p = '\0';
991 if (access( full_name.long_name, W_OK ) == -1)
992 WARN("returns '%s', which doesn't seem to be writeable.\n",
993 buffer);
995 TRACE("returning %s\n", buffer );
996 return unique ? unique : num;
1000 /***********************************************************************
1001 * GetTempFileNameA (KERNEL32.@)
1003 UINT WINAPI GetTempFileNameA( LPCSTR path, LPCSTR prefix, UINT unique,
1004 LPSTR buffer)
1006 return FILE_GetTempFileName(path, prefix, unique, buffer, FALSE);
1009 /***********************************************************************
1010 * GetTempFileNameW (KERNEL32.@)
1012 UINT WINAPI GetTempFileNameW( LPCWSTR path, LPCWSTR prefix, UINT unique,
1013 LPWSTR buffer )
1015 LPSTR patha,prefixa;
1016 char buffera[144];
1017 UINT ret;
1019 if (!path) return 0;
1020 patha = HEAP_strdupWtoA( GetProcessHeap(), 0, path );
1021 prefixa = HEAP_strdupWtoA( GetProcessHeap(), 0, prefix );
1022 ret = FILE_GetTempFileName( patha, prefixa, unique, buffera, FALSE );
1023 MultiByteToWideChar( CP_ACP, 0, buffera, -1, buffer, MAX_PATH );
1024 HeapFree( GetProcessHeap(), 0, patha );
1025 HeapFree( GetProcessHeap(), 0, prefixa );
1026 return ret;
1030 /***********************************************************************
1031 * GetTempFileName (KERNEL.97)
1033 UINT16 WINAPI GetTempFileName16( BYTE drive, LPCSTR prefix, UINT16 unique,
1034 LPSTR buffer )
1036 char temppath[144];
1038 if (!(drive & ~TF_FORCEDRIVE)) /* drive 0 means current default drive */
1039 drive |= DRIVE_GetCurrentDrive() + 'A';
1041 if ((drive & TF_FORCEDRIVE) &&
1042 !DRIVE_IsValid( toupper(drive & ~TF_FORCEDRIVE) - 'A' ))
1044 drive &= ~TF_FORCEDRIVE;
1045 WARN("invalid drive %d specified\n", drive );
1048 if (drive & TF_FORCEDRIVE)
1049 sprintf(temppath,"%c:", drive & ~TF_FORCEDRIVE );
1050 else
1051 GetTempPathA( 132, temppath );
1052 return (UINT16)FILE_GetTempFileName( temppath, prefix, unique, buffer, TRUE );
1055 /***********************************************************************
1056 * FILE_DoOpenFile
1058 * Implementation of OpenFile16() and OpenFile32().
1060 static HFILE FILE_DoOpenFile( LPCSTR name, OFSTRUCT *ofs, UINT mode,
1061 BOOL win32 )
1063 HFILE hFileRet;
1064 FILETIME filetime;
1065 WORD filedatetime[2];
1066 DOS_FULL_NAME full_name;
1067 DWORD access, sharing;
1068 char *p;
1070 if (!ofs) return HFILE_ERROR;
1072 TRACE("%s %s %s %s%s%s%s%s%s%s%s%s\n",name,
1073 ((mode & 0x3 )==OF_READ)?"OF_READ":
1074 ((mode & 0x3 )==OF_WRITE)?"OF_WRITE":
1075 ((mode & 0x3 )==OF_READWRITE)?"OF_READWRITE":"unknown",
1076 ((mode & 0x70 )==OF_SHARE_COMPAT)?"OF_SHARE_COMPAT":
1077 ((mode & 0x70 )==OF_SHARE_DENY_NONE)?"OF_SHARE_DENY_NONE":
1078 ((mode & 0x70 )==OF_SHARE_DENY_READ)?"OF_SHARE_DENY_READ":
1079 ((mode & 0x70 )==OF_SHARE_DENY_WRITE)?"OF_SHARE_DENY_WRITE":
1080 ((mode & 0x70 )==OF_SHARE_EXCLUSIVE)?"OF_SHARE_EXCLUSIVE":"unknown",
1081 ((mode & OF_PARSE )==OF_PARSE)?"OF_PARSE ":"",
1082 ((mode & OF_DELETE )==OF_DELETE)?"OF_DELETE ":"",
1083 ((mode & OF_VERIFY )==OF_VERIFY)?"OF_VERIFY ":"",
1084 ((mode & OF_SEARCH )==OF_SEARCH)?"OF_SEARCH ":"",
1085 ((mode & OF_CANCEL )==OF_CANCEL)?"OF_CANCEL ":"",
1086 ((mode & OF_CREATE )==OF_CREATE)?"OF_CREATE ":"",
1087 ((mode & OF_PROMPT )==OF_PROMPT)?"OF_PROMPT ":"",
1088 ((mode & OF_EXIST )==OF_EXIST)?"OF_EXIST ":"",
1089 ((mode & OF_REOPEN )==OF_REOPEN)?"OF_REOPEN ":""
1093 ofs->cBytes = sizeof(OFSTRUCT);
1094 ofs->nErrCode = 0;
1095 if (mode & OF_REOPEN) name = ofs->szPathName;
1097 if (!name) {
1098 ERR("called with `name' set to NULL ! Please debug.\n");
1099 return HFILE_ERROR;
1102 TRACE("%s %04x\n", name, mode );
1104 /* the watcom 10.6 IDE relies on a valid path returned in ofs->szPathName
1105 Are there any cases where getting the path here is wrong?
1106 Uwe Bonnes 1997 Apr 2 */
1107 if (!GetFullPathNameA( name, sizeof(ofs->szPathName),
1108 ofs->szPathName, NULL )) goto error;
1109 FILE_ConvertOFMode( mode, &access, &sharing );
1111 /* OF_PARSE simply fills the structure */
1113 if (mode & OF_PARSE)
1115 ofs->fFixedDisk = (GetDriveType16( ofs->szPathName[0]-'A' )
1116 != DRIVE_REMOVABLE);
1117 TRACE("(%s): OF_PARSE, res = '%s'\n",
1118 name, ofs->szPathName );
1119 return 0;
1122 /* OF_CREATE is completely different from all other options, so
1123 handle it first */
1125 if (mode & OF_CREATE)
1127 if ((hFileRet = CreateFileA( name, GENERIC_READ | GENERIC_WRITE,
1128 sharing, NULL, CREATE_ALWAYS,
1129 FILE_ATTRIBUTE_NORMAL, 0 ))== INVALID_HANDLE_VALUE)
1130 goto error;
1131 goto success;
1134 /* If OF_SEARCH is set, ignore the given path */
1136 if ((mode & OF_SEARCH) && !(mode & OF_REOPEN))
1138 /* First try the file name as is */
1139 if (DOSFS_GetFullName( name, TRUE, &full_name )) goto found;
1140 /* Now remove the path */
1141 if (name[0] && (name[1] == ':')) name += 2;
1142 if ((p = strrchr( name, '\\' ))) name = p + 1;
1143 if ((p = strrchr( name, '/' ))) name = p + 1;
1144 if (!name[0]) goto not_found;
1147 /* Now look for the file */
1149 if (!DIR_SearchPath( NULL, name, NULL, &full_name, win32 )) goto not_found;
1151 found:
1152 TRACE("found %s = %s\n",
1153 full_name.long_name, full_name.short_name );
1154 lstrcpynA( ofs->szPathName, full_name.short_name,
1155 sizeof(ofs->szPathName) );
1157 if (mode & OF_SHARE_EXCLUSIVE)
1158 /* Some InstallShield version uses OF_SHARE_EXCLUSIVE
1159 on the file <tempdir>/_ins0432._mp to determine how
1160 far installation has proceeded.
1161 _ins0432._mp is an executable and while running the
1162 application expects the open with OF_SHARE_ to fail*/
1163 /* Probable FIXME:
1164 As our loader closes the files after loading the executable,
1165 we can't find the running executable with FILE_InUse.
1166 The loader should keep the file open, as Windows does that, too.
1169 char *last = strrchr(full_name.long_name,'/');
1170 if (!last)
1171 last = full_name.long_name - 1;
1172 if (GetModuleHandle16(last+1))
1174 TRACE("Denying shared open for %s\n",full_name.long_name);
1175 return HFILE_ERROR;
1179 if (mode & OF_DELETE)
1181 if (unlink( full_name.long_name ) == -1) goto not_found;
1182 TRACE("(%s): OF_DELETE return = OK\n", name);
1183 return 1;
1186 hFileRet = FILE_CreateFile( full_name.long_name, access, sharing,
1187 NULL, OPEN_EXISTING, 0, 0,
1188 DRIVE_GetFlags(full_name.drive) & DRIVE_FAIL_READ_ONLY,
1189 GetDriveTypeA( full_name.short_name ) );
1190 if (!hFileRet) goto not_found;
1192 GetFileTime( hFileRet, NULL, NULL, &filetime );
1193 FileTimeToDosDateTime( &filetime, &filedatetime[0], &filedatetime[1] );
1194 if ((mode & OF_VERIFY) && (mode & OF_REOPEN))
1196 if (memcmp( ofs->reserved, filedatetime, sizeof(ofs->reserved) ))
1198 CloseHandle( hFileRet );
1199 WARN("(%s): OF_VERIFY failed\n", name );
1200 /* FIXME: what error here? */
1201 SetLastError( ERROR_FILE_NOT_FOUND );
1202 goto error;
1205 memcpy( ofs->reserved, filedatetime, sizeof(ofs->reserved) );
1207 success: /* We get here if the open was successful */
1208 TRACE("(%s): OK, return = %d\n", name, hFileRet );
1209 if (win32)
1211 if (mode & OF_EXIST) /* Return the handle, but close it first */
1212 CloseHandle( hFileRet );
1214 else
1216 hFileRet = Win32HandleToDosFileHandle( hFileRet );
1217 if (hFileRet == HFILE_ERROR16) goto error;
1218 if (mode & OF_EXIST) /* Return the handle, but close it first */
1219 _lclose16( hFileRet );
1221 return hFileRet;
1223 not_found: /* We get here if the file does not exist */
1224 WARN("'%s' not found or sharing violation\n", name );
1225 SetLastError( ERROR_FILE_NOT_FOUND );
1226 /* fall through */
1228 error: /* We get here if there was an error opening the file */
1229 ofs->nErrCode = GetLastError();
1230 WARN("(%s): return = HFILE_ERROR error= %d\n",
1231 name,ofs->nErrCode );
1232 return HFILE_ERROR;
1236 /***********************************************************************
1237 * OpenFile (KERNEL.74)
1238 * OpenFileEx (KERNEL.360)
1240 HFILE16 WINAPI OpenFile16( LPCSTR name, OFSTRUCT *ofs, UINT16 mode )
1242 return FILE_DoOpenFile( name, ofs, mode, FALSE );
1246 /***********************************************************************
1247 * OpenFile (KERNEL32.@)
1249 HFILE WINAPI OpenFile( LPCSTR name, OFSTRUCT *ofs, UINT mode )
1251 return FILE_DoOpenFile( name, ofs, mode, TRUE );
1255 /***********************************************************************
1256 * FILE_InitProcessDosHandles
1258 * Allocates the default DOS handles for a process. Called either by
1259 * Win32HandleToDosFileHandle below or by the DOSVM stuff.
1261 static void FILE_InitProcessDosHandles( void )
1263 dos_handles[0] = GetStdHandle(STD_INPUT_HANDLE);
1264 dos_handles[1] = GetStdHandle(STD_OUTPUT_HANDLE);
1265 dos_handles[2] = GetStdHandle(STD_ERROR_HANDLE);
1266 dos_handles[3] = GetStdHandle(STD_ERROR_HANDLE);
1267 dos_handles[4] = GetStdHandle(STD_ERROR_HANDLE);
1270 /***********************************************************************
1271 * Win32HandleToDosFileHandle (KERNEL32.21)
1273 * Allocate a DOS handle for a Win32 handle. The Win32 handle is no
1274 * longer valid after this function (even on failure).
1276 * Note: this is not exactly right, since on Win95 the Win32 handles
1277 * are on top of DOS handles and we do it the other way
1278 * around. Should be good enough though.
1280 HFILE WINAPI Win32HandleToDosFileHandle( HANDLE handle )
1282 int i;
1284 if (!handle || (handle == INVALID_HANDLE_VALUE))
1285 return HFILE_ERROR;
1287 for (i = 5; i < DOS_TABLE_SIZE; i++)
1288 if (!dos_handles[i])
1290 dos_handles[i] = handle;
1291 TRACE("Got %d for h32 %d\n", i, handle );
1292 return (HFILE)i;
1294 CloseHandle( handle );
1295 SetLastError( ERROR_TOO_MANY_OPEN_FILES );
1296 return HFILE_ERROR;
1300 /***********************************************************************
1301 * DosFileHandleToWin32Handle (KERNEL32.20)
1303 * Return the Win32 handle for a DOS handle.
1305 * Note: this is not exactly right, since on Win95 the Win32 handles
1306 * are on top of DOS handles and we do it the other way
1307 * around. Should be good enough though.
1309 HANDLE WINAPI DosFileHandleToWin32Handle( HFILE handle )
1311 HFILE16 hfile = (HFILE16)handle;
1312 if (hfile < 5 && !dos_handles[hfile]) FILE_InitProcessDosHandles();
1313 if ((hfile >= DOS_TABLE_SIZE) || !dos_handles[hfile])
1315 SetLastError( ERROR_INVALID_HANDLE );
1316 return INVALID_HANDLE_VALUE;
1318 return dos_handles[hfile];
1322 /***********************************************************************
1323 * DisposeLZ32Handle (KERNEL32.22)
1325 * Note: this is not entirely correct, we should only close the
1326 * 32-bit handle and not the 16-bit one, but we cannot do
1327 * this because of the way our DOS handles are implemented.
1328 * It shouldn't break anything though.
1330 void WINAPI DisposeLZ32Handle( HANDLE handle )
1332 int i;
1334 if (!handle || (handle == INVALID_HANDLE_VALUE)) return;
1336 for (i = 5; i < DOS_TABLE_SIZE; i++)
1337 if (dos_handles[i] == handle)
1339 dos_handles[i] = 0;
1340 CloseHandle( handle );
1341 break;
1346 /***********************************************************************
1347 * FILE_Dup2
1349 * dup2() function for DOS handles.
1351 HFILE16 FILE_Dup2( HFILE16 hFile1, HFILE16 hFile2 )
1353 HANDLE new_handle;
1355 if (hFile1 < 5 && !dos_handles[hFile1]) FILE_InitProcessDosHandles();
1357 if ((hFile1 >= DOS_TABLE_SIZE) || (hFile2 >= DOS_TABLE_SIZE) || !dos_handles[hFile1])
1359 SetLastError( ERROR_INVALID_HANDLE );
1360 return HFILE_ERROR16;
1362 if (hFile2 < 5)
1364 FIXME("stdio handle closed, need proper conversion\n" );
1365 SetLastError( ERROR_INVALID_HANDLE );
1366 return HFILE_ERROR16;
1368 if (!DuplicateHandle( GetCurrentProcess(), dos_handles[hFile1],
1369 GetCurrentProcess(), &new_handle,
1370 0, FALSE, DUPLICATE_SAME_ACCESS ))
1371 return HFILE_ERROR16;
1372 if (dos_handles[hFile2]) CloseHandle( dos_handles[hFile2] );
1373 dos_handles[hFile2] = new_handle;
1374 return hFile2;
1378 /***********************************************************************
1379 * _lclose (KERNEL.81)
1381 HFILE16 WINAPI _lclose16( HFILE16 hFile )
1383 if (hFile < 5)
1385 FIXME("stdio handle closed, need proper conversion\n" );
1386 SetLastError( ERROR_INVALID_HANDLE );
1387 return HFILE_ERROR16;
1389 if ((hFile >= DOS_TABLE_SIZE) || !dos_handles[hFile])
1391 SetLastError( ERROR_INVALID_HANDLE );
1392 return HFILE_ERROR16;
1394 TRACE("%d (handle32=%d)\n", hFile, dos_handles[hFile] );
1395 CloseHandle( dos_handles[hFile] );
1396 dos_handles[hFile] = 0;
1397 return 0;
1401 /***********************************************************************
1402 * _lclose (KERNEL32.@)
1404 HFILE WINAPI _lclose( HFILE hFile )
1406 TRACE("handle %d\n", hFile );
1407 return CloseHandle( hFile ) ? 0 : HFILE_ERROR;
1410 /***********************************************************************
1411 * GetOverlappedResult (KERNEL32.@)
1413 * Check the result of an Asynchronous data transfer from a file.
1415 * RETURNS
1416 * TRUE on success
1417 * FALSE on failure
1419 * If successful (and relevant) lpTransferred will hold the number of
1420 * bytes transferred during the async operation.
1422 * BUGS
1424 * Currently only works for WaitCommEvent, ReadFile, WriteFile
1425 * with communications ports.
1428 BOOL WINAPI GetOverlappedResult(
1429 HANDLE hFile, /* [in] handle of file to check on */
1430 LPOVERLAPPED lpOverlapped, /* [in/out] pointer to overlapped */
1431 LPDWORD lpTransferred, /* [in/out] number of bytes transferred */
1432 BOOL bWait /* [in] wait for the transfer to complete ? */
1434 DWORD r;
1436 TRACE("(%d %p %p %x)\n", hFile, lpOverlapped, lpTransferred, bWait);
1438 if(lpOverlapped==NULL)
1440 ERR("lpOverlapped was null\n");
1441 return FALSE;
1443 if(!lpOverlapped->hEvent)
1445 ERR("lpOverlapped->hEvent was null\n");
1446 return FALSE;
1449 do {
1450 TRACE("waiting on %p\n",lpOverlapped);
1451 r = WaitForSingleObjectEx(lpOverlapped->hEvent, bWait?INFINITE:0, TRUE);
1452 TRACE("wait on %p returned %ld\n",lpOverlapped,r);
1453 } while (r==STATUS_USER_APC);
1455 if(lpTransferred)
1456 *lpTransferred = lpOverlapped->InternalHigh;
1458 SetLastError ( lpOverlapped->Internal == STATUS_PENDING ?
1459 ERROR_IO_INCOMPLETE : RtlNtStatusToDosError ( lpOverlapped->Internal ) );
1461 return (r==WAIT_OBJECT_0);
1464 /***********************************************************************
1465 * CancelIo (KERNEL32.@)
1467 BOOL WINAPI CancelIo(HANDLE handle)
1469 async_private *ovp,*t;
1471 TRACE("handle = %x\n",handle);
1473 for (ovp = NtCurrentTeb()->pending_list; ovp; ovp = t)
1475 t = ovp->next;
1476 if ( ovp->handle == handle )
1477 cancel_async ( ovp );
1479 WaitForMultipleObjectsEx(0,NULL,FALSE,1,TRUE);
1480 return TRUE;
1483 /***********************************************************************
1484 * FILE_AsyncReadService (INTERNAL)
1486 * This function is called while the client is waiting on the
1487 * server, so we can't make any server calls here.
1489 static void FILE_AsyncReadService(async_private *ovp)
1491 async_fileio *fileio = (async_fileio*) ovp;
1492 LPOVERLAPPED lpOverlapped = fileio->lpOverlapped;
1493 int result, r;
1494 int already = lpOverlapped->InternalHigh;
1496 TRACE("%p %p\n", lpOverlapped, fileio->buffer );
1498 /* check to see if the data is ready (non-blocking) */
1500 if ( fileio->fd_type == FD_TYPE_SOCKET )
1501 result = read (ovp->fd, &fileio->buffer[already], fileio->count - already);
1502 else
1504 result = pread (ovp->fd, &fileio->buffer[already], fileio->count - already,
1505 OVERLAPPED_OFFSET (lpOverlapped) + already);
1506 if ((result < 0) && (errno == ESPIPE))
1507 result = read (ovp->fd, &fileio->buffer[already], fileio->count - already);
1510 if ( (result<0) && ((errno == EAGAIN) || (errno == EINTR)))
1512 TRACE("Deferred read %d\n",errno);
1513 r = STATUS_PENDING;
1514 goto async_end;
1517 /* check to see if the transfer is complete */
1518 if(result<0)
1520 r = FILE_GetNtStatus ();
1521 goto async_end;
1524 lpOverlapped->InternalHigh += result;
1525 TRACE("read %d more bytes %ld/%d so far\n",result,lpOverlapped->InternalHigh,fileio->count);
1527 if(lpOverlapped->InternalHigh >= fileio->count || fileio->fd_type == FD_TYPE_SOCKET )
1528 r = STATUS_SUCCESS;
1529 else
1530 r = STATUS_PENDING;
1532 async_end:
1533 lpOverlapped->Internal = r;
1536 /***********************************************************************
1537 * FILE_ReadFileEx (INTERNAL)
1539 static BOOL FILE_ReadFileEx(HANDLE hFile, LPVOID buffer, DWORD bytesToRead,
1540 LPOVERLAPPED overlapped,
1541 LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine,
1542 HANDLE hEvent)
1544 async_fileio *ovp;
1545 int fd;
1546 int flags;
1547 enum fd_type type;
1549 TRACE("file %d to buf %p num %ld %p func %p\n",
1550 hFile, buffer, bytesToRead, overlapped, lpCompletionRoutine);
1552 /* check that there is an overlapped struct */
1553 if (overlapped==NULL)
1555 SetLastError(ERROR_INVALID_PARAMETER);
1556 return FALSE;
1559 fd = FILE_GetUnixHandleType ( hFile, GENERIC_READ, &type, &flags);
1560 if ( fd < 0 )
1562 WARN ( "Couldn't get FD\n" );
1563 return FALSE;
1566 ovp = (async_fileio*) HeapAlloc(GetProcessHeap(), 0, sizeof (async_fileio));
1567 if(!ovp)
1569 TRACE("HeapAlloc Failed\n");
1570 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1571 goto error;
1574 ovp->async.ops = ( lpCompletionRoutine ? &fileio_async_ops : &fileio_nocomp_async_ops );
1575 ovp->async.handle = hFile;
1576 ovp->async.fd = fd;
1577 ovp->async.type = ASYNC_TYPE_READ;
1578 ovp->async.func = FILE_AsyncReadService;
1579 ovp->async.event = hEvent;
1580 ovp->lpOverlapped = overlapped;
1581 ovp->count = bytesToRead;
1582 ovp->completion_func = lpCompletionRoutine;
1583 ovp->buffer = buffer;
1584 ovp->fd_type = type;
1586 return !register_new_async (&ovp->async);
1588 error:
1589 close (fd);
1590 return FALSE;
1594 /***********************************************************************
1595 * ReadFileEx (KERNEL32.@)
1597 BOOL WINAPI ReadFileEx(HANDLE hFile, LPVOID buffer, DWORD bytesToRead,
1598 LPOVERLAPPED overlapped,
1599 LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine)
1601 overlapped->InternalHigh = 0;
1602 return FILE_ReadFileEx(hFile,buffer,bytesToRead,overlapped,lpCompletionRoutine, INVALID_HANDLE_VALUE);
1605 static BOOL FILE_TimeoutRead(HANDLE hFile, LPVOID buffer, DWORD bytesToRead, LPDWORD bytesRead)
1607 OVERLAPPED ov;
1608 BOOL r = FALSE;
1610 TRACE("%d %p %ld %p\n", hFile, buffer, bytesToRead, bytesRead );
1612 ZeroMemory(&ov, sizeof (OVERLAPPED));
1613 if(STATUS_SUCCESS==NtCreateEvent(&ov.hEvent, SYNCHRONIZE, NULL, 0, 0))
1615 if(FILE_ReadFileEx(hFile, buffer, bytesToRead, &ov, NULL, ov.hEvent))
1617 r = GetOverlappedResult(hFile, &ov, bytesRead, TRUE);
1620 CloseHandle(ov.hEvent);
1621 return r;
1624 /***********************************************************************
1625 * ReadFile (KERNEL32.@)
1627 BOOL WINAPI ReadFile( HANDLE hFile, LPVOID buffer, DWORD bytesToRead,
1628 LPDWORD bytesRead, LPOVERLAPPED overlapped )
1630 int unix_handle, result, flags;
1631 enum fd_type type;
1633 TRACE("%d %p %ld %p %p\n", hFile, buffer, bytesToRead,
1634 bytesRead, overlapped );
1636 if (bytesRead) *bytesRead = 0; /* Do this before anything else */
1637 if (!bytesToRead) return TRUE;
1639 unix_handle = FILE_GetUnixHandleType( hFile, GENERIC_READ, &type, &flags );
1641 if (flags & FD_FLAG_OVERLAPPED)
1643 if (unix_handle == -1) return FALSE;
1644 if ( (overlapped==NULL) || NtResetEvent( overlapped->hEvent, NULL ) )
1646 TRACE("Overlapped not specified or invalid event flag\n");
1647 close(unix_handle);
1648 SetLastError(ERROR_INVALID_PARAMETER);
1649 return FALSE;
1652 close(unix_handle);
1653 overlapped->InternalHigh = 0;
1655 if(!FILE_ReadFileEx(hFile, buffer, bytesToRead, overlapped, NULL, overlapped->hEvent))
1656 return FALSE;
1658 if ( !GetOverlappedResult (hFile, overlapped, bytesRead, FALSE) )
1660 if ( GetLastError() == ERROR_IO_INCOMPLETE )
1661 SetLastError ( ERROR_IO_PENDING );
1662 return FALSE;
1665 return TRUE;
1667 if (flags & FD_FLAG_TIMEOUT)
1669 close(unix_handle);
1670 return FILE_TimeoutRead(hFile, buffer, bytesToRead, bytesRead);
1672 switch(type)
1674 case FD_TYPE_SMB:
1675 return SMB_ReadFile(hFile, buffer, bytesToRead, bytesRead, NULL);
1676 case FD_TYPE_CONSOLE:
1677 return ReadConsoleA(hFile, buffer, bytesToRead, bytesRead, NULL);
1679 default:
1680 /* normal unix files */
1681 if (unix_handle == -1)
1682 return FALSE;
1683 if (overlapped)
1685 close(unix_handle);
1686 SetLastError(ERROR_INVALID_PARAMETER);
1687 return FALSE;
1689 break;
1692 /* code for synchronous reads */
1693 while ((result = read( unix_handle, buffer, bytesToRead )) == -1)
1695 if ((errno == EAGAIN) || (errno == EINTR)) continue;
1696 if ((errno == EFAULT) && !IsBadWritePtr( buffer, bytesToRead )) continue;
1697 FILE_SetDosError();
1698 break;
1700 close( unix_handle );
1701 if (result == -1) return FALSE;
1702 if (bytesRead) *bytesRead = result;
1703 return TRUE;
1707 /***********************************************************************
1708 * FILE_AsyncWriteService (INTERNAL)
1710 * This function is called while the client is waiting on the
1711 * server, so we can't make any server calls here.
1713 static void FILE_AsyncWriteService(struct async_private *ovp)
1715 async_fileio *fileio = (async_fileio *) ovp;
1716 LPOVERLAPPED lpOverlapped = fileio->lpOverlapped;
1717 int result, r;
1718 int already = lpOverlapped->InternalHigh;
1720 TRACE("(%p %p)\n",lpOverlapped,fileio->buffer);
1722 /* write some data (non-blocking) */
1724 if ( fileio->fd_type == FD_TYPE_SOCKET )
1725 result = write(ovp->fd, &fileio->buffer[already], fileio->count - already);
1726 else
1728 result = pwrite(ovp->fd, &fileio->buffer[already], fileio->count - already,
1729 OVERLAPPED_OFFSET (lpOverlapped) + already);
1730 if ((result < 0) && (errno == ESPIPE))
1731 result = write(ovp->fd, &fileio->buffer[already], fileio->count - already);
1734 if ( (result<0) && ((errno == EAGAIN) || (errno == EINTR)))
1736 r = STATUS_PENDING;
1737 goto async_end;
1740 /* check to see if the transfer is complete */
1741 if(result<0)
1743 r = FILE_GetNtStatus ();
1744 goto async_end;
1747 lpOverlapped->InternalHigh += result;
1749 TRACE("wrote %d more bytes %ld/%d so far\n",result,lpOverlapped->InternalHigh,fileio->count);
1751 if(lpOverlapped->InternalHigh < fileio->count)
1752 r = STATUS_PENDING;
1753 else
1754 r = STATUS_SUCCESS;
1756 async_end:
1757 lpOverlapped->Internal = r;
1760 /***********************************************************************
1761 * FILE_WriteFileEx
1763 static BOOL FILE_WriteFileEx(HANDLE hFile, LPCVOID buffer, DWORD bytesToWrite,
1764 LPOVERLAPPED overlapped,
1765 LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine,
1766 HANDLE hEvent)
1768 async_fileio *ovp;
1769 int fd;
1770 int flags;
1771 enum fd_type type;
1773 TRACE("file %d to buf %p num %ld %p func %p handle %d\n",
1774 hFile, buffer, bytesToWrite, overlapped, lpCompletionRoutine, hEvent);
1776 if (overlapped == NULL)
1778 SetLastError(ERROR_INVALID_PARAMETER);
1779 return FALSE;
1782 fd = FILE_GetUnixHandleType ( hFile, GENERIC_WRITE, &type, &flags );
1783 if ( fd < 0 )
1785 TRACE( "Couldn't get FD\n" );
1786 return FALSE;
1789 ovp = (async_fileio*) HeapAlloc(GetProcessHeap(), 0, sizeof (async_fileio));
1790 if(!ovp)
1792 TRACE("HeapAlloc Failed\n");
1793 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1794 goto error;
1797 ovp->async.ops = ( lpCompletionRoutine ? &fileio_async_ops : &fileio_nocomp_async_ops );
1798 ovp->async.handle = hFile;
1799 ovp->async.fd = fd;
1800 ovp->async.type = ASYNC_TYPE_WRITE;
1801 ovp->async.func = FILE_AsyncWriteService;
1802 ovp->lpOverlapped = overlapped;
1803 ovp->async.event = hEvent;
1804 ovp->buffer = (LPVOID) buffer;
1805 ovp->count = bytesToWrite;
1806 ovp->completion_func = lpCompletionRoutine;
1807 ovp->fd_type = type;
1809 return !register_new_async (&ovp->async);
1811 error:
1812 close (fd);
1813 return FALSE;
1816 /***********************************************************************
1817 * WriteFileEx (KERNEL32.@)
1819 BOOL WINAPI WriteFileEx(HANDLE hFile, LPCVOID buffer, DWORD bytesToWrite,
1820 LPOVERLAPPED overlapped,
1821 LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine)
1823 overlapped->InternalHigh = 0;
1825 return FILE_WriteFileEx(hFile, buffer, bytesToWrite, overlapped, lpCompletionRoutine, INVALID_HANDLE_VALUE);
1828 /***********************************************************************
1829 * WriteFile (KERNEL32.@)
1831 BOOL WINAPI WriteFile( HANDLE hFile, LPCVOID buffer, DWORD bytesToWrite,
1832 LPDWORD bytesWritten, LPOVERLAPPED overlapped )
1834 int unix_handle, result, flags;
1835 enum fd_type type;
1837 TRACE("%d %p %ld %p %p\n", hFile, buffer, bytesToWrite,
1838 bytesWritten, overlapped );
1840 if (bytesWritten) *bytesWritten = 0; /* Do this before anything else */
1841 if (!bytesToWrite) return TRUE;
1843 unix_handle = FILE_GetUnixHandleType( hFile, GENERIC_WRITE, &type, &flags );
1845 if (flags & FD_FLAG_OVERLAPPED)
1847 if (unix_handle == -1) return FALSE;
1848 if ( (overlapped==NULL) || NtResetEvent( overlapped->hEvent, NULL ) )
1850 TRACE("Overlapped not specified or invalid event flag\n");
1851 close(unix_handle);
1852 SetLastError(ERROR_INVALID_PARAMETER);
1853 return FALSE;
1856 close(unix_handle);
1857 overlapped->InternalHigh = 0;
1859 if(!FILE_WriteFileEx(hFile, buffer, bytesToWrite, overlapped, NULL, overlapped->hEvent))
1860 return FALSE;
1862 if ( !GetOverlappedResult (hFile, overlapped, bytesWritten, FALSE) )
1864 if ( GetLastError() == ERROR_IO_INCOMPLETE )
1865 SetLastError ( ERROR_IO_PENDING );
1866 return FALSE;
1869 return TRUE;
1872 switch(type)
1874 case FD_TYPE_CONSOLE:
1875 TRACE("%d %s %ld %p %p\n", hFile, debugstr_an(buffer, bytesToWrite), bytesToWrite,
1876 bytesWritten, overlapped );
1877 return WriteConsoleA(hFile, buffer, bytesToWrite, bytesWritten, NULL);
1878 default:
1879 if (unix_handle == -1)
1880 return FALSE;
1883 /* synchronous file write */
1884 while ((result = write( unix_handle, buffer, bytesToWrite )) == -1)
1886 if ((errno == EAGAIN) || (errno == EINTR)) continue;
1887 if ((errno == EFAULT) && !IsBadReadPtr( buffer, bytesToWrite )) continue;
1888 if (errno == ENOSPC)
1889 SetLastError( ERROR_DISK_FULL );
1890 else
1891 FILE_SetDosError();
1892 break;
1894 close( unix_handle );
1895 if (result == -1) return FALSE;
1896 if (bytesWritten) *bytesWritten = result;
1897 return TRUE;
1901 /***********************************************************************
1902 * _hread (KERNEL.349)
1904 LONG WINAPI WIN16_hread( HFILE16 hFile, SEGPTR buffer, LONG count )
1906 LONG maxlen;
1908 TRACE("%d %08lx %ld\n",
1909 hFile, (DWORD)buffer, count );
1911 /* Some programs pass a count larger than the allocated buffer */
1912 maxlen = GetSelectorLimit16( SELECTOROF(buffer) ) - OFFSETOF(buffer) + 1;
1913 if (count > maxlen) count = maxlen;
1914 return _lread(DosFileHandleToWin32Handle(hFile), MapSL(buffer), count );
1918 /***********************************************************************
1919 * _lread (KERNEL.82)
1921 UINT16 WINAPI WIN16_lread( HFILE16 hFile, SEGPTR buffer, UINT16 count )
1923 return (UINT16)WIN16_hread( hFile, buffer, (LONG)count );
1927 /***********************************************************************
1928 * _lread (KERNEL32.@)
1930 UINT WINAPI _lread( HFILE handle, LPVOID buffer, UINT count )
1932 DWORD result;
1933 if (!ReadFile( handle, buffer, count, &result, NULL )) return -1;
1934 return result;
1938 /***********************************************************************
1939 * _lread16 (KERNEL.82)
1941 UINT16 WINAPI _lread16( HFILE16 hFile, LPVOID buffer, UINT16 count )
1943 return (UINT16)_lread(DosFileHandleToWin32Handle(hFile), buffer, (LONG)count );
1947 /***********************************************************************
1948 * _lcreat (KERNEL.83)
1950 HFILE16 WINAPI _lcreat16( LPCSTR path, INT16 attr )
1952 return Win32HandleToDosFileHandle( _lcreat( path, attr ) );
1956 /***********************************************************************
1957 * _lcreat (KERNEL32.@)
1959 HFILE WINAPI _lcreat( LPCSTR path, INT attr )
1961 /* Mask off all flags not explicitly allowed by the doc */
1962 attr &= FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM;
1963 TRACE("%s %02x\n", path, attr );
1964 return CreateFileA( path, GENERIC_READ | GENERIC_WRITE,
1965 FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
1966 CREATE_ALWAYS, attr, 0 );
1970 /***********************************************************************
1971 * SetFilePointer (KERNEL32.@)
1973 DWORD WINAPI SetFilePointer( HANDLE hFile, LONG distance, LONG *highword,
1974 DWORD method )
1976 DWORD ret = 0xffffffff;
1978 TRACE("handle %d offset %ld high %ld origin %ld\n",
1979 hFile, distance, highword?*highword:0, method );
1981 SERVER_START_REQ( set_file_pointer )
1983 req->handle = hFile;
1984 req->low = distance;
1985 req->high = highword ? *highword : (distance >= 0) ? 0 : -1;
1986 /* FIXME: assumes 1:1 mapping between Windows and Unix seek constants */
1987 req->whence = method;
1988 SetLastError( 0 );
1989 if (!wine_server_call_err( req ))
1991 ret = reply->new_low;
1992 if (highword) *highword = reply->new_high;
1995 SERVER_END_REQ;
1996 return ret;
2000 /***********************************************************************
2001 * _llseek (KERNEL.84)
2003 * FIXME:
2004 * Seeking before the start of the file should be allowed for _llseek16,
2005 * but cause subsequent I/O operations to fail (cf. interrupt list)
2008 LONG WINAPI _llseek16( HFILE16 hFile, LONG lOffset, INT16 nOrigin )
2010 return SetFilePointer( DosFileHandleToWin32Handle(hFile), lOffset, NULL, nOrigin );
2014 /***********************************************************************
2015 * _llseek (KERNEL32.@)
2017 LONG WINAPI _llseek( HFILE hFile, LONG lOffset, INT nOrigin )
2019 return SetFilePointer( hFile, lOffset, NULL, nOrigin );
2023 /***********************************************************************
2024 * _lopen (KERNEL.85)
2026 HFILE16 WINAPI _lopen16( LPCSTR path, INT16 mode )
2028 return Win32HandleToDosFileHandle( _lopen( path, mode ) );
2032 /***********************************************************************
2033 * _lopen (KERNEL32.@)
2035 HFILE WINAPI _lopen( LPCSTR path, INT mode )
2037 DWORD access, sharing;
2039 TRACE("('%s',%04x)\n", path, mode );
2040 FILE_ConvertOFMode( mode, &access, &sharing );
2041 return CreateFileA( path, access, sharing, NULL, OPEN_EXISTING, 0, 0 );
2045 /***********************************************************************
2046 * _lwrite (KERNEL.86)
2048 UINT16 WINAPI _lwrite16( HFILE16 hFile, LPCSTR buffer, UINT16 count )
2050 return (UINT16)_hwrite( DosFileHandleToWin32Handle(hFile), buffer, (LONG)count );
2053 /***********************************************************************
2054 * _lwrite (KERNEL32.@)
2056 UINT WINAPI _lwrite( HFILE hFile, LPCSTR buffer, UINT count )
2058 return (UINT)_hwrite( hFile, buffer, (LONG)count );
2062 /***********************************************************************
2063 * _hread16 (KERNEL.349)
2065 LONG WINAPI _hread16( HFILE16 hFile, LPVOID buffer, LONG count)
2067 return _lread( DosFileHandleToWin32Handle(hFile), buffer, count );
2071 /***********************************************************************
2072 * _hread (KERNEL32.@)
2074 LONG WINAPI _hread( HFILE hFile, LPVOID buffer, LONG count)
2076 return _lread( hFile, buffer, count );
2080 /***********************************************************************
2081 * _hwrite (KERNEL.350)
2083 LONG WINAPI _hwrite16( HFILE16 hFile, LPCSTR buffer, LONG count )
2085 return _hwrite( DosFileHandleToWin32Handle(hFile), buffer, count );
2089 /***********************************************************************
2090 * _hwrite (KERNEL32.@)
2092 * experimentation yields that _lwrite:
2093 * o truncates the file at the current position with
2094 * a 0 len write
2095 * o returns 0 on a 0 length write
2096 * o works with console handles
2099 LONG WINAPI _hwrite( HFILE handle, LPCSTR buffer, LONG count )
2101 DWORD result;
2103 TRACE("%d %p %ld\n", handle, buffer, count );
2105 if (!count)
2107 /* Expand or truncate at current position */
2108 if (!SetEndOfFile( handle )) return HFILE_ERROR;
2109 return 0;
2111 if (!WriteFile( handle, buffer, count, &result, NULL ))
2112 return HFILE_ERROR;
2113 return result;
2117 /***********************************************************************
2118 * SetHandleCount (KERNEL.199)
2120 UINT16 WINAPI SetHandleCount16( UINT16 count )
2122 return SetHandleCount( count );
2126 /*************************************************************************
2127 * SetHandleCount (KERNEL32.@)
2129 UINT WINAPI SetHandleCount( UINT count )
2131 return min( 256, count );
2135 /***********************************************************************
2136 * FlushFileBuffers (KERNEL32.@)
2138 BOOL WINAPI FlushFileBuffers( HANDLE hFile )
2140 BOOL ret;
2141 SERVER_START_REQ( flush_file )
2143 req->handle = hFile;
2144 ret = !wine_server_call_err( req );
2146 SERVER_END_REQ;
2147 return ret;
2151 /**************************************************************************
2152 * SetEndOfFile (KERNEL32.@)
2154 BOOL WINAPI SetEndOfFile( HANDLE hFile )
2156 BOOL ret;
2157 SERVER_START_REQ( truncate_file )
2159 req->handle = hFile;
2160 ret = !wine_server_call_err( req );
2162 SERVER_END_REQ;
2163 return ret;
2167 /***********************************************************************
2168 * DeleteFile (KERNEL.146)
2170 BOOL16 WINAPI DeleteFile16( LPCSTR path )
2172 return DeleteFileA( path );
2176 /***********************************************************************
2177 * DeleteFileA (KERNEL32.@)
2179 BOOL WINAPI DeleteFileA( LPCSTR path )
2181 DOS_FULL_NAME full_name;
2183 if (!path)
2185 SetLastError(ERROR_INVALID_PARAMETER);
2186 return FALSE;
2188 TRACE("'%s'\n", path );
2190 if (!*path)
2192 ERR("Empty path passed\n");
2193 return FALSE;
2195 if (DOSFS_GetDevice( path ))
2197 WARN("cannot remove DOS device '%s'!\n", path);
2198 SetLastError( ERROR_FILE_NOT_FOUND );
2199 return FALSE;
2202 if (!DOSFS_GetFullName( path, TRUE, &full_name )) return FALSE;
2203 if (unlink( full_name.long_name ) == -1)
2205 FILE_SetDosError();
2206 return FALSE;
2208 return TRUE;
2212 /***********************************************************************
2213 * DeleteFileW (KERNEL32.@)
2215 BOOL WINAPI DeleteFileW( LPCWSTR path )
2217 LPSTR xpath = HEAP_strdupWtoA( GetProcessHeap(), 0, path );
2218 BOOL ret = DeleteFileA( xpath );
2219 HeapFree( GetProcessHeap(), 0, xpath );
2220 return ret;
2224 /***********************************************************************
2225 * GetFileType (KERNEL32.@)
2227 DWORD WINAPI GetFileType( HANDLE hFile )
2229 DWORD ret = FILE_TYPE_UNKNOWN;
2230 SERVER_START_REQ( get_file_info )
2232 req->handle = hFile;
2233 if (!wine_server_call_err( req )) ret = reply->type;
2235 SERVER_END_REQ;
2236 return ret;
2240 /* check if a file name is for an executable file (.exe or .com) */
2241 inline static BOOL is_executable( const char *name )
2243 int len = strlen(name);
2245 if (len < 4) return FALSE;
2246 return (!strcasecmp( name + len - 4, ".exe" ) ||
2247 !strcasecmp( name + len - 4, ".com" ));
2251 /***********************************************************************
2252 * FILE_AddBootRenameEntry
2254 * Adds an entry to the registry that is loaded when windows boots and
2255 * checks if there are some files to be removed or renamed/moved.
2256 * <fn1> has to be valid and <fn2> may be NULL. If both pointers are
2257 * non-NULL then the file is moved, otherwise it is deleted. The
2258 * entry of the registrykey is always appended with two zero
2259 * terminated strings. If <fn2> is NULL then the second entry is
2260 * simply a single 0-byte. Otherwise the second filename goes
2261 * there. The entries are prepended with \??\ before the path and the
2262 * second filename gets also a '!' as the first character if
2263 * MOVEFILE_REPLACE_EXISTING is set. After the final string another
2264 * 0-byte follows to indicate the end of the strings.
2265 * i.e.:
2266 * \??\D:\test\file1[0]
2267 * !\??\D:\test\file1_renamed[0]
2268 * \??\D:\Test|delete[0]
2269 * [0] <- file is to be deleted, second string empty
2270 * \??\D:\test\file2[0]
2271 * !\??\D:\test\file2_renamed[0]
2272 * [0] <- indicates end of strings
2274 * or:
2275 * \??\D:\test\file1[0]
2276 * !\??\D:\test\file1_renamed[0]
2277 * \??\D:\Test|delete[0]
2278 * [0] <- file is to be deleted, second string empty
2279 * [0] <- indicates end of strings
2282 static BOOL FILE_AddBootRenameEntry( const char *fn1, const char *fn2, DWORD flags )
2284 static const char PreString[] = "\\??\\";
2285 static const char ValueName[] = "PendingFileRenameOperations";
2287 BOOL rc = FALSE;
2288 HKEY Reboot = 0;
2289 DWORD Type, len1, len2, l;
2290 DWORD DataSize = 0;
2291 BYTE *Buffer = NULL;
2293 if(RegCreateKeyA(HKEY_LOCAL_MACHINE, "SYSTEM\\CurrentControlSet\\Control\\Session Manager",
2294 &Reboot) != ERROR_SUCCESS)
2296 WARN("Error creating key for reboot managment [%s]\n",
2297 "SYSTEM\\CurrentControlSet\\Control\\Session Manager");
2298 return FALSE;
2301 l = strlen(PreString);
2302 len1 = strlen(fn1) + l + 1;
2303 if (fn2)
2305 len2 = strlen(fn2) + l + 1;
2306 if (flags & MOVEFILE_REPLACE_EXISTING) len2++; /* Plus 1 because of the leading '!' */
2308 else len2 = 1; /* minimum is the 0 byte for the empty second string */
2310 /* First we check if the key exists and if so how many bytes it already contains. */
2311 if (RegQueryValueExA(Reboot, ValueName, NULL, &Type, NULL, &DataSize) == ERROR_SUCCESS)
2313 if (Type != REG_MULTI_SZ) goto Quit;
2314 if (!(Buffer = HeapAlloc( GetProcessHeap(), 0, DataSize + len1 + len2 + 1 ))) goto Quit;
2315 if (RegQueryValueExA(Reboot, ValueName, NULL, &Type, Buffer, &DataSize) != ERROR_SUCCESS)
2316 goto Quit;
2317 if (DataSize) DataSize--; /* remove terminating null (will be added back later) */
2319 else
2321 if (!(Buffer = HeapAlloc( GetProcessHeap(), 0, len1 + len2 + 1 ))) goto Quit;
2322 DataSize = 0;
2324 sprintf( Buffer + DataSize, "%s%s", PreString, fn1 );
2325 DataSize += len1;
2326 if (fn2)
2328 sprintf( Buffer + DataSize, "%s%s%s",
2329 (flags & MOVEFILE_REPLACE_EXISTING) ? "!" : "", PreString, fn2 );
2330 DataSize += len2;
2332 else Buffer[DataSize++] = 0;
2334 Buffer[DataSize++] = 0; /* add final null */
2335 rc = !RegSetValueExA( Reboot, ValueName, 0, REG_MULTI_SZ, Buffer, DataSize );
2337 Quit:
2338 if (Reboot) RegCloseKey(Reboot);
2339 if (Buffer) HeapFree( GetProcessHeap(), 0, Buffer );
2340 return(rc);
2344 /**************************************************************************
2345 * MoveFileExA (KERNEL32.@)
2347 BOOL WINAPI MoveFileExA( LPCSTR fn1, LPCSTR fn2, DWORD flag )
2349 DOS_FULL_NAME full_name1, full_name2;
2351 TRACE("(%s,%s,%04lx)\n", fn1, fn2, flag);
2353 /* FIXME: <Gerhard W. Gruber>sparhawk@gmx.at
2354 In case of W9x and lesser this function should return 120 (ERROR_CALL_NOT_IMPLEMENTED)
2355 to be really compatible. Most programs wont have any problems though. In case
2356 you encounter one, this is what you should return here. I don't know what's up
2357 with NT 3.5. Is this function available there or not?
2358 Does anybody really care about 3.5? :)
2361 /* Filename1 has to be always set to a valid path. Filename2 may be NULL
2362 if the source file has to be deleted.
2364 if (!fn1) {
2365 SetLastError(ERROR_INVALID_PARAMETER);
2366 return FALSE;
2369 /* This function has to be run through in order to process the name properly.
2370 If the BOOTDELAY flag is set, the file doesn't need to exist though. At least
2371 that is the behaviour on NT 4.0. The operation accepts the filenames as
2372 they are given but it can't reply with a reasonable returncode. Success
2373 means in that case success for entering the values into the registry.
2375 if(!DOSFS_GetFullName( fn1, TRUE, &full_name1 ))
2377 if(!(flag & MOVEFILE_DELAY_UNTIL_REBOOT))
2378 return FALSE;
2381 if (fn2) /* !fn2 means delete fn1 */
2383 if (DOSFS_GetFullName( fn2, TRUE, &full_name2 ))
2385 if(!(flag & MOVEFILE_DELAY_UNTIL_REBOOT))
2387 /* target exists, check if we may overwrite */
2388 if (!(flag & MOVEFILE_REPLACE_EXISTING))
2390 /* FIXME: Use right error code */
2391 SetLastError( ERROR_ACCESS_DENIED );
2392 return FALSE;
2396 else
2398 if (!DOSFS_GetFullName( fn2, FALSE, &full_name2 ))
2400 if(!(flag & MOVEFILE_DELAY_UNTIL_REBOOT))
2401 return FALSE;
2405 /* Source name and target path are valid */
2407 if (flag & MOVEFILE_DELAY_UNTIL_REBOOT)
2409 /* FIXME: (bon@elektron.ikp.physik.th-darmstadt.de 970706)
2410 Perhaps we should queue these command and execute it
2411 when exiting... What about using on_exit(2)
2413 FIXME("Please move existing file '%s' to file '%s' when Wine has finished\n",
2414 fn1, fn2);
2415 return FILE_AddBootRenameEntry( fn1, fn2, flag );
2418 if (full_name1.drive != full_name2.drive)
2420 /* use copy, if allowed */
2421 if (!(flag & MOVEFILE_COPY_ALLOWED))
2423 /* FIXME: Use right error code */
2424 SetLastError( ERROR_FILE_EXISTS );
2425 return FALSE;
2427 return CopyFileA( fn1, fn2, !(flag & MOVEFILE_REPLACE_EXISTING) );
2429 if (rename( full_name1.long_name, full_name2.long_name ) == -1)
2431 FILE_SetDosError();
2432 return FALSE;
2434 if (is_executable( full_name1.long_name ) != is_executable( full_name2.long_name ))
2436 struct stat fstat;
2437 if (stat( full_name2.long_name, &fstat ) != -1)
2439 if (is_executable( full_name2.long_name ))
2440 /* set executable bit where read bit is set */
2441 fstat.st_mode |= (fstat.st_mode & 0444) >> 2;
2442 else
2443 fstat.st_mode &= ~0111;
2444 chmod( full_name2.long_name, fstat.st_mode );
2447 return TRUE;
2449 else /* fn2 == NULL means delete source */
2451 if (flag & MOVEFILE_DELAY_UNTIL_REBOOT)
2453 if (flag & MOVEFILE_COPY_ALLOWED) {
2454 WARN("Illegal flag\n");
2455 SetLastError( ERROR_GEN_FAILURE );
2456 return FALSE;
2458 /* FIXME: (bon@elektron.ikp.physik.th-darmstadt.de 970706)
2459 Perhaps we should queue these command and execute it
2460 when exiting... What about using on_exit(2)
2462 FIXME("Please delete file '%s' when Wine has finished\n", fn1);
2463 return FILE_AddBootRenameEntry( fn1, NULL, flag );
2466 if (unlink( full_name1.long_name ) == -1)
2468 FILE_SetDosError();
2469 return FALSE;
2471 return TRUE; /* successfully deleted */
2475 /**************************************************************************
2476 * MoveFileExW (KERNEL32.@)
2478 BOOL WINAPI MoveFileExW( LPCWSTR fn1, LPCWSTR fn2, DWORD flag )
2480 LPSTR afn1 = HEAP_strdupWtoA( GetProcessHeap(), 0, fn1 );
2481 LPSTR afn2 = HEAP_strdupWtoA( GetProcessHeap(), 0, fn2 );
2482 BOOL res = MoveFileExA( afn1, afn2, flag );
2483 HeapFree( GetProcessHeap(), 0, afn1 );
2484 HeapFree( GetProcessHeap(), 0, afn2 );
2485 return res;
2489 /**************************************************************************
2490 * MoveFileA (KERNEL32.@)
2492 * Move file or directory
2494 BOOL WINAPI MoveFileA( LPCSTR fn1, LPCSTR fn2 )
2496 DOS_FULL_NAME full_name1, full_name2;
2497 struct stat fstat;
2499 TRACE("(%s,%s)\n", fn1, fn2 );
2501 if (!DOSFS_GetFullName( fn1, TRUE, &full_name1 )) return FALSE;
2502 if (DOSFS_GetFullName( fn2, TRUE, &full_name2 )) {
2503 /* The new name must not already exist */
2504 SetLastError(ERROR_ALREADY_EXISTS);
2505 return FALSE;
2507 if (!DOSFS_GetFullName( fn2, FALSE, &full_name2 )) return FALSE;
2509 if (full_name1.drive == full_name2.drive) /* move */
2510 return MoveFileExA( fn1, fn2, MOVEFILE_COPY_ALLOWED );
2512 /* copy */
2513 if (stat( full_name1.long_name, &fstat ))
2515 WARN("Invalid source file %s\n",
2516 full_name1.long_name);
2517 FILE_SetDosError();
2518 return FALSE;
2520 if (S_ISDIR(fstat.st_mode)) {
2521 /* No Move for directories across file systems */
2522 /* FIXME: Use right error code */
2523 SetLastError( ERROR_GEN_FAILURE );
2524 return FALSE;
2526 return CopyFileA(fn1, fn2, TRUE); /*fail, if exist */
2530 /**************************************************************************
2531 * MoveFileW (KERNEL32.@)
2533 BOOL WINAPI MoveFileW( LPCWSTR fn1, LPCWSTR fn2 )
2535 LPSTR afn1 = HEAP_strdupWtoA( GetProcessHeap(), 0, fn1 );
2536 LPSTR afn2 = HEAP_strdupWtoA( GetProcessHeap(), 0, fn2 );
2537 BOOL res = MoveFileA( afn1, afn2 );
2538 HeapFree( GetProcessHeap(), 0, afn1 );
2539 HeapFree( GetProcessHeap(), 0, afn2 );
2540 return res;
2544 /**************************************************************************
2545 * CopyFileA (KERNEL32.@)
2547 BOOL WINAPI CopyFileA( LPCSTR source, LPCSTR dest, BOOL fail_if_exists )
2549 HFILE h1, h2;
2550 BY_HANDLE_FILE_INFORMATION info;
2551 UINT count;
2552 BOOL ret = FALSE;
2553 int mode;
2554 char buffer[2048];
2556 if ((h1 = _lopen( source, OF_READ )) == HFILE_ERROR) return FALSE;
2557 if (!GetFileInformationByHandle( h1, &info ))
2559 CloseHandle( h1 );
2560 return FALSE;
2562 mode = (info.dwFileAttributes & FILE_ATTRIBUTE_READONLY) ? 0444 : 0666;
2563 if ((h2 = CreateFileA( dest, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
2564 fail_if_exists ? CREATE_NEW : CREATE_ALWAYS,
2565 info.dwFileAttributes, h1 )) == INVALID_HANDLE_VALUE)
2567 CloseHandle( h1 );
2568 return FALSE;
2570 while ((count = _lread( h1, buffer, sizeof(buffer) )) > 0)
2572 char *p = buffer;
2573 while (count > 0)
2575 INT res = _lwrite( h2, p, count );
2576 if (res <= 0) goto done;
2577 p += res;
2578 count -= res;
2581 ret = TRUE;
2582 done:
2583 CloseHandle( h1 );
2584 CloseHandle( h2 );
2585 return ret;
2589 /**************************************************************************
2590 * CopyFileW (KERNEL32.@)
2592 BOOL WINAPI CopyFileW( LPCWSTR source, LPCWSTR dest, BOOL fail_if_exists)
2594 LPSTR sourceA = HEAP_strdupWtoA( GetProcessHeap(), 0, source );
2595 LPSTR destA = HEAP_strdupWtoA( GetProcessHeap(), 0, dest );
2596 BOOL ret = CopyFileA( sourceA, destA, fail_if_exists );
2597 HeapFree( GetProcessHeap(), 0, sourceA );
2598 HeapFree( GetProcessHeap(), 0, destA );
2599 return ret;
2603 /**************************************************************************
2604 * CopyFileExA (KERNEL32.@)
2606 * This implementation ignores most of the extra parameters passed-in into
2607 * the "ex" version of the method and calls the CopyFile method.
2608 * It will have to be fixed eventually.
2610 BOOL WINAPI CopyFileExA(LPCSTR sourceFilename,
2611 LPCSTR destFilename,
2612 LPPROGRESS_ROUTINE progressRoutine,
2613 LPVOID appData,
2614 LPBOOL cancelFlagPointer,
2615 DWORD copyFlags)
2617 BOOL failIfExists = FALSE;
2620 * Interpret the only flag that CopyFile can interpret.
2622 if ( (copyFlags & COPY_FILE_FAIL_IF_EXISTS) != 0)
2624 failIfExists = TRUE;
2627 return CopyFileA(sourceFilename, destFilename, failIfExists);
2630 /**************************************************************************
2631 * CopyFileExW (KERNEL32.@)
2633 BOOL WINAPI CopyFileExW(LPCWSTR sourceFilename,
2634 LPCWSTR destFilename,
2635 LPPROGRESS_ROUTINE progressRoutine,
2636 LPVOID appData,
2637 LPBOOL cancelFlagPointer,
2638 DWORD copyFlags)
2640 LPSTR sourceA = HEAP_strdupWtoA( GetProcessHeap(), 0, sourceFilename );
2641 LPSTR destA = HEAP_strdupWtoA( GetProcessHeap(), 0, destFilename );
2643 BOOL ret = CopyFileExA(sourceA,
2644 destA,
2645 progressRoutine,
2646 appData,
2647 cancelFlagPointer,
2648 copyFlags);
2650 HeapFree( GetProcessHeap(), 0, sourceA );
2651 HeapFree( GetProcessHeap(), 0, destA );
2653 return ret;
2657 /***********************************************************************
2658 * SetFileTime (KERNEL32.@)
2660 BOOL WINAPI SetFileTime( HANDLE hFile,
2661 const FILETIME *lpCreationTime,
2662 const FILETIME *lpLastAccessTime,
2663 const FILETIME *lpLastWriteTime )
2665 BOOL ret;
2666 SERVER_START_REQ( set_file_time )
2668 req->handle = hFile;
2669 if (lpLastAccessTime)
2670 RtlTimeToSecondsSince1970( lpLastAccessTime, (DWORD *)&req->access_time );
2671 else
2672 req->access_time = 0; /* FIXME */
2673 if (lpLastWriteTime)
2674 RtlTimeToSecondsSince1970( lpLastWriteTime, (DWORD *)&req->write_time );
2675 else
2676 req->write_time = 0; /* FIXME */
2677 ret = !wine_server_call_err( req );
2679 SERVER_END_REQ;
2680 return ret;
2684 /**************************************************************************
2685 * LockFile (KERNEL32.@)
2687 BOOL WINAPI LockFile( HANDLE hFile, DWORD dwFileOffsetLow, DWORD dwFileOffsetHigh,
2688 DWORD nNumberOfBytesToLockLow, DWORD nNumberOfBytesToLockHigh )
2690 BOOL ret;
2691 SERVER_START_REQ( lock_file )
2693 req->handle = hFile;
2694 req->offset_low = dwFileOffsetLow;
2695 req->offset_high = dwFileOffsetHigh;
2696 req->count_low = nNumberOfBytesToLockLow;
2697 req->count_high = nNumberOfBytesToLockHigh;
2698 ret = !wine_server_call_err( req );
2700 SERVER_END_REQ;
2701 return ret;
2704 /**************************************************************************
2705 * LockFileEx [KERNEL32.@]
2707 * Locks a byte range within an open file for shared or exclusive access.
2709 * RETURNS
2710 * success: TRUE
2711 * failure: FALSE
2713 * NOTES
2714 * Per Microsoft docs, the third parameter (reserved) must be set to 0.
2716 BOOL WINAPI LockFileEx( HANDLE hFile, DWORD flags, DWORD reserved,
2717 DWORD nNumberOfBytesToLockLow, DWORD nNumberOfBytesToLockHigh,
2718 LPOVERLAPPED pOverlapped )
2720 FIXME("hFile=%d,flags=%ld,reserved=%ld,lowbytes=%ld,highbytes=%ld,overlapped=%p: stub.\n",
2721 hFile, flags, reserved, nNumberOfBytesToLockLow, nNumberOfBytesToLockHigh,
2722 pOverlapped);
2723 if (reserved == 0)
2724 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
2725 else
2727 ERR("reserved == %ld: Supposed to be 0??\n", reserved);
2728 SetLastError(ERROR_INVALID_PARAMETER);
2731 return FALSE;
2735 /**************************************************************************
2736 * UnlockFile (KERNEL32.@)
2738 BOOL WINAPI UnlockFile( HANDLE hFile, DWORD dwFileOffsetLow, DWORD dwFileOffsetHigh,
2739 DWORD nNumberOfBytesToUnlockLow, DWORD nNumberOfBytesToUnlockHigh )
2741 BOOL ret;
2742 SERVER_START_REQ( unlock_file )
2744 req->handle = hFile;
2745 req->offset_low = dwFileOffsetLow;
2746 req->offset_high = dwFileOffsetHigh;
2747 req->count_low = nNumberOfBytesToUnlockLow;
2748 req->count_high = nNumberOfBytesToUnlockHigh;
2749 ret = !wine_server_call_err( req );
2751 SERVER_END_REQ;
2752 return ret;
2756 /**************************************************************************
2757 * UnlockFileEx (KERNEL32.@)
2759 BOOL WINAPI UnlockFileEx(
2760 HFILE hFile,
2761 DWORD dwReserved,
2762 DWORD nNumberOfBytesToUnlockLow,
2763 DWORD nNumberOfBytesToUnlockHigh,
2764 LPOVERLAPPED lpOverlapped
2767 FIXME("hFile=%d,reserved=%ld,lowbytes=%ld,highbytes=%ld,overlapped=%p: stub.\n",
2768 hFile, dwReserved, nNumberOfBytesToUnlockLow, nNumberOfBytesToUnlockHigh,
2769 lpOverlapped);
2770 if (dwReserved == 0)
2771 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
2772 else
2774 ERR("reserved == %ld: Supposed to be 0??\n", dwReserved);
2775 SetLastError(ERROR_INVALID_PARAMETER);
2778 return FALSE;
2782 #if 0
2784 struct DOS_FILE_LOCK {
2785 struct DOS_FILE_LOCK * next;
2786 DWORD base;
2787 DWORD len;
2788 DWORD processId;
2789 FILE_OBJECT * dos_file;
2790 /* char * unix_name;*/
2793 typedef struct DOS_FILE_LOCK DOS_FILE_LOCK;
2795 static DOS_FILE_LOCK *locks = NULL;
2796 static void DOS_RemoveFileLocks(FILE_OBJECT *file);
2799 /* Locks need to be mirrored because unix file locking is based
2800 * on the pid. Inside of wine there can be multiple WINE processes
2801 * that share the same unix pid.
2802 * Read's and writes should check these locks also - not sure
2803 * how critical that is at this point (FIXME).
2806 static BOOL DOS_AddLock(FILE_OBJECT *file, struct flock *f)
2808 DOS_FILE_LOCK *curr;
2809 DWORD processId;
2811 processId = GetCurrentProcessId();
2813 /* check if lock overlaps a current lock for the same file */
2814 #if 0
2815 for (curr = locks; curr; curr = curr->next) {
2816 if (strcmp(curr->unix_name, file->unix_name) == 0) {
2817 if ((f->l_start == curr->base) && (f->l_len == curr->len))
2818 return TRUE;/* region is identic */
2819 if ((f->l_start < (curr->base + curr->len)) &&
2820 ((f->l_start + f->l_len) > curr->base)) {
2821 /* region overlaps */
2822 return FALSE;
2826 #endif
2828 curr = HeapAlloc( GetProcessHeap(), 0, sizeof(DOS_FILE_LOCK) );
2829 curr->processId = GetCurrentProcessId();
2830 curr->base = f->l_start;
2831 curr->len = f->l_len;
2832 /* curr->unix_name = HEAP_strdupA( GetProcessHeap(), 0, file->unix_name);*/
2833 curr->next = locks;
2834 curr->dos_file = file;
2835 locks = curr;
2836 return TRUE;
2839 static void DOS_RemoveFileLocks(FILE_OBJECT *file)
2841 DWORD processId;
2842 DOS_FILE_LOCK **curr;
2843 DOS_FILE_LOCK *rem;
2845 processId = GetCurrentProcessId();
2846 curr = &locks;
2847 while (*curr) {
2848 if ((*curr)->dos_file == file) {
2849 rem = *curr;
2850 *curr = (*curr)->next;
2851 /* HeapFree( GetProcessHeap(), 0, rem->unix_name );*/
2852 HeapFree( GetProcessHeap(), 0, rem );
2854 else
2855 curr = &(*curr)->next;
2859 static BOOL DOS_RemoveLock(FILE_OBJECT *file, struct flock *f)
2861 DWORD processId;
2862 DOS_FILE_LOCK **curr;
2863 DOS_FILE_LOCK *rem;
2865 processId = GetCurrentProcessId();
2866 for (curr = &locks; *curr; curr = &(*curr)->next) {
2867 if ((*curr)->processId == processId &&
2868 (*curr)->dos_file == file &&
2869 (*curr)->base == f->l_start &&
2870 (*curr)->len == f->l_len) {
2871 /* this is the same lock */
2872 rem = *curr;
2873 *curr = (*curr)->next;
2874 /* HeapFree( GetProcessHeap(), 0, rem->unix_name );*/
2875 HeapFree( GetProcessHeap(), 0, rem );
2876 return TRUE;
2879 /* no matching lock found */
2880 return FALSE;
2884 /**************************************************************************
2885 * LockFile (KERNEL32.@)
2887 BOOL WINAPI LockFile(
2888 HFILE hFile,DWORD dwFileOffsetLow,DWORD dwFileOffsetHigh,
2889 DWORD nNumberOfBytesToLockLow,DWORD nNumberOfBytesToLockHigh )
2891 struct flock f;
2892 FILE_OBJECT *file;
2894 TRACE("handle %d offsetlow=%ld offsethigh=%ld nbyteslow=%ld nbyteshigh=%ld\n",
2895 hFile, dwFileOffsetLow, dwFileOffsetHigh,
2896 nNumberOfBytesToLockLow, nNumberOfBytesToLockHigh);
2898 if (dwFileOffsetHigh || nNumberOfBytesToLockHigh) {
2899 FIXME("Unimplemented bytes > 32bits\n");
2900 return FALSE;
2903 f.l_start = dwFileOffsetLow;
2904 f.l_len = nNumberOfBytesToLockLow;
2905 f.l_whence = SEEK_SET;
2906 f.l_pid = 0;
2907 f.l_type = F_WRLCK;
2909 if (!(file = FILE_GetFile(hFile,0,NULL))) return FALSE;
2911 /* shadow locks internally */
2912 if (!DOS_AddLock(file, &f)) {
2913 SetLastError( ERROR_LOCK_VIOLATION );
2914 return FALSE;
2917 /* FIXME: Unix locking commented out for now, doesn't work with Excel */
2918 #ifdef USE_UNIX_LOCKS
2919 if (fcntl(file->unix_handle, F_SETLK, &f) == -1) {
2920 if (errno == EACCES || errno == EAGAIN) {
2921 SetLastError( ERROR_LOCK_VIOLATION );
2923 else {
2924 FILE_SetDosError();
2926 /* remove our internal copy of the lock */
2927 DOS_RemoveLock(file, &f);
2928 return FALSE;
2930 #endif
2931 return TRUE;
2935 /**************************************************************************
2936 * UnlockFile (KERNEL32.@)
2938 BOOL WINAPI UnlockFile(
2939 HFILE hFile,DWORD dwFileOffsetLow,DWORD dwFileOffsetHigh,
2940 DWORD nNumberOfBytesToUnlockLow,DWORD nNumberOfBytesToUnlockHigh )
2942 FILE_OBJECT *file;
2943 struct flock f;
2945 TRACE("handle %d offsetlow=%ld offsethigh=%ld nbyteslow=%ld nbyteshigh=%ld\n",
2946 hFile, dwFileOffsetLow, dwFileOffsetHigh,
2947 nNumberOfBytesToUnlockLow, nNumberOfBytesToUnlockHigh);
2949 if (dwFileOffsetHigh || nNumberOfBytesToUnlockHigh) {
2950 WARN("Unimplemented bytes > 32bits\n");
2951 return FALSE;
2954 f.l_start = dwFileOffsetLow;
2955 f.l_len = nNumberOfBytesToUnlockLow;
2956 f.l_whence = SEEK_SET;
2957 f.l_pid = 0;
2958 f.l_type = F_UNLCK;
2960 if (!(file = FILE_GetFile(hFile,0,NULL))) return FALSE;
2962 DOS_RemoveLock(file, &f); /* ok if fails - may be another wine */
2964 /* FIXME: Unix locking commented out for now, doesn't work with Excel */
2965 #ifdef USE_UNIX_LOCKS
2966 if (fcntl(file->unix_handle, F_SETLK, &f) == -1) {
2967 FILE_SetDosError();
2968 return FALSE;
2970 #endif
2971 return TRUE;
2973 #endif
2975 /**************************************************************************
2976 * GetFileAttributesExA [KERNEL32.@]
2978 BOOL WINAPI GetFileAttributesExA(
2979 LPCSTR lpFileName, GET_FILEEX_INFO_LEVELS fInfoLevelId,
2980 LPVOID lpFileInformation)
2982 DOS_FULL_NAME full_name;
2983 BY_HANDLE_FILE_INFORMATION info;
2985 if (lpFileName == NULL) return FALSE;
2986 if (lpFileInformation == NULL) return FALSE;
2988 if (fInfoLevelId == GetFileExInfoStandard) {
2989 LPWIN32_FILE_ATTRIBUTE_DATA lpFad =
2990 (LPWIN32_FILE_ATTRIBUTE_DATA) lpFileInformation;
2991 if (!DOSFS_GetFullName( lpFileName, TRUE, &full_name )) return FALSE;
2992 if (!FILE_Stat( full_name.long_name, &info )) return FALSE;
2994 lpFad->dwFileAttributes = info.dwFileAttributes;
2995 lpFad->ftCreationTime = info.ftCreationTime;
2996 lpFad->ftLastAccessTime = info.ftLastAccessTime;
2997 lpFad->ftLastWriteTime = info.ftLastWriteTime;
2998 lpFad->nFileSizeHigh = info.nFileSizeHigh;
2999 lpFad->nFileSizeLow = info.nFileSizeLow;
3001 else {
3002 FIXME("invalid info level %d!\n", fInfoLevelId);
3003 return FALSE;
3006 return TRUE;
3010 /**************************************************************************
3011 * GetFileAttributesExW [KERNEL32.@]
3013 BOOL WINAPI GetFileAttributesExW(
3014 LPCWSTR lpFileName, GET_FILEEX_INFO_LEVELS fInfoLevelId,
3015 LPVOID lpFileInformation)
3017 LPSTR nameA = HEAP_strdupWtoA( GetProcessHeap(), 0, lpFileName );
3018 BOOL res =
3019 GetFileAttributesExA( nameA, fInfoLevelId, lpFileInformation);
3020 HeapFree( GetProcessHeap(), 0, nameA );
3021 return res;