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
22 * Fix the CopyFileEx methods to implement the "extended" functionality.
23 * Right now, they simply call the CopyFile method.
27 #include "wine/port.h"
36 #ifdef HAVE_SYS_ERRNO_H
37 #include <sys/errno.h>
39 #include <sys/types.h>
41 #ifdef HAVE_SYS_MMAN_H
44 #ifdef HAVE_SYS_TIME_H
45 # include <sys/time.h>
47 #ifdef HAVE_SYS_POLL_H
48 # include <sys/poll.h>
62 #include "wine/winbase16.h"
63 #include "wine/server.h"
73 #include "wine/unicode.h"
74 #include "wine/debug.h"
76 WINE_DEFAULT_DEBUG_CHANNEL(file
);
78 #if defined(MAP_ANONYMOUS) && !defined(MAP_ANON)
79 #define MAP_ANON MAP_ANONYMOUS
82 /* Size of per-process table of DOS handles */
83 #define DOS_TABLE_SIZE 256
85 /* Macro to derive file offset from OVERLAPPED struct */
86 #define OVERLAPPED_OFFSET(overlapped) ((off_t) (overlapped)->Offset + ((off_t) (overlapped)->OffsetHigh << 32))
88 static HANDLE dos_handles
[DOS_TABLE_SIZE
];
92 extern HANDLE WINAPI
FILE_SmbOpen(LPCSTR name
);
94 /***********************************************************************
95 * Asynchronous file I/O *
97 static DWORD
fileio_get_async_status (const async_private
*ovp
);
98 static DWORD
fileio_get_async_count (const async_private
*ovp
);
99 static void fileio_set_async_status (async_private
*ovp
, const DWORD status
);
100 static void CALLBACK
fileio_call_completion_func (ULONG_PTR data
);
101 static void fileio_async_cleanup (async_private
*ovp
);
103 static async_ops fileio_async_ops
=
105 fileio_get_async_status
, /* get_status */
106 fileio_set_async_status
, /* set_status */
107 fileio_get_async_count
, /* get_count */
108 fileio_call_completion_func
, /* call_completion */
109 fileio_async_cleanup
/* cleanup */
112 static async_ops fileio_nocomp_async_ops
=
114 fileio_get_async_status
, /* get_status */
115 fileio_set_async_status
, /* set_status */
116 fileio_get_async_count
, /* get_count */
117 NULL
, /* call_completion */
118 fileio_async_cleanup
/* cleanup */
121 typedef struct async_fileio
123 struct async_private async
;
124 LPOVERLAPPED lpOverlapped
;
125 LPOVERLAPPED_COMPLETION_ROUTINE completion_func
;
128 enum fd_type fd_type
;
131 static DWORD
fileio_get_async_status (const struct async_private
*ovp
)
133 return ((async_fileio
*) ovp
)->lpOverlapped
->Internal
;
136 static void fileio_set_async_status (async_private
*ovp
, const DWORD status
)
138 ((async_fileio
*) ovp
)->lpOverlapped
->Internal
= status
;
141 static DWORD
fileio_get_async_count (const struct async_private
*ovp
)
143 async_fileio
*fileio
= (async_fileio
*) ovp
;
145 if (fileio
->count
< fileio
->lpOverlapped
->InternalHigh
)
147 return fileio
->count
- fileio
->lpOverlapped
->InternalHigh
;
150 static void CALLBACK
fileio_call_completion_func (ULONG_PTR data
)
152 async_fileio
*ovp
= (async_fileio
*) data
;
153 TRACE ("data: %p\n", ovp
);
155 ovp
->completion_func( ovp
->lpOverlapped
->Internal
,
156 ovp
->lpOverlapped
->InternalHigh
,
159 fileio_async_cleanup ( &ovp
->async
);
162 static void fileio_async_cleanup ( struct async_private
*ovp
)
164 HeapFree ( GetProcessHeap(), 0, ovp
);
167 /***********************************************************************
170 * Convert OF_* mode into flags for CreateFile.
172 static void FILE_ConvertOFMode( INT mode
, DWORD
*access
, DWORD
*sharing
)
176 case OF_READ
: *access
= GENERIC_READ
; break;
177 case OF_WRITE
: *access
= GENERIC_WRITE
; break;
178 case OF_READWRITE
: *access
= GENERIC_READ
| GENERIC_WRITE
; break;
179 default: *access
= 0; break;
183 case OF_SHARE_EXCLUSIVE
: *sharing
= 0; break;
184 case OF_SHARE_DENY_WRITE
: *sharing
= FILE_SHARE_READ
; break;
185 case OF_SHARE_DENY_READ
: *sharing
= FILE_SHARE_WRITE
; break;
186 case OF_SHARE_DENY_NONE
:
187 case OF_SHARE_COMPAT
:
188 default: *sharing
= FILE_SHARE_READ
| FILE_SHARE_WRITE
; break;
193 /***********************************************************************
196 * locale-independent case conversion for file I/O
198 int FILE_strcasecmp( const char *str1
, const char *str2
)
201 for ( ; ; str1
++, str2
++)
202 if ((ret
= FILE_toupper(*str1
) - FILE_toupper(*str2
)) || !*str1
) break;
207 /***********************************************************************
210 * locale-independent case conversion for file I/O
212 int FILE_strncasecmp( const char *str1
, const char *str2
, int len
)
215 for ( ; len
> 0; len
--, str1
++, str2
++)
216 if ((ret
= FILE_toupper(*str1
) - FILE_toupper(*str2
)) || !*str1
) break;
221 /***********************************************************************
222 * FILE_GetNtStatus(void)
224 * Retrieve the Nt Status code from errno.
225 * Try to be consistent with FILE_SetDosError().
227 DWORD
FILE_GetNtStatus(void)
231 TRACE ( "errno = %d\n", errno
);
234 case EAGAIN
: nt
= STATUS_SHARING_VIOLATION
; break;
235 case EBADF
: nt
= STATUS_INVALID_HANDLE
; break;
236 case ENOSPC
: nt
= STATUS_DISK_FULL
; break;
239 case EACCES
: nt
= STATUS_ACCESS_DENIED
; break;
240 case ENOENT
: nt
= STATUS_SHARING_VIOLATION
; break;
241 case EISDIR
: nt
= STATUS_FILE_IS_A_DIRECTORY
; break;
243 case ENFILE
: nt
= STATUS_NO_MORE_FILES
; break;
245 case ENOTEMPTY
: nt
= STATUS_DIRECTORY_NOT_EMPTY
; break;
246 case EPIPE
: nt
= STATUS_PIPE_BROKEN
; break;
247 case ENOEXEC
: /* ?? */
248 case ESPIPE
: /* ?? */
249 case EEXIST
: /* ?? */
251 FIXME ( "Converting errno %d to STATUS_UNSUCCESSFUL\n", err
);
252 nt
= STATUS_UNSUCCESSFUL
;
257 /***********************************************************************
260 * Set the DOS error code from errno.
262 void FILE_SetDosError(void)
264 int save_errno
= errno
; /* errno gets overwritten by printf */
266 TRACE("errno = %d %s\n", errno
, strerror(errno
));
270 SetLastError( ERROR_SHARING_VIOLATION
);
273 SetLastError( ERROR_INVALID_HANDLE
);
276 SetLastError( ERROR_HANDLE_DISK_FULL
);
281 SetLastError( ERROR_ACCESS_DENIED
);
284 SetLastError( ERROR_LOCK_VIOLATION
);
287 SetLastError( ERROR_FILE_NOT_FOUND
);
290 SetLastError( ERROR_CANNOT_MAKE
);
294 SetLastError( ERROR_NO_MORE_FILES
);
297 SetLastError( ERROR_FILE_EXISTS
);
301 SetLastError( ERROR_SEEK
);
304 SetLastError( ERROR_DIR_NOT_EMPTY
);
307 SetLastError( ERROR_BAD_FORMAT
);
310 WARN("unknown file error: %s\n", strerror(save_errno
) );
311 SetLastError( ERROR_GEN_FAILURE
);
318 /***********************************************************************
319 * FILE_GetUnixHandleType
321 * Retrieve the Unix handle corresponding to a file handle.
322 * Returns -1 on failure.
324 static int FILE_GetUnixHandleType( HANDLE handle
, DWORD access
, enum fd_type
*type
, int *flags_ptr
)
326 int ret
, flags
, fd
= -1;
328 ret
= wine_server_handle_to_fd( handle
, access
, &fd
, type
, &flags
);
329 if (flags_ptr
) *flags_ptr
= flags
;
330 if (ret
) SetLastError( RtlNtStatusToDosError(ret
) );
331 else if (((access
& GENERIC_READ
) && (flags
& FD_FLAG_RECV_SHUTDOWN
)) ||
332 ((access
& GENERIC_WRITE
) && (flags
& FD_FLAG_SEND_SHUTDOWN
)))
335 SetLastError ( ERROR_PIPE_NOT_CONNECTED
);
341 /***********************************************************************
344 * Retrieve the Unix handle corresponding to a file handle.
345 * Returns -1 on failure.
347 int FILE_GetUnixHandle( HANDLE handle
, DWORD access
)
349 return FILE_GetUnixHandleType( handle
, access
, NULL
, NULL
);
352 /*************************************************************************
355 * Open a handle to the current process console.
356 * Returns 0 on failure.
358 static HANDLE
FILE_OpenConsole( BOOL output
, DWORD access
, DWORD sharing
, LPSECURITY_ATTRIBUTES sa
)
362 SERVER_START_REQ( open_console
)
365 req
->access
= access
;
366 req
->share
= sharing
;
367 req
->inherit
= (sa
&& (sa
->nLength
>=sizeof(*sa
)) && sa
->bInheritHandle
);
369 wine_server_call_err( req
);
376 /* FIXME: those routines defined as pointers are needed, because this file is
377 * currently compiled into NTDLL whereas it belongs to kernel32.
378 * this shall go away once all the DLL separation process is done
380 typedef BOOL (WINAPI
* pRW
)(HANDLE
, const void*, DWORD
, DWORD
*, void*);
382 static BOOL
FILE_ReadConsole(HANDLE hCon
, void* buf
, DWORD nb
, DWORD
* nr
, void* p
)
384 static HANDLE hKernel
/* = 0 */;
385 static pRW pReadConsole
/* = 0 */;
387 if ((!hKernel
&& !(hKernel
= LoadLibraryA("kernel32"))) ||
389 !(pReadConsole
= GetProcAddress(hKernel
, "ReadConsoleA"))))
394 return (pReadConsole
)(hCon
, buf
, nb
, nr
, p
);
397 static BOOL
FILE_WriteConsole(HANDLE hCon
, const void* buf
, DWORD nb
, DWORD
* nr
, void* p
)
399 static HANDLE hKernel
/* = 0 */;
400 static pRW pWriteConsole
/* = 0 */;
402 if ((!hKernel
&& !(hKernel
= LoadLibraryA("kernel32"))) ||
404 !(pWriteConsole
= GetProcAddress(hKernel
, "WriteConsoleA"))))
409 return (pWriteConsole
)(hCon
, buf
, nb
, nr
, p
);
413 /***********************************************************************
416 * Implementation of CreateFile. Takes a Unix path name.
417 * Returns 0 on failure.
419 HANDLE
FILE_CreateFile( LPCSTR filename
, DWORD access
, DWORD sharing
,
420 LPSECURITY_ATTRIBUTES sa
, DWORD creation
,
421 DWORD attributes
, HANDLE
template, BOOL fail_read_only
,
429 SERVER_START_REQ( create_file
)
431 req
->access
= access
;
432 req
->inherit
= (sa
&& (sa
->nLength
>=sizeof(*sa
)) && sa
->bInheritHandle
);
433 req
->sharing
= sharing
;
434 req
->create
= creation
;
435 req
->attrs
= attributes
;
436 req
->drive_type
= drive_type
;
437 wine_server_add_data( req
, filename
, strlen(filename
) );
439 err
= wine_server_call( req
);
444 /* If write access failed, retry without GENERIC_WRITE */
446 if (!ret
&& !fail_read_only
&& (access
& GENERIC_WRITE
))
448 if ((err
== STATUS_MEDIA_WRITE_PROTECTED
) || (err
== STATUS_ACCESS_DENIED
))
450 TRACE("Write access failed for file '%s', trying without "
451 "write access\n", filename
);
452 access
&= ~GENERIC_WRITE
;
459 /* In the case file creation was rejected due to CREATE_NEW flag
460 * was specified and file with that name already exists, correct
461 * last error is ERROR_FILE_EXISTS and not ERROR_ALREADY_EXISTS.
462 * Note: RtlNtStatusToDosError is not the subject to blame here.
464 if (err
== STATUS_OBJECT_NAME_COLLISION
)
465 SetLastError( ERROR_FILE_EXISTS
);
467 SetLastError( RtlNtStatusToDosError(err
) );
470 if (!ret
) WARN("Unable to create file '%s' (GLE %ld)\n", filename
, GetLastError());
476 /***********************************************************************
479 * Same as FILE_CreateFile but for a device
480 * Returns 0 on failure.
482 HANDLE
FILE_CreateDevice( int client_id
, DWORD access
, LPSECURITY_ATTRIBUTES sa
)
485 SERVER_START_REQ( create_device
)
487 req
->access
= access
;
488 req
->inherit
= (sa
&& (sa
->nLength
>=sizeof(*sa
)) && sa
->bInheritHandle
);
491 wine_server_call_err( req
);
498 static HANDLE
FILE_OpenPipe(LPCWSTR name
, DWORD access
)
503 if (name
&& (len
= strlenW(name
)) > MAX_PATH
)
505 SetLastError( ERROR_FILENAME_EXCED_RANGE
);
508 SERVER_START_REQ( open_named_pipe
)
510 req
->access
= access
;
512 wine_server_add_data( req
, name
, len
* sizeof(WCHAR
) );
513 wine_server_call_err( req
);
517 TRACE("Returned %d\n",ret
);
521 /*************************************************************************
522 * CreateFileW [KERNEL32.@] Creates or opens a file or other object
524 * Creates or opens an object, and returns a handle that can be used to
525 * access that object.
529 * filename [in] pointer to filename to be accessed
530 * access [in] access mode requested
531 * sharing [in] share mode
532 * sa [in] pointer to security attributes
533 * creation [in] how to create the file
534 * attributes [in] attributes for newly created file
535 * template [in] handle to file with extended attributes to copy
538 * Success: Open handle to specified file
539 * Failure: INVALID_HANDLE_VALUE
542 * Should call SetLastError() on failure.
546 * Doesn't support character devices, template files, or a
547 * lot of the 'attributes' flags yet.
549 HANDLE WINAPI
CreateFileW( LPCWSTR filename
, DWORD access
, DWORD sharing
,
550 LPSECURITY_ATTRIBUTES sa
, DWORD creation
,
551 DWORD attributes
, HANDLE
template )
553 DOS_FULL_NAME full_name
;
555 static const WCHAR bkslashes_with_question_markW
[] = {'\\','\\','?','\\',0};
556 static const WCHAR bkslashes_with_dotW
[] = {'\\','\\','.','\\',0};
557 static const WCHAR bkslashesW
[] = {'\\','\\',0};
558 static const WCHAR coninW
[] = {'C','O','N','I','N','$',0};
559 static const WCHAR conoutW
[] = {'C','O','N','O','U','T','$',0};
563 SetLastError( ERROR_INVALID_PARAMETER
);
564 return INVALID_HANDLE_VALUE
;
566 TRACE("%s %s%s%s%s%s%s%s attributes 0x%lx\n", debugstr_w(filename
),
567 ((access
& GENERIC_READ
)==GENERIC_READ
)?"GENERIC_READ ":"",
568 ((access
& GENERIC_WRITE
)==GENERIC_WRITE
)?"GENERIC_WRITE ":"",
569 (!access
)?"QUERY_ACCESS ":"",
570 ((sharing
& FILE_SHARE_READ
)==FILE_SHARE_READ
)?"FILE_SHARE_READ ":"",
571 ((sharing
& FILE_SHARE_WRITE
)==FILE_SHARE_WRITE
)?"FILE_SHARE_WRITE ":"",
572 ((sharing
& FILE_SHARE_DELETE
)==FILE_SHARE_DELETE
)?"FILE_SHARE_DELETE ":"",
573 (creation
==CREATE_NEW
)?"CREATE_NEW":
574 (creation
==CREATE_ALWAYS
)?"CREATE_ALWAYS ":
575 (creation
==OPEN_EXISTING
)?"OPEN_EXISTING ":
576 (creation
==OPEN_ALWAYS
)?"OPEN_ALWAYS ":
577 (creation
==TRUNCATE_EXISTING
)?"TRUNCATE_EXISTING ":"", attributes
);
579 /* If the name starts with '\\?\', ignore the first 4 chars. */
580 if (!strncmpW(filename
, bkslashes_with_question_markW
, 4))
582 static const WCHAR uncW
[] = {'U','N','C','\\',0};
584 if (!strncmpiW(filename
, uncW
, 4))
586 FIXME("UNC name (%s) not supported.\n", debugstr_w(filename
) );
587 SetLastError( ERROR_PATH_NOT_FOUND
);
588 return INVALID_HANDLE_VALUE
;
592 if (!strncmpW(filename
, bkslashes_with_dotW
, 4))
594 static const WCHAR pipeW
[] = {'P','I','P','E','\\',0};
595 if(!strncmpiW(filename
+ 4, pipeW
, 5))
597 TRACE("Opening a pipe: %s\n", debugstr_w(filename
));
598 ret
= FILE_OpenPipe(filename
,access
);
601 else if (isalphaW(filename
[4]) && filename
[5] == ':' && filename
[6] == '\0')
603 ret
= FILE_CreateDevice( (toupperW(filename
[4]) - 'A') | 0x20000, access
, sa
);
606 else if (!DOSFS_GetDevice( filename
))
608 ret
= DEVICE_Open( filename
+4, access
, sa
);
612 filename
+=4; /* fall into DOSFS_Device case below */
615 /* If the name still starts with '\\', it's a UNC name. */
616 if (!strncmpW(filename
, bkslashesW
, 2))
618 ret
= SMB_CreateFileW(filename
, access
, sharing
, sa
, creation
, attributes
, template );
622 /* If the name contains a DOS wild card (* or ?), do no create a file */
623 if(strchrW(filename
, '*') || strchrW(filename
, '?'))
624 return INVALID_HANDLE_VALUE
;
626 /* Open a console for CONIN$ or CONOUT$ */
627 if (!strcmpiW(filename
, coninW
))
629 ret
= FILE_OpenConsole( FALSE
, access
, sharing
, sa
);
632 if (!strcmpiW(filename
, conoutW
))
634 ret
= FILE_OpenConsole( TRUE
, access
, sharing
, sa
);
638 if (DOSFS_GetDevice( filename
))
640 TRACE("opening device %s\n", debugstr_w(filename
) );
642 if (!(ret
= DOSFS_OpenDevice( filename
, access
, attributes
, sa
)))
644 /* Do not silence this please. It is a critical error. -MM */
645 ERR("Couldn't open device %s!\n", debugstr_w(filename
));
646 SetLastError( ERROR_FILE_NOT_FOUND
);
651 /* check for filename, don't check for last entry if creating */
652 if (!DOSFS_GetFullName( filename
,
653 (creation
== OPEN_EXISTING
) ||
654 (creation
== TRUNCATE_EXISTING
),
656 WARN("Unable to get full filename from %s (GLE %ld)\n",
657 debugstr_w(filename
), GetLastError());
658 return INVALID_HANDLE_VALUE
;
661 ret
= FILE_CreateFile( full_name
.long_name
, access
, sharing
,
662 sa
, creation
, attributes
, template,
663 DRIVE_GetFlags(full_name
.drive
) & DRIVE_FAIL_READ_ONLY
,
664 GetDriveTypeW( full_name
.short_name
) );
666 if (!ret
) ret
= INVALID_HANDLE_VALUE
;
667 TRACE("returning %08x\n", ret
);
673 /*************************************************************************
674 * CreateFileA (KERNEL32.@)
676 HANDLE WINAPI
CreateFileA( LPCSTR filename
, DWORD access
, DWORD sharing
,
677 LPSECURITY_ATTRIBUTES sa
, DWORD creation
,
678 DWORD attributes
, HANDLE
template)
680 UNICODE_STRING filenameW
;
681 HANDLE ret
= INVALID_HANDLE_VALUE
;
685 SetLastError( ERROR_INVALID_PARAMETER
);
686 return INVALID_HANDLE_VALUE
;
689 if (RtlCreateUnicodeStringFromAsciiz(&filenameW
, filename
))
691 ret
= CreateFileW(filenameW
.Buffer
, access
, sharing
, sa
, creation
,
692 attributes
, template);
693 RtlFreeUnicodeString(&filenameW
);
696 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
701 /***********************************************************************
704 * Fill a file information from a struct stat.
706 static void FILE_FillInfo( struct stat
*st
, BY_HANDLE_FILE_INFORMATION
*info
)
708 if (S_ISDIR(st
->st_mode
))
709 info
->dwFileAttributes
= FILE_ATTRIBUTE_DIRECTORY
;
711 info
->dwFileAttributes
= FILE_ATTRIBUTE_ARCHIVE
;
712 if (!(st
->st_mode
& S_IWUSR
))
713 info
->dwFileAttributes
|= FILE_ATTRIBUTE_READONLY
;
715 RtlSecondsSince1970ToTime( st
->st_mtime
, (LARGE_INTEGER
*)&info
->ftCreationTime
);
716 RtlSecondsSince1970ToTime( st
->st_mtime
, (LARGE_INTEGER
*)&info
->ftLastWriteTime
);
717 RtlSecondsSince1970ToTime( st
->st_atime
, (LARGE_INTEGER
*)&info
->ftLastAccessTime
);
719 info
->dwVolumeSerialNumber
= 0; /* FIXME */
720 info
->nFileSizeHigh
= 0;
721 info
->nFileSizeLow
= 0;
722 if (!S_ISDIR(st
->st_mode
)) {
723 info
->nFileSizeHigh
= st
->st_size
>> 32;
724 info
->nFileSizeLow
= st
->st_size
& 0xffffffff;
726 info
->nNumberOfLinks
= st
->st_nlink
;
727 info
->nFileIndexHigh
= 0;
728 info
->nFileIndexLow
= st
->st_ino
;
732 /***********************************************************************
735 * Stat a Unix path name. Return TRUE if OK.
737 BOOL
FILE_Stat( LPCSTR unixName
, BY_HANDLE_FILE_INFORMATION
*info
, BOOL
*is_symlink_ptr
)
743 if (lstat( unixName
, &st
) == -1)
748 is_symlink
= S_ISLNK(st
.st_mode
);
751 /* do a "real" stat to find out
752 about the type of the symlink destination */
753 if (stat( unixName
, &st
) == -1)
760 /* fill in the information we gathered so far */
761 FILE_FillInfo( &st
, info
);
763 /* and now see if this is a hidden file, based on the name */
764 p
= strrchr( unixName
, '/');
765 p
= p
? p
+ 1 : unixName
;
766 if (*p
== '.' && *(p
+1) && (*(p
+1) != '.' || *(p
+2)))
768 static const WCHAR wineW
[] = {'w','i','n','e',0};
769 static const WCHAR ShowDotFilesW
[] = {'S','h','o','w','D','o','t','F','i','l','e','s',0};
770 static int show_dot_files
= -1;
771 if (show_dot_files
== -1)
772 show_dot_files
= PROFILE_GetWineIniBool(wineW
, ShowDotFilesW
, 0);
774 info
->dwFileAttributes
|= FILE_ATTRIBUTE_HIDDEN
;
776 if (is_symlink_ptr
) *is_symlink_ptr
= is_symlink
;
781 /***********************************************************************
782 * GetFileInformationByHandle (KERNEL32.@)
784 DWORD WINAPI
GetFileInformationByHandle( HANDLE hFile
,
785 BY_HANDLE_FILE_INFORMATION
*info
)
790 TRACE("%08x\n", hFile
);
792 SERVER_START_REQ( get_file_info
)
795 if ((ret
= !wine_server_call_err( req
)))
797 /* FIXME: which file types are supported ?
798 * Serial ports (FILE_TYPE_CHAR) are not,
799 * and MSDN also says that pipes are not supported.
800 * FILE_TYPE_REMOTE seems to be supported according to
801 * MSDN q234741.txt */
802 if ((reply
->type
== FILE_TYPE_DISK
) || (reply
->type
== FILE_TYPE_REMOTE
))
804 RtlSecondsSince1970ToTime( reply
->write_time
, (LARGE_INTEGER
*)&info
->ftCreationTime
);
805 RtlSecondsSince1970ToTime( reply
->write_time
, (LARGE_INTEGER
*)&info
->ftLastWriteTime
);
806 RtlSecondsSince1970ToTime( reply
->access_time
, (LARGE_INTEGER
*)&info
->ftLastAccessTime
);
807 info
->dwFileAttributes
= reply
->attr
;
808 info
->dwVolumeSerialNumber
= reply
->serial
;
809 info
->nFileSizeHigh
= reply
->size_high
;
810 info
->nFileSizeLow
= reply
->size_low
;
811 info
->nNumberOfLinks
= reply
->links
;
812 info
->nFileIndexHigh
= reply
->index_high
;
813 info
->nFileIndexLow
= reply
->index_low
;
817 SetLastError(ERROR_NOT_SUPPORTED
);
827 /**************************************************************************
828 * GetFileAttributes (KERNEL.420)
830 DWORD WINAPI
GetFileAttributes16( LPCSTR name
)
832 return GetFileAttributesA( name
);
836 /**************************************************************************
837 * GetFileAttributesW (KERNEL32.@)
839 DWORD WINAPI
GetFileAttributesW( LPCWSTR name
)
841 DOS_FULL_NAME full_name
;
842 BY_HANDLE_FILE_INFORMATION info
;
846 SetLastError( ERROR_INVALID_PARAMETER
);
849 if (!DOSFS_GetFullName( name
, TRUE
, &full_name
) )
851 if (!FILE_Stat( full_name
.long_name
, &info
, NULL
)) return -1;
852 return info
.dwFileAttributes
;
856 /**************************************************************************
857 * GetFileAttributesA (KERNEL32.@)
859 DWORD WINAPI
GetFileAttributesA( LPCSTR name
)
861 UNICODE_STRING nameW
;
862 DWORD ret
= (DWORD
)-1;
866 SetLastError( ERROR_INVALID_PARAMETER
);
870 if (RtlCreateUnicodeStringFromAsciiz(&nameW
, name
))
872 ret
= GetFileAttributesW(nameW
.Buffer
);
873 RtlFreeUnicodeString(&nameW
);
876 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
881 /**************************************************************************
882 * SetFileAttributes (KERNEL.421)
884 BOOL16 WINAPI
SetFileAttributes16( LPCSTR lpFileName
, DWORD attributes
)
886 return SetFileAttributesA( lpFileName
, attributes
);
890 /**************************************************************************
891 * SetFileAttributesW (KERNEL32.@)
893 BOOL WINAPI
SetFileAttributesW(LPCWSTR lpFileName
, DWORD attributes
)
896 DOS_FULL_NAME full_name
;
900 SetLastError( ERROR_INVALID_PARAMETER
);
904 TRACE("(%s,%lx)\n", debugstr_w(lpFileName
), attributes
);
906 if (!DOSFS_GetFullName( lpFileName
, TRUE
, &full_name
))
909 if(stat(full_name
.long_name
,&buf
)==-1)
914 if (attributes
& FILE_ATTRIBUTE_READONLY
)
916 if(S_ISDIR(buf
.st_mode
))
918 WARN("FILE_ATTRIBUTE_READONLY ignored for directory.\n");
920 buf
.st_mode
&= ~0222; /* octal!, clear write permission bits */
921 attributes
&= ~FILE_ATTRIBUTE_READONLY
;
925 /* add write permission */
926 buf
.st_mode
|= (0600 | ((buf
.st_mode
& 044) >> 1)) & (~FILE_umask
);
928 if (attributes
& FILE_ATTRIBUTE_DIRECTORY
)
930 if (!S_ISDIR(buf
.st_mode
))
931 FIXME("SetFileAttributes expected the file %s to be a directory\n",
932 debugstr_w(lpFileName
));
933 attributes
&= ~FILE_ATTRIBUTE_DIRECTORY
;
935 attributes
&= ~(FILE_ATTRIBUTE_NORMAL
|FILE_ATTRIBUTE_ARCHIVE
|FILE_ATTRIBUTE_HIDDEN
|FILE_ATTRIBUTE_SYSTEM
);
937 FIXME("(%s):%lx attribute(s) not implemented.\n", debugstr_w(lpFileName
), attributes
);
938 if (-1==chmod(full_name
.long_name
,buf
.st_mode
))
940 if (GetDriveTypeW(lpFileName
) == DRIVE_CDROM
)
942 SetLastError( ERROR_ACCESS_DENIED
);
947 * FIXME: We don't return FALSE here because of differences between
948 * Linux and Windows privileges. Under Linux only the owner of
949 * the file is allowed to change file attributes. Under Windows,
950 * applications expect that if you can write to a file, you can also
951 * change its attributes (see GENERIC_WRITE). We could try to be
952 * clever here but that would break multi-user installations where
953 * users share read-only DLLs. This is because some installers like
954 * to change attributes of already installed DLLs.
956 FIXME("Couldn't set file attributes for existing file \"%s\".\n"
957 "Check permissions or set VFAT \"quiet\" mount flag\n", full_name
.long_name
);
963 /**************************************************************************
964 * SetFileAttributesA (KERNEL32.@)
966 BOOL WINAPI
SetFileAttributesA(LPCSTR lpFileName
, DWORD attributes
)
968 UNICODE_STRING filenameW
;
973 SetLastError( ERROR_INVALID_PARAMETER
);
977 if (RtlCreateUnicodeStringFromAsciiz(&filenameW
, lpFileName
))
979 ret
= SetFileAttributesW(filenameW
.Buffer
, attributes
);
980 RtlFreeUnicodeString(&filenameW
);
983 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
988 /***********************************************************************
989 * GetFileSize (KERNEL32.@)
991 DWORD WINAPI
GetFileSize( HANDLE hFile
, LPDWORD filesizehigh
)
993 BY_HANDLE_FILE_INFORMATION info
;
994 if (!GetFileInformationByHandle( hFile
, &info
)) return -1;
995 if (filesizehigh
) *filesizehigh
= info
.nFileSizeHigh
;
996 return info
.nFileSizeLow
;
1000 /***********************************************************************
1001 * GetFileTime (KERNEL32.@)
1003 BOOL WINAPI
GetFileTime( HANDLE hFile
, FILETIME
*lpCreationTime
,
1004 FILETIME
*lpLastAccessTime
,
1005 FILETIME
*lpLastWriteTime
)
1007 BY_HANDLE_FILE_INFORMATION info
;
1008 if (!GetFileInformationByHandle( hFile
, &info
)) return FALSE
;
1009 if (lpCreationTime
) *lpCreationTime
= info
.ftCreationTime
;
1010 if (lpLastAccessTime
) *lpLastAccessTime
= info
.ftLastAccessTime
;
1011 if (lpLastWriteTime
) *lpLastWriteTime
= info
.ftLastWriteTime
;
1015 /***********************************************************************
1016 * CompareFileTime (KERNEL32.@)
1018 INT WINAPI
CompareFileTime( LPFILETIME x
, LPFILETIME y
)
1020 if (!x
|| !y
) return -1;
1022 if (x
->dwHighDateTime
> y
->dwHighDateTime
)
1024 if (x
->dwHighDateTime
< y
->dwHighDateTime
)
1026 if (x
->dwLowDateTime
> y
->dwLowDateTime
)
1028 if (x
->dwLowDateTime
< y
->dwLowDateTime
)
1033 /***********************************************************************
1034 * FILE_GetTempFileName : utility for GetTempFileName
1036 static UINT
FILE_GetTempFileName( LPCWSTR path
, LPCWSTR prefix
, UINT unique
,
1039 static UINT unique_temp
;
1040 DOS_FULL_NAME full_name
;
1046 if ( !path
|| !prefix
|| !buffer
)
1048 SetLastError( ERROR_INVALID_PARAMETER
);
1052 if (!unique_temp
) unique_temp
= time(NULL
) & 0xffff;
1053 num
= unique
? (unique
& 0xffff) : (unique_temp
++ & 0xffff);
1055 strcpyW( buffer
, path
);
1056 p
= buffer
+ strlenW(buffer
);
1058 /* add a \, if there isn't one and path is more than just the drive letter ... */
1059 if ( !((strlenW(buffer
) == 2) && (buffer
[1] == ':'))
1060 && ((p
== buffer
) || (p
[-1] != '\\'))) *p
++ = '\\';
1062 for (i
= 3; (i
> 0) && (*prefix
); i
--) *p
++ = *prefix
++;
1064 sprintf( buf
, "%04x.tmp", num
);
1065 MultiByteToWideChar(CP_ACP
, 0, buf
, -1, p
, 20);
1067 /* Now try to create it */
1073 HANDLE handle
= CreateFileW( buffer
, GENERIC_WRITE
, 0, NULL
,
1074 CREATE_NEW
, FILE_ATTRIBUTE_NORMAL
, 0 );
1075 if (handle
!= INVALID_HANDLE_VALUE
)
1076 { /* We created it */
1077 TRACE("created %s\n", debugstr_w(buffer
) );
1078 CloseHandle( handle
);
1081 if (GetLastError() != ERROR_FILE_EXISTS
)
1082 break; /* No need to go on */
1084 sprintf( buf
, "%04x.tmp", num
);
1085 MultiByteToWideChar(CP_ACP
, 0, buf
, -1, p
, 20);
1086 } while (num
!= (unique
& 0xffff));
1089 /* Get the full path name */
1091 if (DOSFS_GetFullName( buffer
, FALSE
, &full_name
))
1094 /* Check if we have write access in the directory */
1095 if ((slash
= strrchr( full_name
.long_name
, '/' ))) *slash
= '\0';
1096 if (access( full_name
.long_name
, W_OK
) == -1)
1097 WARN("returns %s, which doesn't seem to be writeable.\n",
1098 debugstr_w(buffer
) );
1100 TRACE("returning %s\n", debugstr_w(buffer
) );
1101 return unique
? unique
: num
;
1105 /***********************************************************************
1106 * GetTempFileNameA (KERNEL32.@)
1108 UINT WINAPI
GetTempFileNameA( LPCSTR path
, LPCSTR prefix
, UINT unique
,
1111 UNICODE_STRING pathW
, prefixW
;
1112 WCHAR bufferW
[MAX_PATH
];
1115 if ( !path
|| !prefix
|| !buffer
)
1117 SetLastError( ERROR_INVALID_PARAMETER
);
1121 RtlCreateUnicodeStringFromAsciiz(&pathW
, path
);
1122 RtlCreateUnicodeStringFromAsciiz(&prefixW
, prefix
);
1124 ret
= GetTempFileNameW(pathW
.Buffer
, prefixW
.Buffer
, unique
, bufferW
);
1126 WideCharToMultiByte(CP_ACP
, 0, bufferW
, -1, buffer
, MAX_PATH
, NULL
, NULL
);
1128 RtlFreeUnicodeString(&pathW
);
1129 RtlFreeUnicodeString(&prefixW
);
1133 /***********************************************************************
1134 * GetTempFileNameW (KERNEL32.@)
1136 UINT WINAPI
GetTempFileNameW( LPCWSTR path
, LPCWSTR prefix
, UINT unique
,
1139 return FILE_GetTempFileName( path
, prefix
, unique
, buffer
);
1143 /***********************************************************************
1144 * GetTempFileName (KERNEL.97)
1146 UINT16 WINAPI
GetTempFileName16( BYTE drive
, LPCSTR prefix
, UINT16 unique
,
1149 char temppath
[MAX_PATH
];
1150 char *prefix16
= NULL
;
1153 if (!(drive
& ~TF_FORCEDRIVE
)) /* drive 0 means current default drive */
1154 drive
|= DRIVE_GetCurrentDrive() + 'A';
1156 if ((drive
& TF_FORCEDRIVE
) &&
1157 !DRIVE_IsValid( toupper(drive
& ~TF_FORCEDRIVE
) - 'A' ))
1159 drive
&= ~TF_FORCEDRIVE
;
1160 WARN("invalid drive %d specified\n", drive
);
1163 if (drive
& TF_FORCEDRIVE
)
1164 sprintf(temppath
,"%c:", drive
& ~TF_FORCEDRIVE
);
1166 GetTempPathA( MAX_PATH
, temppath
);
1170 prefix16
= HeapAlloc(GetProcessHeap(), 0, strlen(prefix
) + 2);
1172 strcpy(prefix16
+ 1, prefix
);
1175 ret
= GetTempFileNameA( temppath
, prefix16
, unique
, buffer
);
1177 if (prefix16
) HeapFree(GetProcessHeap(), 0, prefix16
);
1181 /***********************************************************************
1184 * Implementation of OpenFile16() and OpenFile32().
1186 static HFILE
FILE_DoOpenFile( LPCSTR name
, OFSTRUCT
*ofs
, UINT mode
,
1192 WORD filedatetime
[2];
1193 DOS_FULL_NAME full_name
;
1194 DWORD access
, sharing
;
1196 WCHAR buffer
[MAX_PATH
];
1199 if (!ofs
) return HFILE_ERROR
;
1201 TRACE("%s %s %s %s%s%s%s%s%s%s%s%s\n",name
,
1202 ((mode
& 0x3 )==OF_READ
)?"OF_READ":
1203 ((mode
& 0x3 )==OF_WRITE
)?"OF_WRITE":
1204 ((mode
& 0x3 )==OF_READWRITE
)?"OF_READWRITE":"unknown",
1205 ((mode
& 0x70 )==OF_SHARE_COMPAT
)?"OF_SHARE_COMPAT":
1206 ((mode
& 0x70 )==OF_SHARE_DENY_NONE
)?"OF_SHARE_DENY_NONE":
1207 ((mode
& 0x70 )==OF_SHARE_DENY_READ
)?"OF_SHARE_DENY_READ":
1208 ((mode
& 0x70 )==OF_SHARE_DENY_WRITE
)?"OF_SHARE_DENY_WRITE":
1209 ((mode
& 0x70 )==OF_SHARE_EXCLUSIVE
)?"OF_SHARE_EXCLUSIVE":"unknown",
1210 ((mode
& OF_PARSE
)==OF_PARSE
)?"OF_PARSE ":"",
1211 ((mode
& OF_DELETE
)==OF_DELETE
)?"OF_DELETE ":"",
1212 ((mode
& OF_VERIFY
)==OF_VERIFY
)?"OF_VERIFY ":"",
1213 ((mode
& OF_SEARCH
)==OF_SEARCH
)?"OF_SEARCH ":"",
1214 ((mode
& OF_CANCEL
)==OF_CANCEL
)?"OF_CANCEL ":"",
1215 ((mode
& OF_CREATE
)==OF_CREATE
)?"OF_CREATE ":"",
1216 ((mode
& OF_PROMPT
)==OF_PROMPT
)?"OF_PROMPT ":"",
1217 ((mode
& OF_EXIST
)==OF_EXIST
)?"OF_EXIST ":"",
1218 ((mode
& OF_REOPEN
)==OF_REOPEN
)?"OF_REOPEN ":""
1222 ofs
->cBytes
= sizeof(OFSTRUCT
);
1224 if (mode
& OF_REOPEN
) name
= ofs
->szPathName
;
1227 ERR("called with `name' set to NULL ! Please debug.\n");
1231 TRACE("%s %04x\n", name
, mode
);
1233 /* the watcom 10.6 IDE relies on a valid path returned in ofs->szPathName
1234 Are there any cases where getting the path here is wrong?
1235 Uwe Bonnes 1997 Apr 2 */
1236 if (!GetFullPathNameA( name
, sizeof(ofs
->szPathName
),
1237 ofs
->szPathName
, NULL
)) goto error
;
1238 FILE_ConvertOFMode( mode
, &access
, &sharing
);
1240 /* OF_PARSE simply fills the structure */
1242 if (mode
& OF_PARSE
)
1244 ofs
->fFixedDisk
= (GetDriveType16( ofs
->szPathName
[0]-'A' )
1245 != DRIVE_REMOVABLE
);
1246 TRACE("(%s): OF_PARSE, res = '%s'\n",
1247 name
, ofs
->szPathName
);
1251 /* OF_CREATE is completely different from all other options, so
1254 if (mode
& OF_CREATE
)
1256 if ((handle
= CreateFileA( name
, GENERIC_READ
| GENERIC_WRITE
,
1257 sharing
, NULL
, CREATE_ALWAYS
,
1258 FILE_ATTRIBUTE_NORMAL
, 0 ))== INVALID_HANDLE_VALUE
)
1263 MultiByteToWideChar(CP_ACP
, 0, name
, -1, buffer
, MAX_PATH
);
1266 /* If OF_SEARCH is set, ignore the given path */
1268 if ((mode
& OF_SEARCH
) && !(mode
& OF_REOPEN
))
1270 /* First try the file name as is */
1271 if (DOSFS_GetFullName( nameW
, TRUE
, &full_name
)) goto found
;
1272 /* Now remove the path */
1273 if (nameW
[0] && (nameW
[1] == ':')) nameW
+= 2;
1274 if ((p
= strrchrW( nameW
, '\\' ))) nameW
= p
+ 1;
1275 if ((p
= strrchrW( nameW
, '/' ))) nameW
= p
+ 1;
1276 if (!nameW
[0]) goto not_found
;
1279 /* Now look for the file */
1281 if (!DIR_SearchPath( NULL
, nameW
, NULL
, &full_name
, win32
)) goto not_found
;
1284 TRACE("found %s = %s\n",
1285 full_name
.long_name
, debugstr_w(full_name
.short_name
) );
1286 WideCharToMultiByte(CP_ACP
, 0, full_name
.short_name
, -1,
1287 ofs
->szPathName
, sizeof(ofs
->szPathName
), NULL
, NULL
);
1289 if (mode
& OF_SHARE_EXCLUSIVE
)
1290 /* Some InstallShield version uses OF_SHARE_EXCLUSIVE
1291 on the file <tempdir>/_ins0432._mp to determine how
1292 far installation has proceeded.
1293 _ins0432._mp is an executable and while running the
1294 application expects the open with OF_SHARE_ to fail*/
1296 As our loader closes the files after loading the executable,
1297 we can't find the running executable with FILE_InUse.
1298 The loader should keep the file open, as Windows does that, too.
1301 char *last
= strrchr(full_name
.long_name
,'/');
1303 last
= full_name
.long_name
- 1;
1304 if (GetModuleHandle16(last
+1))
1306 TRACE("Denying shared open for %s\n",full_name
.long_name
);
1311 if (mode
& OF_DELETE
)
1313 if (unlink( full_name
.long_name
) == -1) goto not_found
;
1314 TRACE("(%s): OF_DELETE return = OK\n", name
);
1318 handle
= FILE_CreateFile( full_name
.long_name
, access
, sharing
,
1319 NULL
, OPEN_EXISTING
, 0, 0,
1320 DRIVE_GetFlags(full_name
.drive
) & DRIVE_FAIL_READ_ONLY
,
1321 GetDriveTypeW( full_name
.short_name
) );
1322 if (!handle
) goto not_found
;
1324 GetFileTime( handle
, NULL
, NULL
, &filetime
);
1325 FileTimeToDosDateTime( &filetime
, &filedatetime
[0], &filedatetime
[1] );
1326 if ((mode
& OF_VERIFY
) && (mode
& OF_REOPEN
))
1328 if (ofs
->Reserved1
!= filedatetime
[0] || ofs
->Reserved2
!= filedatetime
[1] )
1330 CloseHandle( handle
);
1331 WARN("(%s): OF_VERIFY failed\n", name
);
1332 /* FIXME: what error here? */
1333 SetLastError( ERROR_FILE_NOT_FOUND
);
1337 ofs
->Reserved1
= filedatetime
[0];
1338 ofs
->Reserved2
= filedatetime
[1];
1340 success
: /* We get here if the open was successful */
1341 TRACE("(%s): OK, return = %x\n", name
, handle
);
1344 hFileRet
= (HFILE
)handle
;
1345 if (mode
& OF_EXIST
) /* Return the handle, but close it first */
1346 CloseHandle( handle
);
1350 hFileRet
= Win32HandleToDosFileHandle( handle
);
1351 if (hFileRet
== HFILE_ERROR16
) goto error
;
1352 if (mode
& OF_EXIST
) /* Return the handle, but close it first */
1353 _lclose16( hFileRet
);
1357 not_found
: /* We get here if the file does not exist */
1358 WARN("'%s' not found or sharing violation\n", name
);
1359 SetLastError( ERROR_FILE_NOT_FOUND
);
1362 error
: /* We get here if there was an error opening the file */
1363 ofs
->nErrCode
= GetLastError();
1364 WARN("(%s): return = HFILE_ERROR error= %d\n",
1365 name
,ofs
->nErrCode
);
1370 /***********************************************************************
1371 * OpenFile (KERNEL.74)
1372 * OpenFileEx (KERNEL.360)
1374 HFILE16 WINAPI
OpenFile16( LPCSTR name
, OFSTRUCT
*ofs
, UINT16 mode
)
1376 return FILE_DoOpenFile( name
, ofs
, mode
, FALSE
);
1380 /***********************************************************************
1381 * OpenFile (KERNEL32.@)
1383 HFILE WINAPI
OpenFile( LPCSTR name
, OFSTRUCT
*ofs
, UINT mode
)
1385 return FILE_DoOpenFile( name
, ofs
, mode
, TRUE
);
1389 /***********************************************************************
1390 * FILE_InitProcessDosHandles
1392 * Allocates the default DOS handles for a process. Called either by
1393 * Win32HandleToDosFileHandle below or by the DOSVM stuff.
1395 static void FILE_InitProcessDosHandles( void )
1397 HANDLE cp
= GetCurrentProcess();
1398 DuplicateHandle(cp
, GetStdHandle(STD_INPUT_HANDLE
), cp
, &dos_handles
[0],
1399 0, TRUE
, DUPLICATE_SAME_ACCESS
);
1400 DuplicateHandle(cp
, GetStdHandle(STD_OUTPUT_HANDLE
), cp
, &dos_handles
[1],
1401 0, TRUE
, DUPLICATE_SAME_ACCESS
);
1402 DuplicateHandle(cp
, GetStdHandle(STD_ERROR_HANDLE
), cp
, &dos_handles
[2],
1403 0, TRUE
, DUPLICATE_SAME_ACCESS
);
1404 DuplicateHandle(cp
, GetStdHandle(STD_ERROR_HANDLE
), cp
, &dos_handles
[3],
1405 0, TRUE
, DUPLICATE_SAME_ACCESS
);
1406 DuplicateHandle(cp
, GetStdHandle(STD_ERROR_HANDLE
), cp
, &dos_handles
[4],
1407 0, TRUE
, DUPLICATE_SAME_ACCESS
);
1410 /***********************************************************************
1411 * Win32HandleToDosFileHandle (KERNEL32.21)
1413 * Allocate a DOS handle for a Win32 handle. The Win32 handle is no
1414 * longer valid after this function (even on failure).
1416 * Note: this is not exactly right, since on Win95 the Win32 handles
1417 * are on top of DOS handles and we do it the other way
1418 * around. Should be good enough though.
1420 HFILE WINAPI
Win32HandleToDosFileHandle( HANDLE handle
)
1424 if (!handle
|| (handle
== INVALID_HANDLE_VALUE
))
1427 for (i
= 5; i
< DOS_TABLE_SIZE
; i
++)
1428 if (!dos_handles
[i
])
1430 dos_handles
[i
] = handle
;
1431 TRACE("Got %d for h32 %d\n", i
, handle
);
1434 CloseHandle( handle
);
1435 SetLastError( ERROR_TOO_MANY_OPEN_FILES
);
1440 /***********************************************************************
1441 * DosFileHandleToWin32Handle (KERNEL32.20)
1443 * Return the Win32 handle for a DOS handle.
1445 * Note: this is not exactly right, since on Win95 the Win32 handles
1446 * are on top of DOS handles and we do it the other way
1447 * around. Should be good enough though.
1449 HANDLE WINAPI
DosFileHandleToWin32Handle( HFILE handle
)
1451 HFILE16 hfile
= (HFILE16
)handle
;
1452 if (hfile
< 5 && !dos_handles
[hfile
]) FILE_InitProcessDosHandles();
1453 if ((hfile
>= DOS_TABLE_SIZE
) || !dos_handles
[hfile
])
1455 SetLastError( ERROR_INVALID_HANDLE
);
1456 return INVALID_HANDLE_VALUE
;
1458 return dos_handles
[hfile
];
1462 /***********************************************************************
1463 * DisposeLZ32Handle (KERNEL32.22)
1465 * Note: this is not entirely correct, we should only close the
1466 * 32-bit handle and not the 16-bit one, but we cannot do
1467 * this because of the way our DOS handles are implemented.
1468 * It shouldn't break anything though.
1470 void WINAPI
DisposeLZ32Handle( HANDLE handle
)
1474 if (!handle
|| (handle
== INVALID_HANDLE_VALUE
)) return;
1476 for (i
= 5; i
< DOS_TABLE_SIZE
; i
++)
1477 if (dos_handles
[i
] == handle
)
1480 CloseHandle( handle
);
1486 /***********************************************************************
1489 * dup2() function for DOS handles.
1491 HFILE16
FILE_Dup2( HFILE16 hFile1
, HFILE16 hFile2
)
1495 if (hFile1
< 5 && !dos_handles
[hFile1
]) FILE_InitProcessDosHandles();
1497 if ((hFile1
>= DOS_TABLE_SIZE
) || (hFile2
>= DOS_TABLE_SIZE
) || !dos_handles
[hFile1
])
1499 SetLastError( ERROR_INVALID_HANDLE
);
1500 return HFILE_ERROR16
;
1502 if (!DuplicateHandle( GetCurrentProcess(), dos_handles
[hFile1
],
1503 GetCurrentProcess(), &new_handle
,
1504 0, FALSE
, DUPLICATE_SAME_ACCESS
))
1505 return HFILE_ERROR16
;
1506 if (dos_handles
[hFile2
]) CloseHandle( dos_handles
[hFile2
] );
1507 dos_handles
[hFile2
] = new_handle
;
1512 /***********************************************************************
1513 * _lclose (KERNEL.81)
1515 HFILE16 WINAPI
_lclose16( HFILE16 hFile
)
1517 if ((hFile
>= DOS_TABLE_SIZE
) || !dos_handles
[hFile
])
1519 SetLastError( ERROR_INVALID_HANDLE
);
1520 return HFILE_ERROR16
;
1522 TRACE("%d (handle32=%d)\n", hFile
, dos_handles
[hFile
] );
1523 CloseHandle( dos_handles
[hFile
] );
1524 dos_handles
[hFile
] = 0;
1529 /***********************************************************************
1530 * _lclose (KERNEL32.@)
1532 HFILE WINAPI
_lclose( HFILE hFile
)
1534 TRACE("handle %d\n", hFile
);
1535 return CloseHandle( (HANDLE
)hFile
) ? 0 : HFILE_ERROR
;
1538 /***********************************************************************
1539 * GetOverlappedResult (KERNEL32.@)
1541 * Check the result of an Asynchronous data transfer from a file.
1547 * If successful (and relevant) lpTransferred will hold the number of
1548 * bytes transferred during the async operation.
1552 * Currently only works for WaitCommEvent, ReadFile, WriteFile
1553 * with communications ports.
1556 BOOL WINAPI
GetOverlappedResult(
1557 HANDLE hFile
, /* [in] handle of file to check on */
1558 LPOVERLAPPED lpOverlapped
, /* [in/out] pointer to overlapped */
1559 LPDWORD lpTransferred
, /* [in/out] number of bytes transferred */
1560 BOOL bWait
/* [in] wait for the transfer to complete ? */
1564 TRACE("(%d %p %p %x)\n", hFile
, lpOverlapped
, lpTransferred
, bWait
);
1566 if(lpOverlapped
==NULL
)
1568 ERR("lpOverlapped was null\n");
1571 if(!lpOverlapped
->hEvent
)
1573 ERR("lpOverlapped->hEvent was null\n");
1580 TRACE("waiting on %p\n",lpOverlapped
);
1581 r
= WaitForSingleObjectEx(lpOverlapped
->hEvent
, INFINITE
, TRUE
);
1582 TRACE("wait on %p returned %ld\n",lpOverlapped
,r
);
1583 } while (r
==STATUS_USER_APC
);
1585 else if ( lpOverlapped
->Internal
== STATUS_PENDING
)
1587 /* Wait in order to give APCs a chance to run. */
1588 /* This is cheating, so we must set the event again in case of success -
1589 it may be a non-manual reset event. */
1591 TRACE("waiting on %p\n",lpOverlapped
);
1592 r
= WaitForSingleObjectEx(lpOverlapped
->hEvent
, 0, TRUE
);
1593 TRACE("wait on %p returned %ld\n",lpOverlapped
,r
);
1594 } while (r
==STATUS_USER_APC
);
1595 if ( r
== WAIT_OBJECT_0
)
1596 NtSetEvent ( lpOverlapped
->hEvent
, NULL
);
1600 *lpTransferred
= lpOverlapped
->InternalHigh
;
1602 switch ( lpOverlapped
->Internal
)
1604 case STATUS_SUCCESS
:
1606 case STATUS_PENDING
:
1607 SetLastError ( ERROR_IO_INCOMPLETE
);
1608 if ( bWait
) ERR ("PENDING status after waiting!\n");
1611 SetLastError ( RtlNtStatusToDosError ( lpOverlapped
->Internal
) );
1616 /***********************************************************************
1617 * CancelIo (KERNEL32.@)
1619 BOOL WINAPI
CancelIo(HANDLE handle
)
1621 async_private
*ovp
,*t
;
1623 TRACE("handle = %x\n",handle
);
1625 for (ovp
= NtCurrentTeb()->pending_list
; ovp
; ovp
= t
)
1628 if ( ovp
->handle
== handle
)
1629 cancel_async ( ovp
);
1631 WaitForMultipleObjectsEx(0,NULL
,FALSE
,1,TRUE
);
1635 /***********************************************************************
1636 * FILE_AsyncReadService (INTERNAL)
1638 * This function is called while the client is waiting on the
1639 * server, so we can't make any server calls here.
1641 static void FILE_AsyncReadService(async_private
*ovp
)
1643 async_fileio
*fileio
= (async_fileio
*) ovp
;
1644 LPOVERLAPPED lpOverlapped
= fileio
->lpOverlapped
;
1646 int already
= lpOverlapped
->InternalHigh
;
1648 TRACE("%p %p\n", lpOverlapped
, fileio
->buffer
);
1650 /* check to see if the data is ready (non-blocking) */
1652 if ( fileio
->fd_type
== FD_TYPE_SOCKET
)
1653 result
= read (ovp
->fd
, &fileio
->buffer
[already
], fileio
->count
- already
);
1656 result
= pread (ovp
->fd
, &fileio
->buffer
[already
], fileio
->count
- already
,
1657 OVERLAPPED_OFFSET (lpOverlapped
) + already
);
1658 if ((result
< 0) && (errno
== ESPIPE
))
1659 result
= read (ovp
->fd
, &fileio
->buffer
[already
], fileio
->count
- already
);
1662 if ( (result
<0) && ((errno
== EAGAIN
) || (errno
== EINTR
)))
1664 TRACE("Deferred read %d\n",errno
);
1669 /* check to see if the transfer is complete */
1672 r
= FILE_GetNtStatus ();
1676 lpOverlapped
->InternalHigh
+= result
;
1677 TRACE("read %d more bytes %ld/%d so far\n",result
,lpOverlapped
->InternalHigh
,fileio
->count
);
1679 if(lpOverlapped
->InternalHigh
>= fileio
->count
|| fileio
->fd_type
== FD_TYPE_SOCKET
)
1685 lpOverlapped
->Internal
= r
;
1688 /***********************************************************************
1689 * FILE_ReadFileEx (INTERNAL)
1691 static BOOL
FILE_ReadFileEx(HANDLE hFile
, LPVOID buffer
, DWORD bytesToRead
,
1692 LPOVERLAPPED overlapped
,
1693 LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine
,
1701 TRACE("file %d to buf %p num %ld %p func %p\n",
1702 hFile
, buffer
, bytesToRead
, overlapped
, lpCompletionRoutine
);
1704 /* check that there is an overlapped struct */
1705 if (overlapped
==NULL
)
1707 SetLastError(ERROR_INVALID_PARAMETER
);
1711 fd
= FILE_GetUnixHandleType ( hFile
, GENERIC_READ
, &type
, &flags
);
1714 WARN ( "Couldn't get FD\n" );
1718 ovp
= (async_fileio
*) HeapAlloc(GetProcessHeap(), 0, sizeof (async_fileio
));
1721 TRACE("HeapAlloc Failed\n");
1722 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
1726 ovp
->async
.ops
= ( lpCompletionRoutine
? &fileio_async_ops
: &fileio_nocomp_async_ops
);
1727 ovp
->async
.handle
= hFile
;
1729 ovp
->async
.type
= ASYNC_TYPE_READ
;
1730 ovp
->async
.func
= FILE_AsyncReadService
;
1731 ovp
->async
.event
= hEvent
;
1732 ovp
->lpOverlapped
= overlapped
;
1733 ovp
->count
= bytesToRead
;
1734 ovp
->completion_func
= lpCompletionRoutine
;
1735 ovp
->buffer
= buffer
;
1736 ovp
->fd_type
= type
;
1738 return !register_new_async (&ovp
->async
);
1746 /***********************************************************************
1747 * ReadFileEx (KERNEL32.@)
1749 BOOL WINAPI
ReadFileEx(HANDLE hFile
, LPVOID buffer
, DWORD bytesToRead
,
1750 LPOVERLAPPED overlapped
,
1751 LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine
)
1753 overlapped
->InternalHigh
= 0;
1754 return FILE_ReadFileEx(hFile
,buffer
,bytesToRead
,overlapped
,lpCompletionRoutine
, INVALID_HANDLE_VALUE
);
1757 static BOOL
FILE_TimeoutRead(HANDLE hFile
, LPVOID buffer
, DWORD bytesToRead
, LPDWORD bytesRead
)
1762 TRACE("%d %p %ld %p\n", hFile
, buffer
, bytesToRead
, bytesRead
);
1764 ZeroMemory(&ov
, sizeof (OVERLAPPED
));
1765 if(STATUS_SUCCESS
==NtCreateEvent(&ov
.hEvent
, SYNCHRONIZE
, NULL
, 0, 0))
1767 if(FILE_ReadFileEx(hFile
, buffer
, bytesToRead
, &ov
, NULL
, ov
.hEvent
))
1769 r
= GetOverlappedResult(hFile
, &ov
, bytesRead
, TRUE
);
1772 CloseHandle(ov
.hEvent
);
1776 /***********************************************************************
1777 * ReadFile (KERNEL32.@)
1779 BOOL WINAPI
ReadFile( HANDLE hFile
, LPVOID buffer
, DWORD bytesToRead
,
1780 LPDWORD bytesRead
, LPOVERLAPPED overlapped
)
1782 int unix_handle
, result
, flags
;
1785 TRACE("%d %p %ld %p %p\n", hFile
, buffer
, bytesToRead
,
1786 bytesRead
, overlapped
);
1788 if (bytesRead
) *bytesRead
= 0; /* Do this before anything else */
1789 if (!bytesToRead
) return TRUE
;
1791 unix_handle
= FILE_GetUnixHandleType( hFile
, GENERIC_READ
, &type
, &flags
);
1793 if (flags
& FD_FLAG_OVERLAPPED
)
1795 if (unix_handle
== -1) return FALSE
;
1796 if ( (overlapped
==NULL
) || NtResetEvent( overlapped
->hEvent
, NULL
) )
1798 TRACE("Overlapped not specified or invalid event flag\n");
1800 SetLastError(ERROR_INVALID_PARAMETER
);
1805 overlapped
->InternalHigh
= 0;
1807 if(!FILE_ReadFileEx(hFile
, buffer
, bytesToRead
, overlapped
, NULL
, overlapped
->hEvent
))
1810 if ( !GetOverlappedResult (hFile
, overlapped
, bytesRead
, FALSE
) )
1812 if ( GetLastError() == ERROR_IO_INCOMPLETE
)
1813 SetLastError ( ERROR_IO_PENDING
);
1819 if (flags
& FD_FLAG_TIMEOUT
)
1822 return FILE_TimeoutRead(hFile
, buffer
, bytesToRead
, bytesRead
);
1827 return SMB_ReadFile(hFile
, buffer
, bytesToRead
, bytesRead
, NULL
);
1829 case FD_TYPE_CONSOLE
:
1830 return FILE_ReadConsole(hFile
, buffer
, bytesToRead
, bytesRead
, NULL
);
1832 case FD_TYPE_DEFAULT
:
1833 /* normal unix files */
1834 if (unix_handle
== -1) return FALSE
;
1837 DWORD highOffset
= overlapped
->OffsetHigh
;
1838 if ( (INVALID_SET_FILE_POINTER
== SetFilePointer(hFile
, overlapped
->Offset
,
1839 &highOffset
, FILE_BEGIN
)) &&
1840 (GetLastError() != NO_ERROR
) )
1849 if (unix_handle
== -1)
1855 off_t offset
= OVERLAPPED_OFFSET(overlapped
);
1856 if(lseek(unix_handle
, offset
, SEEK_SET
) == -1)
1859 SetLastError(ERROR_INVALID_PARAMETER
);
1864 /* code for synchronous reads */
1865 while ((result
= read( unix_handle
, buffer
, bytesToRead
)) == -1)
1867 if ((errno
== EAGAIN
) || (errno
== EINTR
)) continue;
1868 if ((errno
== EFAULT
) && !IsBadWritePtr( buffer
, bytesToRead
)) continue;
1872 close( unix_handle
);
1873 if (result
== -1) return FALSE
;
1874 if (bytesRead
) *bytesRead
= result
;
1879 /***********************************************************************
1880 * FILE_AsyncWriteService (INTERNAL)
1882 * This function is called while the client is waiting on the
1883 * server, so we can't make any server calls here.
1885 static void FILE_AsyncWriteService(struct async_private
*ovp
)
1887 async_fileio
*fileio
= (async_fileio
*) ovp
;
1888 LPOVERLAPPED lpOverlapped
= fileio
->lpOverlapped
;
1890 int already
= lpOverlapped
->InternalHigh
;
1892 TRACE("(%p %p)\n",lpOverlapped
,fileio
->buffer
);
1894 /* write some data (non-blocking) */
1896 if ( fileio
->fd_type
== FD_TYPE_SOCKET
)
1897 result
= write(ovp
->fd
, &fileio
->buffer
[already
], fileio
->count
- already
);
1900 result
= pwrite(ovp
->fd
, &fileio
->buffer
[already
], fileio
->count
- already
,
1901 OVERLAPPED_OFFSET (lpOverlapped
) + already
);
1902 if ((result
< 0) && (errno
== ESPIPE
))
1903 result
= write(ovp
->fd
, &fileio
->buffer
[already
], fileio
->count
- already
);
1906 if ( (result
<0) && ((errno
== EAGAIN
) || (errno
== EINTR
)))
1912 /* check to see if the transfer is complete */
1915 r
= FILE_GetNtStatus ();
1919 lpOverlapped
->InternalHigh
+= result
;
1921 TRACE("wrote %d more bytes %ld/%d so far\n",result
,lpOverlapped
->InternalHigh
,fileio
->count
);
1923 if(lpOverlapped
->InternalHigh
< fileio
->count
)
1929 lpOverlapped
->Internal
= r
;
1932 /***********************************************************************
1935 static BOOL
FILE_WriteFileEx(HANDLE hFile
, LPCVOID buffer
, DWORD bytesToWrite
,
1936 LPOVERLAPPED overlapped
,
1937 LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine
,
1945 TRACE("file %d to buf %p num %ld %p func %p handle %d\n",
1946 hFile
, buffer
, bytesToWrite
, overlapped
, lpCompletionRoutine
, hEvent
);
1948 if (overlapped
== NULL
)
1950 SetLastError(ERROR_INVALID_PARAMETER
);
1954 fd
= FILE_GetUnixHandleType ( hFile
, GENERIC_WRITE
, &type
, &flags
);
1957 TRACE( "Couldn't get FD\n" );
1961 ovp
= (async_fileio
*) HeapAlloc(GetProcessHeap(), 0, sizeof (async_fileio
));
1964 TRACE("HeapAlloc Failed\n");
1965 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
1969 ovp
->async
.ops
= ( lpCompletionRoutine
? &fileio_async_ops
: &fileio_nocomp_async_ops
);
1970 ovp
->async
.handle
= hFile
;
1972 ovp
->async
.type
= ASYNC_TYPE_WRITE
;
1973 ovp
->async
.func
= FILE_AsyncWriteService
;
1974 ovp
->lpOverlapped
= overlapped
;
1975 ovp
->async
.event
= hEvent
;
1976 ovp
->buffer
= (LPVOID
) buffer
;
1977 ovp
->count
= bytesToWrite
;
1978 ovp
->completion_func
= lpCompletionRoutine
;
1979 ovp
->fd_type
= type
;
1981 return !register_new_async (&ovp
->async
);
1988 /***********************************************************************
1989 * WriteFileEx (KERNEL32.@)
1991 BOOL WINAPI
WriteFileEx(HANDLE hFile
, LPCVOID buffer
, DWORD bytesToWrite
,
1992 LPOVERLAPPED overlapped
,
1993 LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine
)
1995 overlapped
->InternalHigh
= 0;
1997 return FILE_WriteFileEx(hFile
, buffer
, bytesToWrite
, overlapped
, lpCompletionRoutine
, INVALID_HANDLE_VALUE
);
2000 /***********************************************************************
2001 * WriteFile (KERNEL32.@)
2003 BOOL WINAPI
WriteFile( HANDLE hFile
, LPCVOID buffer
, DWORD bytesToWrite
,
2004 LPDWORD bytesWritten
, LPOVERLAPPED overlapped
)
2006 int unix_handle
, result
, flags
;
2009 TRACE("%d %p %ld %p %p\n", hFile
, buffer
, bytesToWrite
,
2010 bytesWritten
, overlapped
);
2012 if (bytesWritten
) *bytesWritten
= 0; /* Do this before anything else */
2013 if (!bytesToWrite
) return TRUE
;
2015 unix_handle
= FILE_GetUnixHandleType( hFile
, GENERIC_WRITE
, &type
, &flags
);
2017 if (flags
& FD_FLAG_OVERLAPPED
)
2019 if (unix_handle
== -1) return FALSE
;
2020 if ( (overlapped
==NULL
) || NtResetEvent( overlapped
->hEvent
, NULL
) )
2022 TRACE("Overlapped not specified or invalid event flag\n");
2024 SetLastError(ERROR_INVALID_PARAMETER
);
2029 overlapped
->InternalHigh
= 0;
2031 if(!FILE_WriteFileEx(hFile
, buffer
, bytesToWrite
, overlapped
, NULL
, overlapped
->hEvent
))
2034 if ( !GetOverlappedResult (hFile
, overlapped
, bytesWritten
, FALSE
) )
2036 if ( GetLastError() == ERROR_IO_INCOMPLETE
)
2037 SetLastError ( ERROR_IO_PENDING
);
2046 case FD_TYPE_CONSOLE
:
2047 TRACE("%d %s %ld %p %p\n", hFile
, debugstr_an(buffer
, bytesToWrite
), bytesToWrite
,
2048 bytesWritten
, overlapped
);
2049 return FILE_WriteConsole(hFile
, buffer
, bytesToWrite
, bytesWritten
, NULL
);
2051 case FD_TYPE_DEFAULT
:
2052 if (unix_handle
== -1) return FALSE
;
2056 DWORD highOffset
= overlapped
->OffsetHigh
;
2057 if ( (INVALID_SET_FILE_POINTER
== SetFilePointer(hFile
, overlapped
->Offset
,
2058 &highOffset
, FILE_BEGIN
)) &&
2059 (GetLastError() != NO_ERROR
) )
2068 if (unix_handle
== -1)
2073 SetLastError(ERROR_INVALID_PARAMETER
);
2081 off_t offset
= OVERLAPPED_OFFSET(overlapped
);
2082 if(lseek(unix_handle
, offset
, SEEK_SET
) == -1)
2085 SetLastError(ERROR_INVALID_PARAMETER
);
2090 /* synchronous file write */
2091 while ((result
= write( unix_handle
, buffer
, bytesToWrite
)) == -1)
2093 if ((errno
== EAGAIN
) || (errno
== EINTR
)) continue;
2094 if ((errno
== EFAULT
) && !IsBadReadPtr( buffer
, bytesToWrite
)) continue;
2095 if (errno
== ENOSPC
)
2096 SetLastError( ERROR_DISK_FULL
);
2101 close( unix_handle
);
2102 if (result
== -1) return FALSE
;
2103 if (bytesWritten
) *bytesWritten
= result
;
2108 /***********************************************************************
2109 * _hread (KERNEL.349)
2111 LONG WINAPI
WIN16_hread( HFILE16 hFile
, SEGPTR buffer
, LONG count
)
2115 TRACE("%d %08lx %ld\n",
2116 hFile
, (DWORD
)buffer
, count
);
2118 /* Some programs pass a count larger than the allocated buffer */
2119 maxlen
= GetSelectorLimit16( SELECTOROF(buffer
) ) - OFFSETOF(buffer
) + 1;
2120 if (count
> maxlen
) count
= maxlen
;
2121 return _lread((HFILE
)DosFileHandleToWin32Handle(hFile
), MapSL(buffer
), count
);
2125 /***********************************************************************
2126 * _lread (KERNEL.82)
2128 UINT16 WINAPI
WIN16_lread( HFILE16 hFile
, SEGPTR buffer
, UINT16 count
)
2130 return (UINT16
)WIN16_hread( hFile
, buffer
, (LONG
)count
);
2134 /***********************************************************************
2135 * _lread (KERNEL32.@)
2137 UINT WINAPI
_lread( HFILE handle
, LPVOID buffer
, UINT count
)
2140 if (!ReadFile( (HANDLE
)handle
, buffer
, count
, &result
, NULL
)) return -1;
2145 /***********************************************************************
2146 * _lread16 (KERNEL.82)
2148 UINT16 WINAPI
_lread16( HFILE16 hFile
, LPVOID buffer
, UINT16 count
)
2150 return (UINT16
)_lread((HFILE
)DosFileHandleToWin32Handle(hFile
), buffer
, (LONG
)count
);
2154 /***********************************************************************
2155 * _lcreat (KERNEL.83)
2157 HFILE16 WINAPI
_lcreat16( LPCSTR path
, INT16 attr
)
2159 return Win32HandleToDosFileHandle( (HANDLE
)_lcreat( path
, attr
) );
2163 /***********************************************************************
2164 * _lcreat (KERNEL32.@)
2166 HFILE WINAPI
_lcreat( LPCSTR path
, INT attr
)
2168 /* Mask off all flags not explicitly allowed by the doc */
2169 attr
&= FILE_ATTRIBUTE_READONLY
| FILE_ATTRIBUTE_HIDDEN
| FILE_ATTRIBUTE_SYSTEM
;
2170 TRACE("%s %02x\n", path
, attr
);
2171 return (HFILE
)CreateFileA( path
, GENERIC_READ
| GENERIC_WRITE
,
2172 FILE_SHARE_READ
| FILE_SHARE_WRITE
, NULL
,
2173 CREATE_ALWAYS
, attr
, 0 );
2177 /***********************************************************************
2178 * SetFilePointer (KERNEL32.@)
2180 DWORD WINAPI
SetFilePointer( HANDLE hFile
, LONG distance
, LONG
*highword
,
2183 DWORD ret
= INVALID_SET_FILE_POINTER
;
2185 TRACE("handle %d offset %ld high %ld origin %ld\n",
2186 hFile
, distance
, highword
?*highword
:0, method
);
2188 SERVER_START_REQ( set_file_pointer
)
2190 req
->handle
= hFile
;
2191 req
->low
= distance
;
2192 req
->high
= highword
? *highword
: (distance
>= 0) ? 0 : -1;
2193 /* FIXME: assumes 1:1 mapping between Windows and Unix seek constants */
2194 req
->whence
= method
;
2196 if (!wine_server_call_err( req
))
2198 ret
= reply
->new_low
;
2199 if (highword
) *highword
= reply
->new_high
;
2207 /***********************************************************************
2208 * _llseek (KERNEL.84)
2211 * Seeking before the start of the file should be allowed for _llseek16,
2212 * but cause subsequent I/O operations to fail (cf. interrupt list)
2215 LONG WINAPI
_llseek16( HFILE16 hFile
, LONG lOffset
, INT16 nOrigin
)
2217 return SetFilePointer( DosFileHandleToWin32Handle(hFile
), lOffset
, NULL
, nOrigin
);
2221 /***********************************************************************
2222 * _llseek (KERNEL32.@)
2224 LONG WINAPI
_llseek( HFILE hFile
, LONG lOffset
, INT nOrigin
)
2226 return SetFilePointer( (HANDLE
)hFile
, lOffset
, NULL
, nOrigin
);
2230 /***********************************************************************
2231 * _lopen (KERNEL.85)
2233 HFILE16 WINAPI
_lopen16( LPCSTR path
, INT16 mode
)
2235 return Win32HandleToDosFileHandle( (HANDLE
)_lopen( path
, mode
) );
2239 /***********************************************************************
2240 * _lopen (KERNEL32.@)
2242 HFILE WINAPI
_lopen( LPCSTR path
, INT mode
)
2244 DWORD access
, sharing
;
2246 TRACE("('%s',%04x)\n", path
, mode
);
2247 FILE_ConvertOFMode( mode
, &access
, &sharing
);
2248 return (HFILE
)CreateFileA( path
, access
, sharing
, NULL
, OPEN_EXISTING
, 0, 0 );
2252 /***********************************************************************
2253 * _lwrite (KERNEL.86)
2255 UINT16 WINAPI
_lwrite16( HFILE16 hFile
, LPCSTR buffer
, UINT16 count
)
2257 return (UINT16
)_hwrite( (HFILE
)DosFileHandleToWin32Handle(hFile
), buffer
, (LONG
)count
);
2260 /***********************************************************************
2261 * _lwrite (KERNEL32.@)
2263 UINT WINAPI
_lwrite( HFILE hFile
, LPCSTR buffer
, UINT count
)
2265 return (UINT
)_hwrite( hFile
, buffer
, (LONG
)count
);
2269 /***********************************************************************
2270 * _hread16 (KERNEL.349)
2272 LONG WINAPI
_hread16( HFILE16 hFile
, LPVOID buffer
, LONG count
)
2274 return _lread( (HFILE
)DosFileHandleToWin32Handle(hFile
), buffer
, count
);
2278 /***********************************************************************
2279 * _hread (KERNEL32.@)
2281 LONG WINAPI
_hread( HFILE hFile
, LPVOID buffer
, LONG count
)
2283 return _lread( hFile
, buffer
, count
);
2287 /***********************************************************************
2288 * _hwrite (KERNEL.350)
2290 LONG WINAPI
_hwrite16( HFILE16 hFile
, LPCSTR buffer
, LONG count
)
2292 return _hwrite( (HFILE
)DosFileHandleToWin32Handle(hFile
), buffer
, count
);
2296 /***********************************************************************
2297 * _hwrite (KERNEL32.@)
2299 * experimentation yields that _lwrite:
2300 * o truncates the file at the current position with
2302 * o returns 0 on a 0 length write
2303 * o works with console handles
2306 LONG WINAPI
_hwrite( HFILE handle
, LPCSTR buffer
, LONG count
)
2310 TRACE("%d %p %ld\n", handle
, buffer
, count
);
2314 /* Expand or truncate at current position */
2315 if (!SetEndOfFile( (HANDLE
)handle
)) return HFILE_ERROR
;
2318 if (!WriteFile( (HANDLE
)handle
, buffer
, count
, &result
, NULL
))
2324 /***********************************************************************
2325 * SetHandleCount (KERNEL.199)
2327 UINT16 WINAPI
SetHandleCount16( UINT16 count
)
2329 return SetHandleCount( count
);
2333 /*************************************************************************
2334 * SetHandleCount (KERNEL32.@)
2336 UINT WINAPI
SetHandleCount( UINT count
)
2338 return min( 256, count
);
2342 /***********************************************************************
2343 * FlushFileBuffers (KERNEL32.@)
2345 BOOL WINAPI
FlushFileBuffers( HANDLE hFile
)
2348 SERVER_START_REQ( flush_file
)
2350 req
->handle
= hFile
;
2351 ret
= !wine_server_call_err( req
);
2358 /**************************************************************************
2359 * SetEndOfFile (KERNEL32.@)
2361 BOOL WINAPI
SetEndOfFile( HANDLE hFile
)
2364 SERVER_START_REQ( truncate_file
)
2366 req
->handle
= hFile
;
2367 ret
= !wine_server_call_err( req
);
2374 /***********************************************************************
2375 * DeleteFile (KERNEL.146)
2377 BOOL16 WINAPI
DeleteFile16( LPCSTR path
)
2379 return DeleteFileA( path
);
2383 /***********************************************************************
2384 * DeleteFileW (KERNEL32.@)
2386 BOOL WINAPI
DeleteFileW( LPCWSTR path
)
2388 DOS_FULL_NAME full_name
;
2393 SetLastError(ERROR_INVALID_PARAMETER
);
2396 TRACE("%s\n", debugstr_w(path
) );
2400 ERR("Empty path passed\n");
2403 if (DOSFS_GetDevice( path
))
2405 WARN("cannot remove DOS device %s!\n", debugstr_w(path
));
2406 SetLastError( ERROR_FILE_NOT_FOUND
);
2410 if (!DOSFS_GetFullName( path
, TRUE
, &full_name
)) return FALSE
;
2412 /* check if we are allowed to delete the source */
2413 hFile
= FILE_CreateFile( full_name
.long_name
, GENERIC_READ
|GENERIC_WRITE
, 0,
2414 NULL
, OPEN_EXISTING
, 0, 0, TRUE
,
2415 GetDriveTypeW( full_name
.short_name
) );
2416 if (!hFile
) return FALSE
;
2418 if (unlink( full_name
.long_name
) == -1)
2429 /***********************************************************************
2430 * DeleteFileA (KERNEL32.@)
2432 BOOL WINAPI
DeleteFileA( LPCSTR path
)
2434 UNICODE_STRING pathW
;
2439 SetLastError(ERROR_INVALID_PARAMETER
);
2443 if (RtlCreateUnicodeStringFromAsciiz(&pathW
, path
))
2445 ret
= DeleteFileW(pathW
.Buffer
);
2446 RtlFreeUnicodeString(&pathW
);
2449 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
2454 /***********************************************************************
2455 * GetFileType (KERNEL32.@)
2457 DWORD WINAPI
GetFileType( HANDLE hFile
)
2459 DWORD ret
= FILE_TYPE_UNKNOWN
;
2460 SERVER_START_REQ( get_file_info
)
2462 req
->handle
= hFile
;
2463 if (!wine_server_call_err( req
)) ret
= reply
->type
;
2470 /* check if a file name is for an executable file (.exe or .com) */
2471 inline static BOOL
is_executable( const char *name
)
2473 int len
= strlen(name
);
2475 if (len
< 4) return FALSE
;
2476 return (!strcasecmp( name
+ len
- 4, ".exe" ) ||
2477 !strcasecmp( name
+ len
- 4, ".com" ));
2481 /***********************************************************************
2482 * FILE_AddBootRenameEntry
2484 * Adds an entry to the registry that is loaded when windows boots and
2485 * checks if there are some files to be removed or renamed/moved.
2486 * <fn1> has to be valid and <fn2> may be NULL. If both pointers are
2487 * non-NULL then the file is moved, otherwise it is deleted. The
2488 * entry of the registrykey is always appended with two zero
2489 * terminated strings. If <fn2> is NULL then the second entry is
2490 * simply a single 0-byte. Otherwise the second filename goes
2491 * there. The entries are prepended with \??\ before the path and the
2492 * second filename gets also a '!' as the first character if
2493 * MOVEFILE_REPLACE_EXISTING is set. After the final string another
2494 * 0-byte follows to indicate the end of the strings.
2496 * \??\D:\test\file1[0]
2497 * !\??\D:\test\file1_renamed[0]
2498 * \??\D:\Test|delete[0]
2499 * [0] <- file is to be deleted, second string empty
2500 * \??\D:\test\file2[0]
2501 * !\??\D:\test\file2_renamed[0]
2502 * [0] <- indicates end of strings
2505 * \??\D:\test\file1[0]
2506 * !\??\D:\test\file1_renamed[0]
2507 * \??\D:\Test|delete[0]
2508 * [0] <- file is to be deleted, second string empty
2509 * [0] <- indicates end of strings
2512 static BOOL
FILE_AddBootRenameEntry( LPCWSTR fn1
, LPCWSTR fn2
, DWORD flags
)
2514 static const WCHAR PreString
[] = {'\\','?','?','\\',0};
2515 static const WCHAR ValueName
[] = {'P','e','n','d','i','n','g',
2516 'F','i','l','e','R','e','n','a','m','e',
2517 'O','p','e','r','a','t','i','o','n','s',0};
2518 static const WCHAR SessionW
[] = {'M','a','c','h','i','n','e','\\',
2519 'S','y','s','t','e','m','\\',
2520 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
2521 'C','o','n','t','r','o','l','\\',
2522 'S','e','s','s','i','o','n',' ','M','a','n','a','g','e','r',0};
2523 static const int info_size
= FIELD_OFFSET( KEY_VALUE_PARTIAL_INFORMATION
, Data
);
2525 OBJECT_ATTRIBUTES attr
;
2526 UNICODE_STRING nameW
;
2527 KEY_VALUE_PARTIAL_INFORMATION
*info
;
2530 DWORD len0
, len1
, len2
;
2532 BYTE
*Buffer
= NULL
;
2535 attr
.Length
= sizeof(attr
);
2536 attr
.RootDirectory
= 0;
2537 attr
.ObjectName
= &nameW
;
2538 attr
.Attributes
= 0;
2539 attr
.SecurityDescriptor
= NULL
;
2540 attr
.SecurityQualityOfService
= NULL
;
2541 RtlInitUnicodeString( &nameW
, SessionW
);
2543 if (NtCreateKey( &Reboot
, KEY_ALL_ACCESS
, &attr
, 0, NULL
, 0, NULL
) != STATUS_SUCCESS
)
2545 WARN("Error creating key for reboot managment [%s]\n",
2546 "SYSTEM\\CurrentControlSet\\Control\\Session Manager");
2550 len0
= strlenW(PreString
);
2551 len1
= strlenW(fn1
) + len0
+ 1;
2554 len2
= strlenW(fn2
) + len0
+ 1;
2555 if (flags
& MOVEFILE_REPLACE_EXISTING
) len2
++; /* Plus 1 because of the leading '!' */
2557 else len2
= 1; /* minimum is the 0 characters for the empty second string */
2559 /* convert characters to bytes */
2560 len0
*= sizeof(WCHAR
);
2561 len1
*= sizeof(WCHAR
);
2562 len2
*= sizeof(WCHAR
);
2564 RtlInitUnicodeString( &nameW
, ValueName
);
2566 /* First we check if the key exists and if so how many bytes it already contains. */
2567 if (NtQueryValueKey( Reboot
, &nameW
, KeyValuePartialInformation
,
2568 NULL
, 0, &DataSize
) == STATUS_BUFFER_OVERFLOW
)
2570 if (!(Buffer
= HeapAlloc( GetProcessHeap(), 0, DataSize
+ len1
+ len2
+ sizeof(WCHAR
) )))
2572 if (NtQueryValueKey( Reboot
, &nameW
, KeyValuePartialInformation
,
2573 Buffer
, DataSize
, &DataSize
)) goto Quit
;
2574 info
= (KEY_VALUE_PARTIAL_INFORMATION
*)Buffer
;
2575 if (info
->Type
!= REG_MULTI_SZ
) goto Quit
;
2576 if (DataSize
> sizeof(info
)) DataSize
-= sizeof(WCHAR
); /* remove terminating null (will be added back later) */
2580 DataSize
= info_size
;
2581 if (!(Buffer
= HeapAlloc( GetProcessHeap(), 0, DataSize
+ len1
+ len2
+ sizeof(WCHAR
) )))
2585 p
= (WCHAR
*)(Buffer
+ DataSize
);
2586 strcpyW( p
, PreString
);
2591 p
= (WCHAR
*)(Buffer
+ DataSize
);
2592 if (flags
& MOVEFILE_REPLACE_EXISTING
)
2594 strcpyW( p
, PreString
);
2600 p
= (WCHAR
*)(Buffer
+ DataSize
);
2602 DataSize
+= sizeof(WCHAR
);
2605 /* add final null */
2606 p
= (WCHAR
*)(Buffer
+ DataSize
);
2608 DataSize
+= sizeof(WCHAR
);
2610 rc
= !NtSetValueKey(Reboot
, &nameW
, 0, REG_MULTI_SZ
, Buffer
+ info_size
, DataSize
- info_size
);
2613 if (Reboot
) NtClose(Reboot
);
2614 if (Buffer
) HeapFree( GetProcessHeap(), 0, Buffer
);
2619 /**************************************************************************
2620 * MoveFileExW (KERNEL32.@)
2622 BOOL WINAPI
MoveFileExW( LPCWSTR fn1
, LPCWSTR fn2
, DWORD flag
)
2624 DOS_FULL_NAME full_name1
, full_name2
;
2626 DWORD attr
= INVALID_FILE_ATTRIBUTES
;
2628 TRACE("(%s,%s,%04lx)\n", debugstr_w(fn1
), debugstr_w(fn2
), flag
);
2630 /* FIXME: <Gerhard W. Gruber>sparhawk@gmx.at
2631 In case of W9x and lesser this function should return 120 (ERROR_CALL_NOT_IMPLEMENTED)
2632 to be really compatible. Most programs wont have any problems though. In case
2633 you encounter one, this is what you should return here. I don't know what's up
2634 with NT 3.5. Is this function available there or not?
2635 Does anybody really care about 3.5? :)
2638 /* Filename1 has to be always set to a valid path. Filename2 may be NULL
2639 if the source file has to be deleted.
2642 SetLastError(ERROR_INVALID_PARAMETER
);
2646 /* This function has to be run through in order to process the name properly.
2647 If the BOOTDELAY flag is set, the file doesn't need to exist though. At least
2648 that is the behaviour on NT 4.0. The operation accepts the filenames as
2649 they are given but it can't reply with a reasonable returncode. Success
2650 means in that case success for entering the values into the registry.
2652 if(!DOSFS_GetFullName( fn1
, TRUE
, &full_name1
))
2654 if(!(flag
& MOVEFILE_DELAY_UNTIL_REBOOT
))
2658 if (fn2
) /* !fn2 means delete fn1 */
2660 if (DOSFS_GetFullName( fn2
, TRUE
, &full_name2
))
2662 if(!(flag
& MOVEFILE_DELAY_UNTIL_REBOOT
))
2664 /* target exists, check if we may overwrite */
2665 if (!(flag
& MOVEFILE_REPLACE_EXISTING
))
2667 SetLastError( ERROR_FILE_EXISTS
);
2674 if (!DOSFS_GetFullName( fn2
, FALSE
, &full_name2
))
2676 if(!(flag
& MOVEFILE_DELAY_UNTIL_REBOOT
))
2681 /* Source name and target path are valid */
2683 if (flag
& MOVEFILE_DELAY_UNTIL_REBOOT
)
2685 /* FIXME: (bon@elektron.ikp.physik.th-darmstadt.de 970706)
2686 Perhaps we should queue these command and execute it
2687 when exiting... What about using on_exit(2)
2689 FIXME("Please move existing file %s to file %s when Wine has finished\n",
2690 debugstr_w(fn1
), debugstr_w(fn2
));
2691 return FILE_AddBootRenameEntry( fn1
, fn2
, flag
);
2694 attr
= GetFileAttributesW( fn1
);
2695 if ( attr
== INVALID_FILE_ATTRIBUTES
) return FALSE
;
2697 /* check if we are allowed to rename the source */
2698 hFile
= FILE_CreateFile( full_name1
.long_name
, 0, 0,
2699 NULL
, OPEN_EXISTING
, 0, 0, TRUE
,
2700 GetDriveTypeW( full_name1
.short_name
) );
2703 if (GetLastError() != ERROR_ACCESS_DENIED
) return FALSE
;
2704 if ( !(attr
& FILE_ATTRIBUTE_DIRECTORY
) ) return FALSE
;
2705 /* if it's a directory we can continue */
2707 else CloseHandle(hFile
);
2709 /* check, if we are allowed to delete the destination,
2710 ** (but the file not being there is fine) */
2711 hFile
= FILE_CreateFile( full_name2
.long_name
, GENERIC_READ
|GENERIC_WRITE
, 0,
2712 NULL
, OPEN_EXISTING
, 0, 0, TRUE
,
2713 GetDriveTypeW( full_name2
.short_name
) );
2714 if(!hFile
&& GetLastError() != ERROR_FILE_NOT_FOUND
) return FALSE
;
2717 if (full_name1
.drive
!= full_name2
.drive
)
2719 if (!(flag
& MOVEFILE_COPY_ALLOWED
))
2721 SetLastError( ERROR_NOT_SAME_DEVICE
);
2724 else if ( attr
& FILE_ATTRIBUTE_DIRECTORY
)
2726 /* Strange, but that's what Windows returns */
2727 SetLastError ( ERROR_ACCESS_DENIED
);
2731 if (rename( full_name1
.long_name
, full_name2
.long_name
) == -1)
2732 /* Try copy/delete unless it's a directory. */
2733 /* FIXME: This does not handle the (unlikely) case that the two locations
2734 are on the same Wine drive, but on different Unix file systems. */
2736 if ( attr
& FILE_ATTRIBUTE_DIRECTORY
)
2743 if ( ! CopyFileW( fn1
, fn2
, !(flag
& MOVEFILE_REPLACE_EXISTING
) ))
2745 if ( ! DeleteFileW ( fn1
) )
2749 if (is_executable( full_name1
.long_name
) != is_executable( full_name2
.long_name
))
2752 if (stat( full_name2
.long_name
, &fstat
) != -1)
2754 if (is_executable( full_name2
.long_name
))
2755 /* set executable bit where read bit is set */
2756 fstat
.st_mode
|= (fstat
.st_mode
& 0444) >> 2;
2758 fstat
.st_mode
&= ~0111;
2759 chmod( full_name2
.long_name
, fstat
.st_mode
);
2764 else /* fn2 == NULL means delete source */
2766 if (flag
& MOVEFILE_DELAY_UNTIL_REBOOT
)
2768 if (flag
& MOVEFILE_COPY_ALLOWED
) {
2769 WARN("Illegal flag\n");
2770 SetLastError( ERROR_GEN_FAILURE
);
2773 /* FIXME: (bon@elektron.ikp.physik.th-darmstadt.de 970706)
2774 Perhaps we should queue these command and execute it
2775 when exiting... What about using on_exit(2)
2777 FIXME("Please delete file %s when Wine has finished\n", debugstr_w(fn1
));
2778 return FILE_AddBootRenameEntry( fn1
, NULL
, flag
);
2781 if (unlink( full_name1
.long_name
) == -1)
2786 return TRUE
; /* successfully deleted */
2790 /**************************************************************************
2791 * MoveFileExA (KERNEL32.@)
2793 BOOL WINAPI
MoveFileExA( LPCSTR fn1
, LPCSTR fn2
, DWORD flag
)
2795 UNICODE_STRING fn1W
, fn2W
;
2800 SetLastError(ERROR_INVALID_PARAMETER
);
2804 RtlCreateUnicodeStringFromAsciiz(&fn1W
, fn1
);
2805 if (fn2
) RtlCreateUnicodeStringFromAsciiz(&fn2W
, fn2
);
2806 else fn2W
.Buffer
= NULL
;
2808 ret
= MoveFileExW( fn1W
.Buffer
, fn2W
.Buffer
, flag
);
2810 RtlFreeUnicodeString(&fn1W
);
2811 RtlFreeUnicodeString(&fn2W
);
2816 /**************************************************************************
2817 * MoveFileW (KERNEL32.@)
2819 * Move file or directory
2821 BOOL WINAPI
MoveFileW( LPCWSTR fn1
, LPCWSTR fn2
)
2823 DOS_FULL_NAME full_name1
, full_name2
;
2828 SetLastError(ERROR_INVALID_PARAMETER
);
2832 TRACE("(%s,%s)\n", debugstr_w(fn1
), debugstr_w(fn2
) );
2834 if (!DOSFS_GetFullName( fn1
, TRUE
, &full_name1
)) return FALSE
;
2835 if (DOSFS_GetFullName( fn2
, TRUE
, &full_name2
)) {
2836 /* The new name must not already exist */
2837 SetLastError(ERROR_ALREADY_EXISTS
);
2840 if (!DOSFS_GetFullName( fn2
, FALSE
, &full_name2
)) return FALSE
;
2842 if (full_name1
.drive
== full_name2
.drive
) /* move */
2843 return MoveFileExW( fn1
, fn2
, MOVEFILE_COPY_ALLOWED
);
2846 if (stat( full_name1
.long_name
, &fstat
))
2848 WARN("Invalid source file %s\n",
2849 full_name1
.long_name
);
2853 if (S_ISDIR(fstat
.st_mode
)) {
2854 /* No Move for directories across file systems */
2855 /* FIXME: Use right error code */
2856 SetLastError( ERROR_GEN_FAILURE
);
2859 return CopyFileW(fn1
, fn2
, TRUE
); /*fail, if exist */
2863 /**************************************************************************
2864 * MoveFileA (KERNEL32.@)
2866 BOOL WINAPI
MoveFileA( LPCSTR fn1
, LPCSTR fn2
)
2868 UNICODE_STRING fn1W
, fn2W
;
2873 SetLastError(ERROR_INVALID_PARAMETER
);
2877 RtlCreateUnicodeStringFromAsciiz(&fn1W
, fn1
);
2878 RtlCreateUnicodeStringFromAsciiz(&fn2W
, fn2
);
2880 ret
= MoveFileW( fn1W
.Buffer
, fn2W
.Buffer
);
2882 RtlFreeUnicodeString(&fn1W
);
2883 RtlFreeUnicodeString(&fn2W
);
2888 /**************************************************************************
2889 * CopyFileW (KERNEL32.@)
2891 BOOL WINAPI
CopyFileW( LPCWSTR source
, LPCWSTR dest
, BOOL fail_if_exists
)
2894 BY_HANDLE_FILE_INFORMATION info
;
2899 if (!source
|| !dest
)
2901 SetLastError(ERROR_INVALID_PARAMETER
);
2905 TRACE("%s -> %s\n", debugstr_w(source
), debugstr_w(dest
));
2907 if ((h1
= CreateFileW(source
, GENERIC_READ
, FILE_SHARE_READ
| FILE_SHARE_WRITE
,
2908 NULL
, OPEN_EXISTING
, 0, 0)) == INVALID_HANDLE_VALUE
)
2910 WARN("Unable to open source %s\n", debugstr_w(source
));
2914 if (!GetFileInformationByHandle( h1
, &info
))
2916 WARN("GetFileInformationByHandle returned error for %s\n", debugstr_w(source
));
2921 if ((h2
= CreateFileW( dest
, GENERIC_WRITE
, FILE_SHARE_READ
| FILE_SHARE_WRITE
, NULL
,
2922 fail_if_exists
? CREATE_NEW
: CREATE_ALWAYS
,
2923 info
.dwFileAttributes
, h1
)) == INVALID_HANDLE_VALUE
)
2925 WARN("Unable to open dest %s\n", debugstr_w(dest
));
2930 while (ReadFile( h1
, buffer
, sizeof(buffer
), &count
, NULL
) && count
)
2936 if (!WriteFile( h2
, p
, count
, &res
, NULL
) || !res
) goto done
;
2949 /**************************************************************************
2950 * CopyFileA (KERNEL32.@)
2952 BOOL WINAPI
CopyFileA( LPCSTR source
, LPCSTR dest
, BOOL fail_if_exists
)
2954 UNICODE_STRING sourceW
, destW
;
2957 if (!source
|| !dest
)
2959 SetLastError(ERROR_INVALID_PARAMETER
);
2963 RtlCreateUnicodeStringFromAsciiz(&sourceW
, source
);
2964 RtlCreateUnicodeStringFromAsciiz(&destW
, dest
);
2966 ret
= CopyFileW(sourceW
.Buffer
, destW
.Buffer
, fail_if_exists
);
2968 RtlFreeUnicodeString(&sourceW
);
2969 RtlFreeUnicodeString(&destW
);
2974 /**************************************************************************
2975 * CopyFileExW (KERNEL32.@)
2977 * This implementation ignores most of the extra parameters passed-in into
2978 * the "ex" version of the method and calls the CopyFile method.
2979 * It will have to be fixed eventually.
2981 BOOL WINAPI
CopyFileExW(LPCWSTR sourceFilename
, LPCWSTR destFilename
,
2982 LPPROGRESS_ROUTINE progressRoutine
, LPVOID appData
,
2983 LPBOOL cancelFlagPointer
, DWORD copyFlags
)
2986 * Interpret the only flag that CopyFile can interpret.
2988 return CopyFileW(sourceFilename
, destFilename
, (copyFlags
& COPY_FILE_FAIL_IF_EXISTS
) != 0);
2991 /**************************************************************************
2992 * CopyFileExA (KERNEL32.@)
2994 BOOL WINAPI
CopyFileExA(LPCSTR sourceFilename
, LPCSTR destFilename
,
2995 LPPROGRESS_ROUTINE progressRoutine
, LPVOID appData
,
2996 LPBOOL cancelFlagPointer
, DWORD copyFlags
)
2998 UNICODE_STRING sourceW
, destW
;
3001 if (!sourceFilename
|| !destFilename
)
3003 SetLastError(ERROR_INVALID_PARAMETER
);
3007 RtlCreateUnicodeStringFromAsciiz(&sourceW
, sourceFilename
);
3008 RtlCreateUnicodeStringFromAsciiz(&destW
, destFilename
);
3010 ret
= CopyFileExW(sourceW
.Buffer
, destW
.Buffer
, progressRoutine
, appData
,
3011 cancelFlagPointer
, copyFlags
);
3013 RtlFreeUnicodeString(&sourceW
);
3014 RtlFreeUnicodeString(&destW
);
3019 /***********************************************************************
3020 * SetFileTime (KERNEL32.@)
3022 BOOL WINAPI
SetFileTime( HANDLE hFile
,
3023 const FILETIME
*lpCreationTime
,
3024 const FILETIME
*lpLastAccessTime
,
3025 const FILETIME
*lpLastWriteTime
)
3028 SERVER_START_REQ( set_file_time
)
3030 req
->handle
= hFile
;
3031 if (lpLastAccessTime
)
3032 RtlTimeToSecondsSince1970( (PLARGE_INTEGER
) lpLastAccessTime
, (DWORD
*)&req
->access_time
);
3034 req
->access_time
= 0; /* FIXME */
3035 if (lpLastWriteTime
)
3036 RtlTimeToSecondsSince1970( (PLARGE_INTEGER
) lpLastWriteTime
, (DWORD
*)&req
->write_time
);
3038 req
->write_time
= 0; /* FIXME */
3039 ret
= !wine_server_call_err( req
);
3046 /**************************************************************************
3047 * LockFile (KERNEL32.@)
3049 BOOL WINAPI
LockFile( HANDLE hFile
, DWORD dwFileOffsetLow
, DWORD dwFileOffsetHigh
,
3050 DWORD nNumberOfBytesToLockLow
, DWORD nNumberOfBytesToLockHigh
)
3054 FIXME("not implemented in server\n");
3056 SERVER_START_REQ( lock_file
)
3058 req
->handle
= hFile
;
3059 req
->offset_low
= dwFileOffsetLow
;
3060 req
->offset_high
= dwFileOffsetHigh
;
3061 req
->count_low
= nNumberOfBytesToLockLow
;
3062 req
->count_high
= nNumberOfBytesToLockHigh
;
3063 ret
= !wine_server_call_err( req
);
3069 /**************************************************************************
3070 * LockFileEx [KERNEL32.@]
3072 * Locks a byte range within an open file for shared or exclusive access.
3079 * Per Microsoft docs, the third parameter (reserved) must be set to 0.
3081 BOOL WINAPI
LockFileEx( HANDLE hFile
, DWORD flags
, DWORD reserved
,
3082 DWORD nNumberOfBytesToLockLow
, DWORD nNumberOfBytesToLockHigh
,
3083 LPOVERLAPPED pOverlapped
)
3085 FIXME("hFile=%d,flags=%ld,reserved=%ld,lowbytes=%ld,highbytes=%ld,overlapped=%p: stub.\n",
3086 hFile
, flags
, reserved
, nNumberOfBytesToLockLow
, nNumberOfBytesToLockHigh
,
3089 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
3092 ERR("reserved == %ld: Supposed to be 0??\n", reserved
);
3093 SetLastError(ERROR_INVALID_PARAMETER
);
3100 /**************************************************************************
3101 * UnlockFile (KERNEL32.@)
3103 BOOL WINAPI
UnlockFile( HANDLE hFile
, DWORD dwFileOffsetLow
, DWORD dwFileOffsetHigh
,
3104 DWORD nNumberOfBytesToUnlockLow
, DWORD nNumberOfBytesToUnlockHigh
)
3108 FIXME("not implemented in server\n");
3110 SERVER_START_REQ( unlock_file
)
3112 req
->handle
= hFile
;
3113 req
->offset_low
= dwFileOffsetLow
;
3114 req
->offset_high
= dwFileOffsetHigh
;
3115 req
->count_low
= nNumberOfBytesToUnlockLow
;
3116 req
->count_high
= nNumberOfBytesToUnlockHigh
;
3117 ret
= !wine_server_call_err( req
);
3124 /**************************************************************************
3125 * UnlockFileEx (KERNEL32.@)
3127 BOOL WINAPI
UnlockFileEx(
3130 DWORD nNumberOfBytesToUnlockLow
,
3131 DWORD nNumberOfBytesToUnlockHigh
,
3132 LPOVERLAPPED lpOverlapped
3135 FIXME("hFile=%d,reserved=%ld,lowbytes=%ld,highbytes=%ld,overlapped=%p: stub.\n",
3136 hFile
, dwReserved
, nNumberOfBytesToUnlockLow
, nNumberOfBytesToUnlockHigh
,
3138 if (dwReserved
== 0)
3139 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
3142 ERR("reserved == %ld: Supposed to be 0??\n", dwReserved
);
3143 SetLastError(ERROR_INVALID_PARAMETER
);
3152 struct DOS_FILE_LOCK
{
3153 struct DOS_FILE_LOCK
* next
;
3157 FILE_OBJECT
* dos_file
;
3158 /* char * unix_name;*/
3161 typedef struct DOS_FILE_LOCK DOS_FILE_LOCK
;
3163 static DOS_FILE_LOCK
*locks
= NULL
;
3164 static void DOS_RemoveFileLocks(FILE_OBJECT
*file
);
3167 /* Locks need to be mirrored because unix file locking is based
3168 * on the pid. Inside of wine there can be multiple WINE processes
3169 * that share the same unix pid.
3170 * Read's and writes should check these locks also - not sure
3171 * how critical that is at this point (FIXME).
3174 static BOOL
DOS_AddLock(FILE_OBJECT
*file
, struct flock
*f
)
3176 DOS_FILE_LOCK
*curr
;
3179 processId
= GetCurrentProcessId();
3181 /* check if lock overlaps a current lock for the same file */
3183 for (curr
= locks
; curr
; curr
= curr
->next
) {
3184 if (strcmp(curr
->unix_name
, file
->unix_name
) == 0) {
3185 if ((f
->l_start
== curr
->base
) && (f
->l_len
== curr
->len
))
3186 return TRUE
;/* region is identic */
3187 if ((f
->l_start
< (curr
->base
+ curr
->len
)) &&
3188 ((f
->l_start
+ f
->l_len
) > curr
->base
)) {
3189 /* region overlaps */
3196 curr
= HeapAlloc( GetProcessHeap(), 0, sizeof(DOS_FILE_LOCK
) );
3197 curr
->processId
= GetCurrentProcessId();
3198 curr
->base
= f
->l_start
;
3199 curr
->len
= f
->l_len
;
3200 /* curr->unix_name = HEAP_strdupA( GetProcessHeap(), 0, file->unix_name);*/
3202 curr
->dos_file
= file
;
3207 static void DOS_RemoveFileLocks(FILE_OBJECT
*file
)
3210 DOS_FILE_LOCK
**curr
;
3213 processId
= GetCurrentProcessId();
3216 if ((*curr
)->dos_file
== file
) {
3218 *curr
= (*curr
)->next
;
3219 /* HeapFree( GetProcessHeap(), 0, rem->unix_name );*/
3220 HeapFree( GetProcessHeap(), 0, rem
);
3223 curr
= &(*curr
)->next
;
3227 static BOOL
DOS_RemoveLock(FILE_OBJECT
*file
, struct flock
*f
)
3230 DOS_FILE_LOCK
**curr
;
3233 processId
= GetCurrentProcessId();
3234 for (curr
= &locks
; *curr
; curr
= &(*curr
)->next
) {
3235 if ((*curr
)->processId
== processId
&&
3236 (*curr
)->dos_file
== file
&&
3237 (*curr
)->base
== f
->l_start
&&
3238 (*curr
)->len
== f
->l_len
) {
3239 /* this is the same lock */
3241 *curr
= (*curr
)->next
;
3242 /* HeapFree( GetProcessHeap(), 0, rem->unix_name );*/
3243 HeapFree( GetProcessHeap(), 0, rem
);
3247 /* no matching lock found */
3252 /**************************************************************************
3253 * LockFile (KERNEL32.@)
3255 BOOL WINAPI
LockFile(
3256 HANDLE hFile
,DWORD dwFileOffsetLow
,DWORD dwFileOffsetHigh
,
3257 DWORD nNumberOfBytesToLockLow
,DWORD nNumberOfBytesToLockHigh
)
3262 TRACE("handle %d offsetlow=%ld offsethigh=%ld nbyteslow=%ld nbyteshigh=%ld\n",
3263 hFile
, dwFileOffsetLow
, dwFileOffsetHigh
,
3264 nNumberOfBytesToLockLow
, nNumberOfBytesToLockHigh
);
3266 if (dwFileOffsetHigh
|| nNumberOfBytesToLockHigh
) {
3267 FIXME("Unimplemented bytes > 32bits\n");
3271 f
.l_start
= dwFileOffsetLow
;
3272 f
.l_len
= nNumberOfBytesToLockLow
;
3273 f
.l_whence
= SEEK_SET
;
3277 if (!(file
= FILE_GetFile(hFile
,0,NULL
))) return FALSE
;
3279 /* shadow locks internally */
3280 if (!DOS_AddLock(file
, &f
)) {
3281 SetLastError( ERROR_LOCK_VIOLATION
);
3285 /* FIXME: Unix locking commented out for now, doesn't work with Excel */
3286 #ifdef USE_UNIX_LOCKS
3287 if (fcntl(file
->unix_handle
, F_SETLK
, &f
) == -1) {
3288 if (errno
== EACCES
|| errno
== EAGAIN
) {
3289 SetLastError( ERROR_LOCK_VIOLATION
);
3294 /* remove our internal copy of the lock */
3295 DOS_RemoveLock(file
, &f
);
3303 /**************************************************************************
3304 * UnlockFile (KERNEL32.@)
3306 BOOL WINAPI
UnlockFile(
3307 HANDLE hFile
,DWORD dwFileOffsetLow
,DWORD dwFileOffsetHigh
,
3308 DWORD nNumberOfBytesToUnlockLow
,DWORD nNumberOfBytesToUnlockHigh
)
3313 TRACE("handle %d offsetlow=%ld offsethigh=%ld nbyteslow=%ld nbyteshigh=%ld\n",
3314 hFile
, dwFileOffsetLow
, dwFileOffsetHigh
,
3315 nNumberOfBytesToUnlockLow
, nNumberOfBytesToUnlockHigh
);
3317 if (dwFileOffsetHigh
|| nNumberOfBytesToUnlockHigh
) {
3318 WARN("Unimplemented bytes > 32bits\n");
3322 f
.l_start
= dwFileOffsetLow
;
3323 f
.l_len
= nNumberOfBytesToUnlockLow
;
3324 f
.l_whence
= SEEK_SET
;
3328 if (!(file
= FILE_GetFile(hFile
,0,NULL
))) return FALSE
;
3330 DOS_RemoveLock(file
, &f
); /* ok if fails - may be another wine */
3332 /* FIXME: Unix locking commented out for now, doesn't work with Excel */
3333 #ifdef USE_UNIX_LOCKS
3334 if (fcntl(file
->unix_handle
, F_SETLK
, &f
) == -1) {
3343 /**************************************************************************
3344 * GetFileAttributesExW (KERNEL32.@)
3346 BOOL WINAPI
GetFileAttributesExW(
3347 LPCWSTR lpFileName
, GET_FILEEX_INFO_LEVELS fInfoLevelId
,
3348 LPVOID lpFileInformation
)
3350 DOS_FULL_NAME full_name
;
3351 BY_HANDLE_FILE_INFORMATION info
;
3353 if (!lpFileName
|| !lpFileInformation
)
3355 SetLastError(ERROR_INVALID_PARAMETER
);
3359 if (fInfoLevelId
== GetFileExInfoStandard
) {
3360 LPWIN32_FILE_ATTRIBUTE_DATA lpFad
=
3361 (LPWIN32_FILE_ATTRIBUTE_DATA
) lpFileInformation
;
3362 if (!DOSFS_GetFullName( lpFileName
, TRUE
, &full_name
)) return FALSE
;
3363 if (!FILE_Stat( full_name
.long_name
, &info
, NULL
)) return FALSE
;
3365 lpFad
->dwFileAttributes
= info
.dwFileAttributes
;
3366 lpFad
->ftCreationTime
= info
.ftCreationTime
;
3367 lpFad
->ftLastAccessTime
= info
.ftLastAccessTime
;
3368 lpFad
->ftLastWriteTime
= info
.ftLastWriteTime
;
3369 lpFad
->nFileSizeHigh
= info
.nFileSizeHigh
;
3370 lpFad
->nFileSizeLow
= info
.nFileSizeLow
;
3373 FIXME("invalid info level %d!\n", fInfoLevelId
);
3381 /**************************************************************************
3382 * GetFileAttributesExA (KERNEL32.@)
3384 BOOL WINAPI
GetFileAttributesExA(
3385 LPCSTR filename
, GET_FILEEX_INFO_LEVELS fInfoLevelId
,
3386 LPVOID lpFileInformation
)
3388 UNICODE_STRING filenameW
;
3391 if (!filename
|| !lpFileInformation
)
3393 SetLastError(ERROR_INVALID_PARAMETER
);
3397 if (RtlCreateUnicodeStringFromAsciiz(&filenameW
, filename
))
3399 ret
= GetFileAttributesExW(filenameW
.Buffer
, fInfoLevelId
, lpFileInformation
);
3400 RtlFreeUnicodeString(&filenameW
);
3403 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);