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
)
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
);
762 if (is_symlink
) info
->dwFileAttributes
|= FILE_ATTRIBUTE_SYMLINK
;
764 /* and now see if this is a hidden file, based on the name */
765 p
= strrchr( unixName
, '/');
766 p
= p
? p
+ 1 : unixName
;
767 if (*p
== '.' && *(p
+1) && (*(p
+1) != '.' || *(p
+2)))
769 static const WCHAR wineW
[] = {'w','i','n','e',0};
770 static const WCHAR ShowDotFilesW
[] = {'S','h','o','w','D','o','t','F','i','l','e','s',0};
771 static int show_dot_files
= -1;
772 if (show_dot_files
== -1)
773 show_dot_files
= PROFILE_GetWineIniBool(wineW
, ShowDotFilesW
, 0);
775 info
->dwFileAttributes
|= FILE_ATTRIBUTE_HIDDEN
;
782 /***********************************************************************
783 * GetFileInformationByHandle (KERNEL32.@)
785 DWORD WINAPI
GetFileInformationByHandle( HANDLE hFile
,
786 BY_HANDLE_FILE_INFORMATION
*info
)
791 TRACE("%08x\n", hFile
);
793 SERVER_START_REQ( get_file_info
)
796 if ((ret
= !wine_server_call_err( req
)))
798 /* FIXME: which file types are supported ?
799 * Serial ports (FILE_TYPE_CHAR) are not,
800 * and MSDN also says that pipes are not supported.
801 * FILE_TYPE_REMOTE seems to be supported according to
802 * MSDN q234741.txt */
803 if ((reply
->type
== FILE_TYPE_DISK
) || (reply
->type
== FILE_TYPE_REMOTE
))
805 RtlSecondsSince1970ToTime( reply
->write_time
, (LARGE_INTEGER
*)&info
->ftCreationTime
);
806 RtlSecondsSince1970ToTime( reply
->write_time
, (LARGE_INTEGER
*)&info
->ftLastWriteTime
);
807 RtlSecondsSince1970ToTime( reply
->access_time
, (LARGE_INTEGER
*)&info
->ftLastAccessTime
);
808 info
->dwFileAttributes
= reply
->attr
;
809 info
->dwVolumeSerialNumber
= reply
->serial
;
810 info
->nFileSizeHigh
= reply
->size_high
;
811 info
->nFileSizeLow
= reply
->size_low
;
812 info
->nNumberOfLinks
= reply
->links
;
813 info
->nFileIndexHigh
= reply
->index_high
;
814 info
->nFileIndexLow
= reply
->index_low
;
818 SetLastError(ERROR_NOT_SUPPORTED
);
828 /**************************************************************************
829 * GetFileAttributes (KERNEL.420)
831 DWORD WINAPI
GetFileAttributes16( LPCSTR name
)
833 return GetFileAttributesA( name
);
837 /**************************************************************************
838 * GetFileAttributesW (KERNEL32.@)
840 DWORD WINAPI
GetFileAttributesW( LPCWSTR name
)
842 DOS_FULL_NAME full_name
;
843 BY_HANDLE_FILE_INFORMATION info
;
847 SetLastError( ERROR_INVALID_PARAMETER
);
850 if (!DOSFS_GetFullName( name
, TRUE
, &full_name
) )
852 if (!FILE_Stat( full_name
.long_name
, &info
)) return -1;
853 return info
.dwFileAttributes
;
857 /**************************************************************************
858 * GetFileAttributesA (KERNEL32.@)
860 DWORD WINAPI
GetFileAttributesA( LPCSTR name
)
862 UNICODE_STRING nameW
;
863 DWORD ret
= (DWORD
)-1;
867 SetLastError( ERROR_INVALID_PARAMETER
);
871 if (RtlCreateUnicodeStringFromAsciiz(&nameW
, name
))
873 ret
= GetFileAttributesW(nameW
.Buffer
);
874 RtlFreeUnicodeString(&nameW
);
877 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
882 /**************************************************************************
883 * SetFileAttributes (KERNEL.421)
885 BOOL16 WINAPI
SetFileAttributes16( LPCSTR lpFileName
, DWORD attributes
)
887 return SetFileAttributesA( lpFileName
, attributes
);
891 /**************************************************************************
892 * SetFileAttributesW (KERNEL32.@)
894 BOOL WINAPI
SetFileAttributesW(LPCWSTR lpFileName
, DWORD attributes
)
897 DOS_FULL_NAME full_name
;
901 SetLastError( ERROR_INVALID_PARAMETER
);
905 TRACE("(%s,%lx)\n", debugstr_w(lpFileName
), attributes
);
907 if (!DOSFS_GetFullName( lpFileName
, TRUE
, &full_name
))
910 if(stat(full_name
.long_name
,&buf
)==-1)
915 if (attributes
& FILE_ATTRIBUTE_READONLY
)
917 if(S_ISDIR(buf
.st_mode
))
919 WARN("FILE_ATTRIBUTE_READONLY ignored for directory.\n");
921 buf
.st_mode
&= ~0222; /* octal!, clear write permission bits */
922 attributes
&= ~FILE_ATTRIBUTE_READONLY
;
926 /* add write permission */
927 buf
.st_mode
|= (0600 | ((buf
.st_mode
& 044) >> 1)) & (~FILE_umask
);
929 if (attributes
& FILE_ATTRIBUTE_DIRECTORY
)
931 if (!S_ISDIR(buf
.st_mode
))
932 FIXME("SetFileAttributes expected the file %s to be a directory\n",
933 debugstr_w(lpFileName
));
934 attributes
&= ~FILE_ATTRIBUTE_DIRECTORY
;
936 attributes
&= ~(FILE_ATTRIBUTE_NORMAL
|FILE_ATTRIBUTE_ARCHIVE
|FILE_ATTRIBUTE_HIDDEN
|FILE_ATTRIBUTE_SYSTEM
);
938 FIXME("(%s):%lx attribute(s) not implemented.\n", debugstr_w(lpFileName
), attributes
);
939 if (-1==chmod(full_name
.long_name
,buf
.st_mode
))
941 if (GetDriveTypeW(lpFileName
) == DRIVE_CDROM
)
943 SetLastError( ERROR_ACCESS_DENIED
);
948 * FIXME: We don't return FALSE here because of differences between
949 * Linux and Windows privileges. Under Linux only the owner of
950 * the file is allowed to change file attributes. Under Windows,
951 * applications expect that if you can write to a file, you can also
952 * change its attributes (see GENERIC_WRITE). We could try to be
953 * clever here but that would break multi-user installations where
954 * users share read-only DLLs. This is because some installers like
955 * to change attributes of already installed DLLs.
957 FIXME("Couldn't set file attributes for existing file \"%s\".\n"
958 "Check permissions or set VFAT \"quiet\" mount flag\n", full_name
.long_name
);
964 /**************************************************************************
965 * SetFileAttributesA (KERNEL32.@)
967 BOOL WINAPI
SetFileAttributesA(LPCSTR lpFileName
, DWORD attributes
)
969 UNICODE_STRING filenameW
;
974 SetLastError( ERROR_INVALID_PARAMETER
);
978 if (RtlCreateUnicodeStringFromAsciiz(&filenameW
, lpFileName
))
980 ret
= SetFileAttributesW(filenameW
.Buffer
, attributes
);
981 RtlFreeUnicodeString(&filenameW
);
984 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
989 /***********************************************************************
990 * GetFileSize (KERNEL32.@)
992 DWORD WINAPI
GetFileSize( HANDLE hFile
, LPDWORD filesizehigh
)
994 BY_HANDLE_FILE_INFORMATION info
;
995 if (!GetFileInformationByHandle( hFile
, &info
)) return -1;
996 if (filesizehigh
) *filesizehigh
= info
.nFileSizeHigh
;
997 return info
.nFileSizeLow
;
1001 /***********************************************************************
1002 * GetFileTime (KERNEL32.@)
1004 BOOL WINAPI
GetFileTime( HANDLE hFile
, FILETIME
*lpCreationTime
,
1005 FILETIME
*lpLastAccessTime
,
1006 FILETIME
*lpLastWriteTime
)
1008 BY_HANDLE_FILE_INFORMATION info
;
1009 if (!GetFileInformationByHandle( hFile
, &info
)) return FALSE
;
1010 if (lpCreationTime
) *lpCreationTime
= info
.ftCreationTime
;
1011 if (lpLastAccessTime
) *lpLastAccessTime
= info
.ftLastAccessTime
;
1012 if (lpLastWriteTime
) *lpLastWriteTime
= info
.ftLastWriteTime
;
1016 /***********************************************************************
1017 * CompareFileTime (KERNEL32.@)
1019 INT WINAPI
CompareFileTime( LPFILETIME x
, LPFILETIME y
)
1021 if (!x
|| !y
) return -1;
1023 if (x
->dwHighDateTime
> y
->dwHighDateTime
)
1025 if (x
->dwHighDateTime
< y
->dwHighDateTime
)
1027 if (x
->dwLowDateTime
> y
->dwLowDateTime
)
1029 if (x
->dwLowDateTime
< y
->dwLowDateTime
)
1034 /***********************************************************************
1035 * FILE_GetTempFileName : utility for GetTempFileName
1037 static UINT
FILE_GetTempFileName( LPCWSTR path
, LPCWSTR prefix
, UINT unique
,
1040 static UINT unique_temp
;
1041 DOS_FULL_NAME full_name
;
1047 if ( !path
|| !prefix
|| !buffer
)
1049 SetLastError( ERROR_INVALID_PARAMETER
);
1053 if (!unique_temp
) unique_temp
= time(NULL
) & 0xffff;
1054 num
= unique
? (unique
& 0xffff) : (unique_temp
++ & 0xffff);
1056 strcpyW( buffer
, path
);
1057 p
= buffer
+ strlenW(buffer
);
1059 /* add a \, if there isn't one and path is more than just the drive letter ... */
1060 if ( !((strlenW(buffer
) == 2) && (buffer
[1] == ':'))
1061 && ((p
== buffer
) || (p
[-1] != '\\'))) *p
++ = '\\';
1063 for (i
= 3; (i
> 0) && (*prefix
); i
--) *p
++ = *prefix
++;
1065 sprintf( buf
, "%04x.tmp", num
);
1066 MultiByteToWideChar(CP_ACP
, 0, buf
, -1, p
, 20);
1068 /* Now try to create it */
1074 HANDLE handle
= CreateFileW( buffer
, GENERIC_WRITE
, 0, NULL
,
1075 CREATE_NEW
, FILE_ATTRIBUTE_NORMAL
, 0 );
1076 if (handle
!= INVALID_HANDLE_VALUE
)
1077 { /* We created it */
1078 TRACE("created %s\n", debugstr_w(buffer
) );
1079 CloseHandle( handle
);
1082 if (GetLastError() != ERROR_FILE_EXISTS
)
1083 break; /* No need to go on */
1085 sprintf( buf
, "%04x.tmp", num
);
1086 MultiByteToWideChar(CP_ACP
, 0, buf
, -1, p
, 20);
1087 } while (num
!= (unique
& 0xffff));
1090 /* Get the full path name */
1092 if (DOSFS_GetFullName( buffer
, FALSE
, &full_name
))
1095 /* Check if we have write access in the directory */
1096 if ((slash
= strrchr( full_name
.long_name
, '/' ))) *slash
= '\0';
1097 if (access( full_name
.long_name
, W_OK
) == -1)
1098 WARN("returns %s, which doesn't seem to be writeable.\n",
1099 debugstr_w(buffer
) );
1101 TRACE("returning %s\n", debugstr_w(buffer
) );
1102 return unique
? unique
: num
;
1106 /***********************************************************************
1107 * GetTempFileNameA (KERNEL32.@)
1109 UINT WINAPI
GetTempFileNameA( LPCSTR path
, LPCSTR prefix
, UINT unique
,
1112 UNICODE_STRING pathW
, prefixW
;
1113 WCHAR bufferW
[MAX_PATH
];
1116 if ( !path
|| !prefix
|| !buffer
)
1118 SetLastError( ERROR_INVALID_PARAMETER
);
1122 RtlCreateUnicodeStringFromAsciiz(&pathW
, path
);
1123 RtlCreateUnicodeStringFromAsciiz(&prefixW
, prefix
);
1125 ret
= GetTempFileNameW(pathW
.Buffer
, prefixW
.Buffer
, unique
, bufferW
);
1127 WideCharToMultiByte(CP_ACP
, 0, bufferW
, -1, buffer
, MAX_PATH
, NULL
, NULL
);
1129 RtlFreeUnicodeString(&pathW
);
1130 RtlFreeUnicodeString(&prefixW
);
1134 /***********************************************************************
1135 * GetTempFileNameW (KERNEL32.@)
1137 UINT WINAPI
GetTempFileNameW( LPCWSTR path
, LPCWSTR prefix
, UINT unique
,
1140 return FILE_GetTempFileName( path
, prefix
, unique
, buffer
);
1144 /***********************************************************************
1145 * GetTempFileName (KERNEL.97)
1147 UINT16 WINAPI
GetTempFileName16( BYTE drive
, LPCSTR prefix
, UINT16 unique
,
1150 char temppath
[MAX_PATH
];
1151 char *prefix16
= NULL
;
1154 if (!(drive
& ~TF_FORCEDRIVE
)) /* drive 0 means current default drive */
1155 drive
|= DRIVE_GetCurrentDrive() + 'A';
1157 if ((drive
& TF_FORCEDRIVE
) &&
1158 !DRIVE_IsValid( toupper(drive
& ~TF_FORCEDRIVE
) - 'A' ))
1160 drive
&= ~TF_FORCEDRIVE
;
1161 WARN("invalid drive %d specified\n", drive
);
1164 if (drive
& TF_FORCEDRIVE
)
1165 sprintf(temppath
,"%c:", drive
& ~TF_FORCEDRIVE
);
1167 GetTempPathA( MAX_PATH
, temppath
);
1171 prefix16
= HeapAlloc(GetProcessHeap(), 0, strlen(prefix
) + 2);
1173 strcpy(prefix16
+ 1, prefix
);
1176 ret
= GetTempFileNameA( temppath
, prefix16
, unique
, buffer
);
1178 if (prefix16
) HeapFree(GetProcessHeap(), 0, prefix16
);
1182 /***********************************************************************
1185 * Implementation of OpenFile16() and OpenFile32().
1187 static HFILE
FILE_DoOpenFile( LPCSTR name
, OFSTRUCT
*ofs
, UINT mode
,
1193 WORD filedatetime
[2];
1194 DOS_FULL_NAME full_name
;
1195 DWORD access
, sharing
;
1197 WCHAR buffer
[MAX_PATH
];
1200 if (!ofs
) return HFILE_ERROR
;
1202 TRACE("%s %s %s %s%s%s%s%s%s%s%s%s\n",name
,
1203 ((mode
& 0x3 )==OF_READ
)?"OF_READ":
1204 ((mode
& 0x3 )==OF_WRITE
)?"OF_WRITE":
1205 ((mode
& 0x3 )==OF_READWRITE
)?"OF_READWRITE":"unknown",
1206 ((mode
& 0x70 )==OF_SHARE_COMPAT
)?"OF_SHARE_COMPAT":
1207 ((mode
& 0x70 )==OF_SHARE_DENY_NONE
)?"OF_SHARE_DENY_NONE":
1208 ((mode
& 0x70 )==OF_SHARE_DENY_READ
)?"OF_SHARE_DENY_READ":
1209 ((mode
& 0x70 )==OF_SHARE_DENY_WRITE
)?"OF_SHARE_DENY_WRITE":
1210 ((mode
& 0x70 )==OF_SHARE_EXCLUSIVE
)?"OF_SHARE_EXCLUSIVE":"unknown",
1211 ((mode
& OF_PARSE
)==OF_PARSE
)?"OF_PARSE ":"",
1212 ((mode
& OF_DELETE
)==OF_DELETE
)?"OF_DELETE ":"",
1213 ((mode
& OF_VERIFY
)==OF_VERIFY
)?"OF_VERIFY ":"",
1214 ((mode
& OF_SEARCH
)==OF_SEARCH
)?"OF_SEARCH ":"",
1215 ((mode
& OF_CANCEL
)==OF_CANCEL
)?"OF_CANCEL ":"",
1216 ((mode
& OF_CREATE
)==OF_CREATE
)?"OF_CREATE ":"",
1217 ((mode
& OF_PROMPT
)==OF_PROMPT
)?"OF_PROMPT ":"",
1218 ((mode
& OF_EXIST
)==OF_EXIST
)?"OF_EXIST ":"",
1219 ((mode
& OF_REOPEN
)==OF_REOPEN
)?"OF_REOPEN ":""
1223 ofs
->cBytes
= sizeof(OFSTRUCT
);
1225 if (mode
& OF_REOPEN
) name
= ofs
->szPathName
;
1228 ERR("called with `name' set to NULL ! Please debug.\n");
1232 TRACE("%s %04x\n", name
, mode
);
1234 /* the watcom 10.6 IDE relies on a valid path returned in ofs->szPathName
1235 Are there any cases where getting the path here is wrong?
1236 Uwe Bonnes 1997 Apr 2 */
1237 if (!GetFullPathNameA( name
, sizeof(ofs
->szPathName
),
1238 ofs
->szPathName
, NULL
)) goto error
;
1239 FILE_ConvertOFMode( mode
, &access
, &sharing
);
1241 /* OF_PARSE simply fills the structure */
1243 if (mode
& OF_PARSE
)
1245 ofs
->fFixedDisk
= (GetDriveType16( ofs
->szPathName
[0]-'A' )
1246 != DRIVE_REMOVABLE
);
1247 TRACE("(%s): OF_PARSE, res = '%s'\n",
1248 name
, ofs
->szPathName
);
1252 /* OF_CREATE is completely different from all other options, so
1255 if (mode
& OF_CREATE
)
1257 if ((handle
= CreateFileA( name
, GENERIC_READ
| GENERIC_WRITE
,
1258 sharing
, NULL
, CREATE_ALWAYS
,
1259 FILE_ATTRIBUTE_NORMAL
, 0 ))== INVALID_HANDLE_VALUE
)
1264 MultiByteToWideChar(CP_ACP
, 0, name
, -1, buffer
, MAX_PATH
);
1267 /* If OF_SEARCH is set, ignore the given path */
1269 if ((mode
& OF_SEARCH
) && !(mode
& OF_REOPEN
))
1271 /* First try the file name as is */
1272 if (DOSFS_GetFullName( nameW
, TRUE
, &full_name
)) goto found
;
1273 /* Now remove the path */
1274 if (nameW
[0] && (nameW
[1] == ':')) nameW
+= 2;
1275 if ((p
= strrchrW( nameW
, '\\' ))) nameW
= p
+ 1;
1276 if ((p
= strrchrW( nameW
, '/' ))) nameW
= p
+ 1;
1277 if (!nameW
[0]) goto not_found
;
1280 /* Now look for the file */
1282 if (!DIR_SearchPath( NULL
, nameW
, NULL
, &full_name
, win32
)) goto not_found
;
1285 TRACE("found %s = %s\n",
1286 full_name
.long_name
, debugstr_w(full_name
.short_name
) );
1287 WideCharToMultiByte(CP_ACP
, 0, full_name
.short_name
, -1,
1288 ofs
->szPathName
, sizeof(ofs
->szPathName
), NULL
, NULL
);
1290 if (mode
& OF_SHARE_EXCLUSIVE
)
1291 /* Some InstallShield version uses OF_SHARE_EXCLUSIVE
1292 on the file <tempdir>/_ins0432._mp to determine how
1293 far installation has proceeded.
1294 _ins0432._mp is an executable and while running the
1295 application expects the open with OF_SHARE_ to fail*/
1297 As our loader closes the files after loading the executable,
1298 we can't find the running executable with FILE_InUse.
1299 The loader should keep the file open, as Windows does that, too.
1302 char *last
= strrchr(full_name
.long_name
,'/');
1304 last
= full_name
.long_name
- 1;
1305 if (GetModuleHandle16(last
+1))
1307 TRACE("Denying shared open for %s\n",full_name
.long_name
);
1312 if (mode
& OF_DELETE
)
1314 if (unlink( full_name
.long_name
) == -1) goto not_found
;
1315 TRACE("(%s): OF_DELETE return = OK\n", name
);
1319 handle
= FILE_CreateFile( full_name
.long_name
, access
, sharing
,
1320 NULL
, OPEN_EXISTING
, 0, 0,
1321 DRIVE_GetFlags(full_name
.drive
) & DRIVE_FAIL_READ_ONLY
,
1322 GetDriveTypeW( full_name
.short_name
) );
1323 if (!handle
) goto not_found
;
1325 GetFileTime( handle
, NULL
, NULL
, &filetime
);
1326 FileTimeToDosDateTime( &filetime
, &filedatetime
[0], &filedatetime
[1] );
1327 if ((mode
& OF_VERIFY
) && (mode
& OF_REOPEN
))
1329 if (memcmp( ofs
->reserved
, filedatetime
, sizeof(ofs
->reserved
) ))
1331 CloseHandle( handle
);
1332 WARN("(%s): OF_VERIFY failed\n", name
);
1333 /* FIXME: what error here? */
1334 SetLastError( ERROR_FILE_NOT_FOUND
);
1338 memcpy( ofs
->reserved
, filedatetime
, sizeof(ofs
->reserved
) );
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
)) 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
);