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( RtlNtStatusToDosError ( 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 %p\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 %p\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("%p\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 * GetFileSizeEx (KERNEL32.@)
1003 BOOL WINAPI
GetFileSizeEx( HANDLE hFile
, PLARGE_INTEGER lpFileSize
)
1005 BY_HANDLE_FILE_INFORMATION info
;
1009 SetLastError( ERROR_INVALID_PARAMETER
);
1013 if (!GetFileInformationByHandle( hFile
, &info
))
1018 lpFileSize
->s
.LowPart
= info
.nFileSizeLow
;
1019 lpFileSize
->s
.HighPart
= info
.nFileSizeHigh
;
1025 /***********************************************************************
1026 * GetFileTime (KERNEL32.@)
1028 BOOL WINAPI
GetFileTime( HANDLE hFile
, FILETIME
*lpCreationTime
,
1029 FILETIME
*lpLastAccessTime
,
1030 FILETIME
*lpLastWriteTime
)
1032 BY_HANDLE_FILE_INFORMATION info
;
1033 if (!GetFileInformationByHandle( hFile
, &info
)) return FALSE
;
1034 if (lpCreationTime
) *lpCreationTime
= info
.ftCreationTime
;
1035 if (lpLastAccessTime
) *lpLastAccessTime
= info
.ftLastAccessTime
;
1036 if (lpLastWriteTime
) *lpLastWriteTime
= info
.ftLastWriteTime
;
1040 /***********************************************************************
1041 * FILE_GetTempFileName : utility for GetTempFileName
1043 static UINT
FILE_GetTempFileName( LPCWSTR path
, LPCWSTR prefix
, UINT unique
,
1046 static UINT unique_temp
;
1047 DOS_FULL_NAME full_name
;
1053 if ( !path
|| !prefix
|| !buffer
)
1055 SetLastError( ERROR_INVALID_PARAMETER
);
1059 if (!unique_temp
) unique_temp
= time(NULL
) & 0xffff;
1060 num
= unique
? (unique
& 0xffff) : (unique_temp
++ & 0xffff);
1062 strcpyW( buffer
, path
);
1063 p
= buffer
+ strlenW(buffer
);
1065 /* add a \, if there isn't one and path is more than just the drive letter ... */
1066 if ( !((strlenW(buffer
) == 2) && (buffer
[1] == ':'))
1067 && ((p
== buffer
) || (p
[-1] != '\\'))) *p
++ = '\\';
1069 for (i
= 3; (i
> 0) && (*prefix
); i
--) *p
++ = *prefix
++;
1071 sprintf( buf
, "%04x.tmp", num
);
1072 MultiByteToWideChar(CP_ACP
, 0, buf
, -1, p
, 20);
1074 /* Now try to create it */
1080 HANDLE handle
= CreateFileW( buffer
, GENERIC_WRITE
, 0, NULL
,
1081 CREATE_NEW
, FILE_ATTRIBUTE_NORMAL
, 0 );
1082 if (handle
!= INVALID_HANDLE_VALUE
)
1083 { /* We created it */
1084 TRACE("created %s\n", debugstr_w(buffer
) );
1085 CloseHandle( handle
);
1088 if (GetLastError() != ERROR_FILE_EXISTS
)
1089 break; /* No need to go on */
1091 sprintf( buf
, "%04x.tmp", num
);
1092 MultiByteToWideChar(CP_ACP
, 0, buf
, -1, p
, 20);
1093 } while (num
!= (unique
& 0xffff));
1096 /* Get the full path name */
1098 if (DOSFS_GetFullName( buffer
, FALSE
, &full_name
))
1101 /* Check if we have write access in the directory */
1102 if ((slash
= strrchr( full_name
.long_name
, '/' ))) *slash
= '\0';
1103 if (access( full_name
.long_name
, W_OK
) == -1)
1104 WARN("returns %s, which doesn't seem to be writeable.\n",
1105 debugstr_w(buffer
) );
1107 TRACE("returning %s\n", debugstr_w(buffer
) );
1108 return unique
? unique
: num
;
1112 /***********************************************************************
1113 * GetTempFileNameA (KERNEL32.@)
1115 UINT WINAPI
GetTempFileNameA( LPCSTR path
, LPCSTR prefix
, UINT unique
,
1118 UNICODE_STRING pathW
, prefixW
;
1119 WCHAR bufferW
[MAX_PATH
];
1122 if ( !path
|| !prefix
|| !buffer
)
1124 SetLastError( ERROR_INVALID_PARAMETER
);
1128 RtlCreateUnicodeStringFromAsciiz(&pathW
, path
);
1129 RtlCreateUnicodeStringFromAsciiz(&prefixW
, prefix
);
1131 ret
= GetTempFileNameW(pathW
.Buffer
, prefixW
.Buffer
, unique
, bufferW
);
1133 WideCharToMultiByte(CP_ACP
, 0, bufferW
, -1, buffer
, MAX_PATH
, NULL
, NULL
);
1135 RtlFreeUnicodeString(&pathW
);
1136 RtlFreeUnicodeString(&prefixW
);
1140 /***********************************************************************
1141 * GetTempFileNameW (KERNEL32.@)
1143 UINT WINAPI
GetTempFileNameW( LPCWSTR path
, LPCWSTR prefix
, UINT unique
,
1146 return FILE_GetTempFileName( path
, prefix
, unique
, buffer
);
1150 /***********************************************************************
1151 * GetTempFileName (KERNEL.97)
1153 UINT16 WINAPI
GetTempFileName16( BYTE drive
, LPCSTR prefix
, UINT16 unique
,
1156 char temppath
[MAX_PATH
];
1157 char *prefix16
= NULL
;
1160 if (!(drive
& ~TF_FORCEDRIVE
)) /* drive 0 means current default drive */
1161 drive
|= DRIVE_GetCurrentDrive() + 'A';
1163 if ((drive
& TF_FORCEDRIVE
) &&
1164 !DRIVE_IsValid( toupper(drive
& ~TF_FORCEDRIVE
) - 'A' ))
1166 drive
&= ~TF_FORCEDRIVE
;
1167 WARN("invalid drive %d specified\n", drive
);
1170 if (drive
& TF_FORCEDRIVE
)
1171 sprintf(temppath
,"%c:", drive
& ~TF_FORCEDRIVE
);
1173 GetTempPathA( MAX_PATH
, temppath
);
1177 prefix16
= HeapAlloc(GetProcessHeap(), 0, strlen(prefix
) + 2);
1179 strcpy(prefix16
+ 1, prefix
);
1182 ret
= GetTempFileNameA( temppath
, prefix16
, unique
, buffer
);
1184 if (prefix16
) HeapFree(GetProcessHeap(), 0, prefix16
);
1188 /***********************************************************************
1191 * Implementation of OpenFile16() and OpenFile32().
1193 static HFILE
FILE_DoOpenFile( LPCSTR name
, OFSTRUCT
*ofs
, UINT mode
,
1199 WORD filedatetime
[2];
1200 DOS_FULL_NAME full_name
;
1201 DWORD access
, sharing
;
1203 WCHAR buffer
[MAX_PATH
];
1206 if (!ofs
) return HFILE_ERROR
;
1208 TRACE("%s %s %s %s%s%s%s%s%s%s%s%s\n",name
,
1209 ((mode
& 0x3 )==OF_READ
)?"OF_READ":
1210 ((mode
& 0x3 )==OF_WRITE
)?"OF_WRITE":
1211 ((mode
& 0x3 )==OF_READWRITE
)?"OF_READWRITE":"unknown",
1212 ((mode
& 0x70 )==OF_SHARE_COMPAT
)?"OF_SHARE_COMPAT":
1213 ((mode
& 0x70 )==OF_SHARE_DENY_NONE
)?"OF_SHARE_DENY_NONE":
1214 ((mode
& 0x70 )==OF_SHARE_DENY_READ
)?"OF_SHARE_DENY_READ":
1215 ((mode
& 0x70 )==OF_SHARE_DENY_WRITE
)?"OF_SHARE_DENY_WRITE":
1216 ((mode
& 0x70 )==OF_SHARE_EXCLUSIVE
)?"OF_SHARE_EXCLUSIVE":"unknown",
1217 ((mode
& OF_PARSE
)==OF_PARSE
)?"OF_PARSE ":"",
1218 ((mode
& OF_DELETE
)==OF_DELETE
)?"OF_DELETE ":"",
1219 ((mode
& OF_VERIFY
)==OF_VERIFY
)?"OF_VERIFY ":"",
1220 ((mode
& OF_SEARCH
)==OF_SEARCH
)?"OF_SEARCH ":"",
1221 ((mode
& OF_CANCEL
)==OF_CANCEL
)?"OF_CANCEL ":"",
1222 ((mode
& OF_CREATE
)==OF_CREATE
)?"OF_CREATE ":"",
1223 ((mode
& OF_PROMPT
)==OF_PROMPT
)?"OF_PROMPT ":"",
1224 ((mode
& OF_EXIST
)==OF_EXIST
)?"OF_EXIST ":"",
1225 ((mode
& OF_REOPEN
)==OF_REOPEN
)?"OF_REOPEN ":""
1229 ofs
->cBytes
= sizeof(OFSTRUCT
);
1231 if (mode
& OF_REOPEN
) name
= ofs
->szPathName
;
1234 ERR("called with `name' set to NULL ! Please debug.\n");
1238 TRACE("%s %04x\n", name
, mode
);
1240 /* the watcom 10.6 IDE relies on a valid path returned in ofs->szPathName
1241 Are there any cases where getting the path here is wrong?
1242 Uwe Bonnes 1997 Apr 2 */
1243 if (!GetFullPathNameA( name
, sizeof(ofs
->szPathName
),
1244 ofs
->szPathName
, NULL
)) goto error
;
1245 FILE_ConvertOFMode( mode
, &access
, &sharing
);
1247 /* OF_PARSE simply fills the structure */
1249 if (mode
& OF_PARSE
)
1251 ofs
->fFixedDisk
= (GetDriveType16( ofs
->szPathName
[0]-'A' )
1252 != DRIVE_REMOVABLE
);
1253 TRACE("(%s): OF_PARSE, res = '%s'\n",
1254 name
, ofs
->szPathName
);
1258 /* OF_CREATE is completely different from all other options, so
1261 if (mode
& OF_CREATE
)
1263 if ((handle
= CreateFileA( name
, GENERIC_READ
| GENERIC_WRITE
,
1264 sharing
, NULL
, CREATE_ALWAYS
,
1265 FILE_ATTRIBUTE_NORMAL
, 0 ))== INVALID_HANDLE_VALUE
)
1270 MultiByteToWideChar(CP_ACP
, 0, name
, -1, buffer
, MAX_PATH
);
1273 /* If OF_SEARCH is set, ignore the given path */
1275 if ((mode
& OF_SEARCH
) && !(mode
& OF_REOPEN
))
1277 /* First try the file name as is */
1278 if (DOSFS_GetFullName( nameW
, TRUE
, &full_name
)) goto found
;
1279 /* Now remove the path */
1280 if (nameW
[0] && (nameW
[1] == ':')) nameW
+= 2;
1281 if ((p
= strrchrW( nameW
, '\\' ))) nameW
= p
+ 1;
1282 if ((p
= strrchrW( nameW
, '/' ))) nameW
= p
+ 1;
1283 if (!nameW
[0]) goto not_found
;
1286 /* Now look for the file */
1288 if (!DIR_SearchPath( NULL
, nameW
, NULL
, &full_name
, win32
)) goto not_found
;
1291 TRACE("found %s = %s\n",
1292 full_name
.long_name
, debugstr_w(full_name
.short_name
) );
1293 WideCharToMultiByte(CP_ACP
, 0, full_name
.short_name
, -1,
1294 ofs
->szPathName
, sizeof(ofs
->szPathName
), NULL
, NULL
);
1296 if (mode
& OF_SHARE_EXCLUSIVE
)
1297 /* Some InstallShield version uses OF_SHARE_EXCLUSIVE
1298 on the file <tempdir>/_ins0432._mp to determine how
1299 far installation has proceeded.
1300 _ins0432._mp is an executable and while running the
1301 application expects the open with OF_SHARE_ to fail*/
1303 As our loader closes the files after loading the executable,
1304 we can't find the running executable with FILE_InUse.
1305 The loader should keep the file open, as Windows does that, too.
1308 char *last
= strrchr(full_name
.long_name
,'/');
1310 last
= full_name
.long_name
- 1;
1311 if (GetModuleHandle16(last
+1))
1313 TRACE("Denying shared open for %s\n",full_name
.long_name
);
1318 if (mode
& OF_DELETE
)
1320 if (unlink( full_name
.long_name
) == -1) goto not_found
;
1321 TRACE("(%s): OF_DELETE return = OK\n", name
);
1325 handle
= FILE_CreateFile( full_name
.long_name
, access
, sharing
,
1326 NULL
, OPEN_EXISTING
, 0, 0,
1327 DRIVE_GetFlags(full_name
.drive
) & DRIVE_FAIL_READ_ONLY
,
1328 GetDriveTypeW( full_name
.short_name
) );
1329 if (!handle
) goto not_found
;
1331 GetFileTime( handle
, NULL
, NULL
, &filetime
);
1332 FileTimeToDosDateTime( &filetime
, &filedatetime
[0], &filedatetime
[1] );
1333 if ((mode
& OF_VERIFY
) && (mode
& OF_REOPEN
))
1335 if (ofs
->Reserved1
!= filedatetime
[0] || ofs
->Reserved2
!= filedatetime
[1] )
1337 CloseHandle( handle
);
1338 WARN("(%s): OF_VERIFY failed\n", name
);
1339 /* FIXME: what error here? */
1340 SetLastError( ERROR_FILE_NOT_FOUND
);
1344 ofs
->Reserved1
= filedatetime
[0];
1345 ofs
->Reserved2
= filedatetime
[1];
1347 success
: /* We get here if the open was successful */
1348 TRACE("(%s): OK, return = %p\n", name
, handle
);
1351 hFileRet
= (HFILE
)handle
;
1352 if (mode
& OF_EXIST
) /* Return the handle, but close it first */
1353 CloseHandle( handle
);
1357 hFileRet
= Win32HandleToDosFileHandle( handle
);
1358 if (hFileRet
== HFILE_ERROR16
) goto error
;
1359 if (mode
& OF_EXIST
) /* Return the handle, but close it first */
1360 _lclose16( hFileRet
);
1364 not_found
: /* We get here if the file does not exist */
1365 WARN("'%s' not found or sharing violation\n", name
);
1366 SetLastError( ERROR_FILE_NOT_FOUND
);
1369 error
: /* We get here if there was an error opening the file */
1370 ofs
->nErrCode
= GetLastError();
1371 WARN("(%s): return = HFILE_ERROR error= %d\n",
1372 name
,ofs
->nErrCode
);
1377 /***********************************************************************
1378 * OpenFile (KERNEL.74)
1379 * OpenFileEx (KERNEL.360)
1381 HFILE16 WINAPI
OpenFile16( LPCSTR name
, OFSTRUCT
*ofs
, UINT16 mode
)
1383 return FILE_DoOpenFile( name
, ofs
, mode
, FALSE
);
1387 /***********************************************************************
1388 * OpenFile (KERNEL32.@)
1390 HFILE WINAPI
OpenFile( LPCSTR name
, OFSTRUCT
*ofs
, UINT mode
)
1392 return FILE_DoOpenFile( name
, ofs
, mode
, TRUE
);
1396 /***********************************************************************
1397 * FILE_InitProcessDosHandles
1399 * Allocates the default DOS handles for a process. Called either by
1400 * Win32HandleToDosFileHandle below or by the DOSVM stuff.
1402 static void FILE_InitProcessDosHandles( void )
1404 HANDLE cp
= GetCurrentProcess();
1405 DuplicateHandle(cp
, GetStdHandle(STD_INPUT_HANDLE
), cp
, &dos_handles
[0],
1406 0, TRUE
, DUPLICATE_SAME_ACCESS
);
1407 DuplicateHandle(cp
, GetStdHandle(STD_OUTPUT_HANDLE
), cp
, &dos_handles
[1],
1408 0, TRUE
, DUPLICATE_SAME_ACCESS
);
1409 DuplicateHandle(cp
, GetStdHandle(STD_ERROR_HANDLE
), cp
, &dos_handles
[2],
1410 0, TRUE
, DUPLICATE_SAME_ACCESS
);
1411 DuplicateHandle(cp
, GetStdHandle(STD_ERROR_HANDLE
), cp
, &dos_handles
[3],
1412 0, TRUE
, DUPLICATE_SAME_ACCESS
);
1413 DuplicateHandle(cp
, GetStdHandle(STD_ERROR_HANDLE
), cp
, &dos_handles
[4],
1414 0, TRUE
, DUPLICATE_SAME_ACCESS
);
1417 /***********************************************************************
1418 * Win32HandleToDosFileHandle (KERNEL32.21)
1420 * Allocate a DOS handle for a Win32 handle. The Win32 handle is no
1421 * longer valid after this function (even on failure).
1423 * Note: this is not exactly right, since on Win95 the Win32 handles
1424 * are on top of DOS handles and we do it the other way
1425 * around. Should be good enough though.
1427 HFILE WINAPI
Win32HandleToDosFileHandle( HANDLE handle
)
1431 if (!handle
|| (handle
== INVALID_HANDLE_VALUE
))
1434 for (i
= 5; i
< DOS_TABLE_SIZE
; i
++)
1435 if (!dos_handles
[i
])
1437 dos_handles
[i
] = handle
;
1438 TRACE("Got %d for h32 %p\n", i
, handle
);
1441 CloseHandle( handle
);
1442 SetLastError( ERROR_TOO_MANY_OPEN_FILES
);
1447 /***********************************************************************
1448 * DosFileHandleToWin32Handle (KERNEL32.20)
1450 * Return the Win32 handle for a DOS handle.
1452 * Note: this is not exactly right, since on Win95 the Win32 handles
1453 * are on top of DOS handles and we do it the other way
1454 * around. Should be good enough though.
1456 HANDLE WINAPI
DosFileHandleToWin32Handle( HFILE handle
)
1458 HFILE16 hfile
= (HFILE16
)handle
;
1459 if (hfile
< 5 && !dos_handles
[hfile
]) FILE_InitProcessDosHandles();
1460 if ((hfile
>= DOS_TABLE_SIZE
) || !dos_handles
[hfile
])
1462 SetLastError( ERROR_INVALID_HANDLE
);
1463 return INVALID_HANDLE_VALUE
;
1465 return dos_handles
[hfile
];
1469 /***********************************************************************
1470 * DisposeLZ32Handle (KERNEL32.22)
1472 * Note: this is not entirely correct, we should only close the
1473 * 32-bit handle and not the 16-bit one, but we cannot do
1474 * this because of the way our DOS handles are implemented.
1475 * It shouldn't break anything though.
1477 void WINAPI
DisposeLZ32Handle( HANDLE handle
)
1481 if (!handle
|| (handle
== INVALID_HANDLE_VALUE
)) return;
1483 for (i
= 5; i
< DOS_TABLE_SIZE
; i
++)
1484 if (dos_handles
[i
] == handle
)
1487 CloseHandle( handle
);
1493 /***********************************************************************
1496 * dup2() function for DOS handles.
1498 HFILE16
FILE_Dup2( HFILE16 hFile1
, HFILE16 hFile2
)
1502 if (hFile1
< 5 && !dos_handles
[hFile1
]) FILE_InitProcessDosHandles();
1504 if ((hFile1
>= DOS_TABLE_SIZE
) || (hFile2
>= DOS_TABLE_SIZE
) || !dos_handles
[hFile1
])
1506 SetLastError( ERROR_INVALID_HANDLE
);
1507 return HFILE_ERROR16
;
1509 if (!DuplicateHandle( GetCurrentProcess(), dos_handles
[hFile1
],
1510 GetCurrentProcess(), &new_handle
,
1511 0, FALSE
, DUPLICATE_SAME_ACCESS
))
1512 return HFILE_ERROR16
;
1513 if (dos_handles
[hFile2
]) CloseHandle( dos_handles
[hFile2
] );
1514 dos_handles
[hFile2
] = new_handle
;
1519 /***********************************************************************
1520 * _lclose (KERNEL.81)
1522 HFILE16 WINAPI
_lclose16( HFILE16 hFile
)
1524 if ((hFile
>= DOS_TABLE_SIZE
) || !dos_handles
[hFile
])
1526 SetLastError( ERROR_INVALID_HANDLE
);
1527 return HFILE_ERROR16
;
1529 TRACE("%d (handle32=%p)\n", hFile
, dos_handles
[hFile
] );
1530 CloseHandle( dos_handles
[hFile
] );
1531 dos_handles
[hFile
] = 0;
1536 /***********************************************************************
1537 * _lclose (KERNEL32.@)
1539 HFILE WINAPI
_lclose( HFILE hFile
)
1541 TRACE("handle %d\n", hFile
);
1542 return CloseHandle( (HANDLE
)hFile
) ? 0 : HFILE_ERROR
;
1545 /***********************************************************************
1546 * GetOverlappedResult (KERNEL32.@)
1548 * Check the result of an Asynchronous data transfer from a file.
1554 * If successful (and relevant) lpTransferred will hold the number of
1555 * bytes transferred during the async operation.
1559 * Currently only works for WaitCommEvent, ReadFile, WriteFile
1560 * with communications ports.
1563 BOOL WINAPI
GetOverlappedResult(
1564 HANDLE hFile
, /* [in] handle of file to check on */
1565 LPOVERLAPPED lpOverlapped
, /* [in/out] pointer to overlapped */
1566 LPDWORD lpTransferred
, /* [in/out] number of bytes transferred */
1567 BOOL bWait
/* [in] wait for the transfer to complete ? */
1571 TRACE("(%p %p %p %x)\n", hFile
, lpOverlapped
, lpTransferred
, bWait
);
1573 if(lpOverlapped
==NULL
)
1575 ERR("lpOverlapped was null\n");
1578 if(!lpOverlapped
->hEvent
)
1580 ERR("lpOverlapped->hEvent was null\n");
1587 TRACE("waiting on %p\n",lpOverlapped
);
1588 r
= WaitForSingleObjectEx(lpOverlapped
->hEvent
, INFINITE
, TRUE
);
1589 TRACE("wait on %p returned %ld\n",lpOverlapped
,r
);
1590 } while (r
==STATUS_USER_APC
);
1592 else if ( lpOverlapped
->Internal
== STATUS_PENDING
)
1594 /* Wait in order to give APCs a chance to run. */
1595 /* This is cheating, so we must set the event again in case of success -
1596 it may be a non-manual reset event. */
1598 TRACE("waiting on %p\n",lpOverlapped
);
1599 r
= WaitForSingleObjectEx(lpOverlapped
->hEvent
, 0, TRUE
);
1600 TRACE("wait on %p returned %ld\n",lpOverlapped
,r
);
1601 } while (r
==STATUS_USER_APC
);
1602 if ( r
== WAIT_OBJECT_0
)
1603 NtSetEvent ( lpOverlapped
->hEvent
, NULL
);
1607 *lpTransferred
= lpOverlapped
->InternalHigh
;
1609 switch ( lpOverlapped
->Internal
)
1611 case STATUS_SUCCESS
:
1613 case STATUS_PENDING
:
1614 SetLastError ( ERROR_IO_INCOMPLETE
);
1615 if ( bWait
) ERR ("PENDING status after waiting!\n");
1618 SetLastError ( RtlNtStatusToDosError ( lpOverlapped
->Internal
) );
1623 /***********************************************************************
1624 * CancelIo (KERNEL32.@)
1626 BOOL WINAPI
CancelIo(HANDLE handle
)
1628 async_private
*ovp
,*t
;
1630 TRACE("handle = %p\n",handle
);
1632 for (ovp
= NtCurrentTeb()->pending_list
; ovp
; ovp
= t
)
1635 if ( ovp
->handle
== handle
)
1636 cancel_async ( ovp
);
1638 WaitForMultipleObjectsEx(0,NULL
,FALSE
,1,TRUE
);
1642 /***********************************************************************
1643 * FILE_AsyncReadService (INTERNAL)
1645 * This function is called while the client is waiting on the
1646 * server, so we can't make any server calls here.
1648 static void FILE_AsyncReadService(async_private
*ovp
)
1650 async_fileio
*fileio
= (async_fileio
*) ovp
;
1651 LPOVERLAPPED lpOverlapped
= fileio
->lpOverlapped
;
1653 int already
= lpOverlapped
->InternalHigh
;
1655 TRACE("%p %p\n", lpOverlapped
, fileio
->buffer
);
1657 /* check to see if the data is ready (non-blocking) */
1659 if ( fileio
->fd_type
== FD_TYPE_SOCKET
)
1660 result
= read (ovp
->fd
, &fileio
->buffer
[already
], fileio
->count
- already
);
1663 result
= pread (ovp
->fd
, &fileio
->buffer
[already
], fileio
->count
- already
,
1664 OVERLAPPED_OFFSET (lpOverlapped
) + already
);
1665 if ((result
< 0) && (errno
== ESPIPE
))
1666 result
= read (ovp
->fd
, &fileio
->buffer
[already
], fileio
->count
- already
);
1669 if ( (result
<0) && ((errno
== EAGAIN
) || (errno
== EINTR
)))
1671 TRACE("Deferred read %d\n",errno
);
1676 /* check to see if the transfer is complete */
1679 r
= FILE_GetNtStatus ();
1682 else if ( result
== 0 )
1684 r
= ( lpOverlapped
->InternalHigh
? STATUS_SUCCESS
: STATUS_END_OF_FILE
);
1688 lpOverlapped
->InternalHigh
+= result
;
1689 TRACE("read %d more bytes %ld/%d so far\n",result
,lpOverlapped
->InternalHigh
,fileio
->count
);
1691 if(lpOverlapped
->InternalHigh
>= fileio
->count
|| fileio
->fd_type
== FD_TYPE_SOCKET
)
1697 lpOverlapped
->Internal
= r
;
1700 /***********************************************************************
1701 * FILE_ReadFileEx (INTERNAL)
1703 static BOOL
FILE_ReadFileEx(HANDLE hFile
, LPVOID buffer
, DWORD bytesToRead
,
1704 LPOVERLAPPED overlapped
,
1705 LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine
,
1713 TRACE("file %p to buf %p num %ld %p func %p\n",
1714 hFile
, buffer
, bytesToRead
, overlapped
, lpCompletionRoutine
);
1716 /* check that there is an overlapped struct */
1717 if (overlapped
==NULL
)
1719 SetLastError(ERROR_INVALID_PARAMETER
);
1723 fd
= FILE_GetUnixHandleType ( hFile
, GENERIC_READ
, &type
, &flags
);
1726 WARN ( "Couldn't get FD\n" );
1730 ovp
= (async_fileio
*) HeapAlloc(GetProcessHeap(), 0, sizeof (async_fileio
));
1733 TRACE("HeapAlloc Failed\n");
1734 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
1738 ovp
->async
.ops
= ( lpCompletionRoutine
? &fileio_async_ops
: &fileio_nocomp_async_ops
);
1739 ovp
->async
.handle
= hFile
;
1741 ovp
->async
.type
= ASYNC_TYPE_READ
;
1742 ovp
->async
.func
= FILE_AsyncReadService
;
1743 ovp
->async
.event
= hEvent
;
1744 ovp
->lpOverlapped
= overlapped
;
1745 ovp
->count
= bytesToRead
;
1746 ovp
->completion_func
= lpCompletionRoutine
;
1747 ovp
->buffer
= buffer
;
1748 ovp
->fd_type
= type
;
1750 return !register_new_async (&ovp
->async
);
1758 /***********************************************************************
1759 * ReadFileEx (KERNEL32.@)
1761 BOOL WINAPI
ReadFileEx(HANDLE hFile
, LPVOID buffer
, DWORD bytesToRead
,
1762 LPOVERLAPPED overlapped
,
1763 LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine
)
1765 overlapped
->InternalHigh
= 0;
1766 return FILE_ReadFileEx(hFile
,buffer
,bytesToRead
,overlapped
,lpCompletionRoutine
, INVALID_HANDLE_VALUE
);
1769 static BOOL
FILE_TimeoutRead(HANDLE hFile
, LPVOID buffer
, DWORD bytesToRead
, LPDWORD bytesRead
)
1774 TRACE("%p %p %ld %p\n", hFile
, buffer
, bytesToRead
, bytesRead
);
1776 ZeroMemory(&ov
, sizeof (OVERLAPPED
));
1777 if(STATUS_SUCCESS
==NtCreateEvent(&ov
.hEvent
, SYNCHRONIZE
, NULL
, 0, 0))
1779 if(FILE_ReadFileEx(hFile
, buffer
, bytesToRead
, &ov
, NULL
, ov
.hEvent
))
1781 r
= GetOverlappedResult(hFile
, &ov
, bytesRead
, TRUE
);
1784 CloseHandle(ov
.hEvent
);
1788 /***********************************************************************
1789 * ReadFile (KERNEL32.@)
1791 BOOL WINAPI
ReadFile( HANDLE hFile
, LPVOID buffer
, DWORD bytesToRead
,
1792 LPDWORD bytesRead
, LPOVERLAPPED overlapped
)
1794 int unix_handle
, result
, flags
;
1797 TRACE("%p %p %ld %p %p\n", hFile
, buffer
, bytesToRead
,
1798 bytesRead
, overlapped
);
1800 if (bytesRead
) *bytesRead
= 0; /* Do this before anything else */
1801 if (!bytesToRead
) return TRUE
;
1803 unix_handle
= FILE_GetUnixHandleType( hFile
, GENERIC_READ
, &type
, &flags
);
1805 if (flags
& FD_FLAG_OVERLAPPED
)
1807 if (unix_handle
== -1) return FALSE
;
1808 if ( (overlapped
==NULL
) || NtResetEvent( overlapped
->hEvent
, NULL
) )
1810 TRACE("Overlapped not specified or invalid event flag\n");
1812 SetLastError(ERROR_INVALID_PARAMETER
);
1817 overlapped
->InternalHigh
= 0;
1819 if(!FILE_ReadFileEx(hFile
, buffer
, bytesToRead
, overlapped
, NULL
, overlapped
->hEvent
))
1822 if ( !GetOverlappedResult (hFile
, overlapped
, bytesRead
, FALSE
) )
1824 if ( GetLastError() == ERROR_IO_INCOMPLETE
)
1825 SetLastError ( ERROR_IO_PENDING
);
1831 if (flags
& FD_FLAG_TIMEOUT
)
1834 return FILE_TimeoutRead(hFile
, buffer
, bytesToRead
, bytesRead
);
1839 return SMB_ReadFile(hFile
, buffer
, bytesToRead
, bytesRead
, NULL
);
1841 case FD_TYPE_CONSOLE
:
1842 return FILE_ReadConsole(hFile
, buffer
, bytesToRead
, bytesRead
, NULL
);
1844 case FD_TYPE_DEFAULT
:
1845 /* normal unix files */
1846 if (unix_handle
== -1) return FALSE
;
1849 DWORD highOffset
= overlapped
->OffsetHigh
;
1850 if ( (INVALID_SET_FILE_POINTER
== SetFilePointer(hFile
, overlapped
->Offset
,
1851 &highOffset
, FILE_BEGIN
)) &&
1852 (GetLastError() != NO_ERROR
) )
1861 if (unix_handle
== -1)
1867 off_t offset
= OVERLAPPED_OFFSET(overlapped
);
1868 if(lseek(unix_handle
, offset
, SEEK_SET
) == -1)
1871 SetLastError(ERROR_INVALID_PARAMETER
);
1876 /* code for synchronous reads */
1877 while ((result
= read( unix_handle
, buffer
, bytesToRead
)) == -1)
1879 if ((errno
== EAGAIN
) || (errno
== EINTR
)) continue;
1880 if ((errno
== EFAULT
) && !IsBadWritePtr( buffer
, bytesToRead
)) continue;
1884 close( unix_handle
);
1885 if (result
== -1) return FALSE
;
1886 if (bytesRead
) *bytesRead
= result
;
1891 /***********************************************************************
1892 * FILE_AsyncWriteService (INTERNAL)
1894 * This function is called while the client is waiting on the
1895 * server, so we can't make any server calls here.
1897 static void FILE_AsyncWriteService(struct async_private
*ovp
)
1899 async_fileio
*fileio
= (async_fileio
*) ovp
;
1900 LPOVERLAPPED lpOverlapped
= fileio
->lpOverlapped
;
1902 int already
= lpOverlapped
->InternalHigh
;
1904 TRACE("(%p %p)\n",lpOverlapped
,fileio
->buffer
);
1906 /* write some data (non-blocking) */
1908 if ( fileio
->fd_type
== FD_TYPE_SOCKET
)
1909 result
= write(ovp
->fd
, &fileio
->buffer
[already
], fileio
->count
- already
);
1912 result
= pwrite(ovp
->fd
, &fileio
->buffer
[already
], fileio
->count
- already
,
1913 OVERLAPPED_OFFSET (lpOverlapped
) + already
);
1914 if ((result
< 0) && (errno
== ESPIPE
))
1915 result
= write(ovp
->fd
, &fileio
->buffer
[already
], fileio
->count
- already
);
1918 if ( (result
<0) && ((errno
== EAGAIN
) || (errno
== EINTR
)))
1924 /* check to see if the transfer is complete */
1927 r
= FILE_GetNtStatus ();
1931 lpOverlapped
->InternalHigh
+= result
;
1933 TRACE("wrote %d more bytes %ld/%d so far\n",result
,lpOverlapped
->InternalHigh
,fileio
->count
);
1935 if(lpOverlapped
->InternalHigh
< fileio
->count
)
1941 lpOverlapped
->Internal
= r
;
1944 /***********************************************************************
1947 static BOOL
FILE_WriteFileEx(HANDLE hFile
, LPCVOID buffer
, DWORD bytesToWrite
,
1948 LPOVERLAPPED overlapped
,
1949 LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine
,
1957 TRACE("file %p to buf %p num %ld %p func %p handle %p\n",
1958 hFile
, buffer
, bytesToWrite
, overlapped
, lpCompletionRoutine
, hEvent
);
1960 if (overlapped
== NULL
)
1962 SetLastError(ERROR_INVALID_PARAMETER
);
1966 fd
= FILE_GetUnixHandleType ( hFile
, GENERIC_WRITE
, &type
, &flags
);
1969 TRACE( "Couldn't get FD\n" );
1973 ovp
= (async_fileio
*) HeapAlloc(GetProcessHeap(), 0, sizeof (async_fileio
));
1976 TRACE("HeapAlloc Failed\n");
1977 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
1981 ovp
->async
.ops
= ( lpCompletionRoutine
? &fileio_async_ops
: &fileio_nocomp_async_ops
);
1982 ovp
->async
.handle
= hFile
;
1984 ovp
->async
.type
= ASYNC_TYPE_WRITE
;
1985 ovp
->async
.func
= FILE_AsyncWriteService
;
1986 ovp
->lpOverlapped
= overlapped
;
1987 ovp
->async
.event
= hEvent
;
1988 ovp
->buffer
= (LPVOID
) buffer
;
1989 ovp
->count
= bytesToWrite
;
1990 ovp
->completion_func
= lpCompletionRoutine
;
1991 ovp
->fd_type
= type
;
1993 return !register_new_async (&ovp
->async
);
2000 /***********************************************************************
2001 * WriteFileEx (KERNEL32.@)
2003 BOOL WINAPI
WriteFileEx(HANDLE hFile
, LPCVOID buffer
, DWORD bytesToWrite
,
2004 LPOVERLAPPED overlapped
,
2005 LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine
)
2007 overlapped
->InternalHigh
= 0;
2009 return FILE_WriteFileEx(hFile
, buffer
, bytesToWrite
, overlapped
, lpCompletionRoutine
, INVALID_HANDLE_VALUE
);
2012 /***********************************************************************
2013 * WriteFile (KERNEL32.@)
2015 BOOL WINAPI
WriteFile( HANDLE hFile
, LPCVOID buffer
, DWORD bytesToWrite
,
2016 LPDWORD bytesWritten
, LPOVERLAPPED overlapped
)
2018 int unix_handle
, result
, flags
;
2021 TRACE("%p %p %ld %p %p\n", hFile
, buffer
, bytesToWrite
,
2022 bytesWritten
, overlapped
);
2024 if (bytesWritten
) *bytesWritten
= 0; /* Do this before anything else */
2025 if (!bytesToWrite
) return TRUE
;
2027 unix_handle
= FILE_GetUnixHandleType( hFile
, GENERIC_WRITE
, &type
, &flags
);
2029 if (flags
& FD_FLAG_OVERLAPPED
)
2031 if (unix_handle
== -1) return FALSE
;
2032 if ( (overlapped
==NULL
) || NtResetEvent( overlapped
->hEvent
, NULL
) )
2034 TRACE("Overlapped not specified or invalid event flag\n");
2036 SetLastError(ERROR_INVALID_PARAMETER
);
2041 overlapped
->InternalHigh
= 0;
2043 if(!FILE_WriteFileEx(hFile
, buffer
, bytesToWrite
, overlapped
, NULL
, overlapped
->hEvent
))
2046 if ( !GetOverlappedResult (hFile
, overlapped
, bytesWritten
, FALSE
) )
2048 if ( GetLastError() == ERROR_IO_INCOMPLETE
)
2049 SetLastError ( ERROR_IO_PENDING
);
2058 case FD_TYPE_CONSOLE
:
2059 TRACE("%p %s %ld %p %p\n", hFile
, debugstr_an(buffer
, bytesToWrite
), bytesToWrite
,
2060 bytesWritten
, overlapped
);
2061 return FILE_WriteConsole(hFile
, buffer
, bytesToWrite
, bytesWritten
, NULL
);
2063 case FD_TYPE_DEFAULT
:
2064 if (unix_handle
== -1) return FALSE
;
2068 DWORD highOffset
= overlapped
->OffsetHigh
;
2069 if ( (INVALID_SET_FILE_POINTER
== SetFilePointer(hFile
, overlapped
->Offset
,
2070 &highOffset
, FILE_BEGIN
)) &&
2071 (GetLastError() != NO_ERROR
) )
2080 if (unix_handle
== -1)
2085 SetLastError(ERROR_INVALID_PARAMETER
);
2093 off_t offset
= OVERLAPPED_OFFSET(overlapped
);
2094 if(lseek(unix_handle
, offset
, SEEK_SET
) == -1)
2097 SetLastError(ERROR_INVALID_PARAMETER
);
2102 /* synchronous file write */
2103 while ((result
= write( unix_handle
, buffer
, bytesToWrite
)) == -1)
2105 if ((errno
== EAGAIN
) || (errno
== EINTR
)) continue;
2106 if ((errno
== EFAULT
) && !IsBadReadPtr( buffer
, bytesToWrite
)) continue;
2107 if (errno
== ENOSPC
)
2108 SetLastError( ERROR_DISK_FULL
);
2113 close( unix_handle
);
2114 if (result
== -1) return FALSE
;
2115 if (bytesWritten
) *bytesWritten
= result
;
2120 /***********************************************************************
2121 * _hread (KERNEL.349)
2123 LONG WINAPI
WIN16_hread( HFILE16 hFile
, SEGPTR buffer
, LONG count
)
2127 TRACE("%d %08lx %ld\n",
2128 hFile
, (DWORD
)buffer
, count
);
2130 /* Some programs pass a count larger than the allocated buffer */
2131 maxlen
= GetSelectorLimit16( SELECTOROF(buffer
) ) - OFFSETOF(buffer
) + 1;
2132 if (count
> maxlen
) count
= maxlen
;
2133 return _lread((HFILE
)DosFileHandleToWin32Handle(hFile
), MapSL(buffer
), count
);
2137 /***********************************************************************
2138 * _lread (KERNEL.82)
2140 UINT16 WINAPI
WIN16_lread( HFILE16 hFile
, SEGPTR buffer
, UINT16 count
)
2142 return (UINT16
)WIN16_hread( hFile
, buffer
, (LONG
)count
);
2146 /***********************************************************************
2147 * _lread (KERNEL32.@)
2149 UINT WINAPI
_lread( HFILE handle
, LPVOID buffer
, UINT count
)
2152 if (!ReadFile( (HANDLE
)handle
, buffer
, count
, &result
, NULL
)) return -1;
2157 /***********************************************************************
2158 * _lread16 (KERNEL.82)
2160 UINT16 WINAPI
_lread16( HFILE16 hFile
, LPVOID buffer
, UINT16 count
)
2162 return (UINT16
)_lread((HFILE
)DosFileHandleToWin32Handle(hFile
), buffer
, (LONG
)count
);
2166 /***********************************************************************
2167 * _lcreat (KERNEL.83)
2169 HFILE16 WINAPI
_lcreat16( LPCSTR path
, INT16 attr
)
2171 return Win32HandleToDosFileHandle( (HANDLE
)_lcreat( path
, attr
) );
2175 /***********************************************************************
2176 * _lcreat (KERNEL32.@)
2178 HFILE WINAPI
_lcreat( LPCSTR path
, INT attr
)
2180 /* Mask off all flags not explicitly allowed by the doc */
2181 attr
&= FILE_ATTRIBUTE_READONLY
| FILE_ATTRIBUTE_HIDDEN
| FILE_ATTRIBUTE_SYSTEM
;
2182 TRACE("%s %02x\n", path
, attr
);
2183 return (HFILE
)CreateFileA( path
, GENERIC_READ
| GENERIC_WRITE
,
2184 FILE_SHARE_READ
| FILE_SHARE_WRITE
, NULL
,
2185 CREATE_ALWAYS
, attr
, 0 );
2189 /***********************************************************************
2190 * SetFilePointer (KERNEL32.@)
2192 DWORD WINAPI
SetFilePointer( HANDLE hFile
, LONG distance
, LONG
*highword
,
2195 DWORD ret
= INVALID_SET_FILE_POINTER
;
2197 TRACE("handle %p offset %ld high %ld origin %ld\n",
2198 hFile
, distance
, highword
?*highword
:0, method
);
2200 SERVER_START_REQ( set_file_pointer
)
2202 req
->handle
= hFile
;
2203 req
->low
= distance
;
2204 req
->high
= highword
? *highword
: (distance
>= 0) ? 0 : -1;
2205 /* FIXME: assumes 1:1 mapping between Windows and Unix seek constants */
2206 req
->whence
= method
;
2208 if (!wine_server_call_err( req
))
2210 ret
= reply
->new_low
;
2211 if (highword
) *highword
= reply
->new_high
;
2219 /***********************************************************************
2220 * _llseek (KERNEL.84)
2223 * Seeking before the start of the file should be allowed for _llseek16,
2224 * but cause subsequent I/O operations to fail (cf. interrupt list)
2227 LONG WINAPI
_llseek16( HFILE16 hFile
, LONG lOffset
, INT16 nOrigin
)
2229 return SetFilePointer( DosFileHandleToWin32Handle(hFile
), lOffset
, NULL
, nOrigin
);
2233 /***********************************************************************
2234 * _llseek (KERNEL32.@)
2236 LONG WINAPI
_llseek( HFILE hFile
, LONG lOffset
, INT nOrigin
)
2238 return SetFilePointer( (HANDLE
)hFile
, lOffset
, NULL
, nOrigin
);
2242 /***********************************************************************
2243 * _lopen (KERNEL.85)
2245 HFILE16 WINAPI
_lopen16( LPCSTR path
, INT16 mode
)
2247 return Win32HandleToDosFileHandle( (HANDLE
)_lopen( path
, mode
) );
2251 /***********************************************************************
2252 * _lopen (KERNEL32.@)
2254 HFILE WINAPI
_lopen( LPCSTR path
, INT mode
)
2256 DWORD access
, sharing
;
2258 TRACE("('%s',%04x)\n", path
, mode
);
2259 FILE_ConvertOFMode( mode
, &access
, &sharing
);
2260 return (HFILE
)CreateFileA( path
, access
, sharing
, NULL
, OPEN_EXISTING
, 0, 0 );
2264 /***********************************************************************
2265 * _lwrite (KERNEL.86)
2267 UINT16 WINAPI
_lwrite16( HFILE16 hFile
, LPCSTR buffer
, UINT16 count
)
2269 return (UINT16
)_hwrite( (HFILE
)DosFileHandleToWin32Handle(hFile
), buffer
, (LONG
)count
);
2272 /***********************************************************************
2273 * _lwrite (KERNEL32.@)
2275 UINT WINAPI
_lwrite( HFILE hFile
, LPCSTR buffer
, UINT count
)
2277 return (UINT
)_hwrite( hFile
, buffer
, (LONG
)count
);
2281 /***********************************************************************
2282 * _hread16 (KERNEL.349)
2284 LONG WINAPI
_hread16( HFILE16 hFile
, LPVOID buffer
, LONG count
)
2286 return _lread( (HFILE
)DosFileHandleToWin32Handle(hFile
), buffer
, count
);
2290 /***********************************************************************
2291 * _hread (KERNEL32.@)
2293 LONG WINAPI
_hread( HFILE hFile
, LPVOID buffer
, LONG count
)
2295 return _lread( hFile
, buffer
, count
);
2299 /***********************************************************************
2300 * _hwrite (KERNEL.350)
2302 LONG WINAPI
_hwrite16( HFILE16 hFile
, LPCSTR buffer
, LONG count
)
2304 return _hwrite( (HFILE
)DosFileHandleToWin32Handle(hFile
), buffer
, count
);
2308 /***********************************************************************
2309 * _hwrite (KERNEL32.@)
2311 * experimentation yields that _lwrite:
2312 * o truncates the file at the current position with
2314 * o returns 0 on a 0 length write
2315 * o works with console handles
2318 LONG WINAPI
_hwrite( HFILE handle
, LPCSTR buffer
, LONG count
)
2322 TRACE("%d %p %ld\n", handle
, buffer
, count
);
2326 /* Expand or truncate at current position */
2327 if (!SetEndOfFile( (HANDLE
)handle
)) return HFILE_ERROR
;
2330 if (!WriteFile( (HANDLE
)handle
, buffer
, count
, &result
, NULL
))
2336 /***********************************************************************
2337 * SetHandleCount (KERNEL.199)
2339 UINT16 WINAPI
SetHandleCount16( UINT16 count
)
2341 return SetHandleCount( count
);
2345 /*************************************************************************
2346 * SetHandleCount (KERNEL32.@)
2348 UINT WINAPI
SetHandleCount( UINT count
)
2350 return min( 256, count
);
2354 /***********************************************************************
2355 * FlushFileBuffers (KERNEL32.@)
2357 BOOL WINAPI
FlushFileBuffers( HANDLE hFile
)
2360 SERVER_START_REQ( flush_file
)
2362 req
->handle
= hFile
;
2363 ret
= !wine_server_call_err( req
);
2370 /**************************************************************************
2371 * SetEndOfFile (KERNEL32.@)
2373 BOOL WINAPI
SetEndOfFile( HANDLE hFile
)
2376 SERVER_START_REQ( truncate_file
)
2378 req
->handle
= hFile
;
2379 ret
= !wine_server_call_err( req
);
2386 /***********************************************************************
2387 * DeleteFile (KERNEL.146)
2389 BOOL16 WINAPI
DeleteFile16( LPCSTR path
)
2391 return DeleteFileA( path
);
2395 /***********************************************************************
2396 * DeleteFileW (KERNEL32.@)
2398 BOOL WINAPI
DeleteFileW( LPCWSTR path
)
2400 DOS_FULL_NAME full_name
;
2403 TRACE("%s\n", debugstr_w(path
) );
2404 if (!path
|| !*path
)
2406 SetLastError(ERROR_PATH_NOT_FOUND
);
2409 if (DOSFS_GetDevice( path
))
2411 WARN("cannot remove DOS device %s!\n", debugstr_w(path
));
2412 SetLastError( ERROR_FILE_NOT_FOUND
);
2416 if (!DOSFS_GetFullName( path
, TRUE
, &full_name
)) return FALSE
;
2418 /* check if we are allowed to delete the source */
2419 hFile
= FILE_CreateFile( full_name
.long_name
, GENERIC_READ
|GENERIC_WRITE
, 0,
2420 NULL
, OPEN_EXISTING
, 0, 0, TRUE
,
2421 GetDriveTypeW( full_name
.short_name
) );
2422 if (!hFile
) return FALSE
;
2424 if (unlink( full_name
.long_name
) == -1)
2435 /***********************************************************************
2436 * DeleteFileA (KERNEL32.@)
2438 BOOL WINAPI
DeleteFileA( LPCSTR path
)
2440 UNICODE_STRING pathW
;
2445 SetLastError(ERROR_INVALID_PARAMETER
);
2449 if (RtlCreateUnicodeStringFromAsciiz(&pathW
, path
))
2451 ret
= DeleteFileW(pathW
.Buffer
);
2452 RtlFreeUnicodeString(&pathW
);
2455 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
2460 /***********************************************************************
2461 * GetFileType (KERNEL32.@)
2463 DWORD WINAPI
GetFileType( HANDLE hFile
)
2465 DWORD ret
= FILE_TYPE_UNKNOWN
;
2466 SERVER_START_REQ( get_file_info
)
2468 req
->handle
= hFile
;
2469 if (!wine_server_call_err( req
)) ret
= reply
->type
;
2476 /* check if a file name is for an executable file (.exe or .com) */
2477 inline static BOOL
is_executable( const char *name
)
2479 int len
= strlen(name
);
2481 if (len
< 4) return FALSE
;
2482 return (!strcasecmp( name
+ len
- 4, ".exe" ) ||
2483 !strcasecmp( name
+ len
- 4, ".com" ));
2487 /***********************************************************************
2488 * FILE_AddBootRenameEntry
2490 * Adds an entry to the registry that is loaded when windows boots and
2491 * checks if there are some files to be removed or renamed/moved.
2492 * <fn1> has to be valid and <fn2> may be NULL. If both pointers are
2493 * non-NULL then the file is moved, otherwise it is deleted. The
2494 * entry of the registrykey is always appended with two zero
2495 * terminated strings. If <fn2> is NULL then the second entry is
2496 * simply a single 0-byte. Otherwise the second filename goes
2497 * there. The entries are prepended with \??\ before the path and the
2498 * second filename gets also a '!' as the first character if
2499 * MOVEFILE_REPLACE_EXISTING is set. After the final string another
2500 * 0-byte follows to indicate the end of the strings.
2502 * \??\D:\test\file1[0]
2503 * !\??\D:\test\file1_renamed[0]
2504 * \??\D:\Test|delete[0]
2505 * [0] <- file is to be deleted, second string empty
2506 * \??\D:\test\file2[0]
2507 * !\??\D:\test\file2_renamed[0]
2508 * [0] <- indicates end of strings
2511 * \??\D:\test\file1[0]
2512 * !\??\D:\test\file1_renamed[0]
2513 * \??\D:\Test|delete[0]
2514 * [0] <- file is to be deleted, second string empty
2515 * [0] <- indicates end of strings
2518 static BOOL
FILE_AddBootRenameEntry( LPCWSTR fn1
, LPCWSTR fn2
, DWORD flags
)
2520 static const WCHAR PreString
[] = {'\\','?','?','\\',0};
2521 static const WCHAR ValueName
[] = {'P','e','n','d','i','n','g',
2522 'F','i','l','e','R','e','n','a','m','e',
2523 'O','p','e','r','a','t','i','o','n','s',0};
2524 static const WCHAR SessionW
[] = {'M','a','c','h','i','n','e','\\',
2525 'S','y','s','t','e','m','\\',
2526 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
2527 'C','o','n','t','r','o','l','\\',
2528 'S','e','s','s','i','o','n',' ','M','a','n','a','g','e','r',0};
2529 static const int info_size
= FIELD_OFFSET( KEY_VALUE_PARTIAL_INFORMATION
, Data
);
2531 OBJECT_ATTRIBUTES attr
;
2532 UNICODE_STRING nameW
;
2533 KEY_VALUE_PARTIAL_INFORMATION
*info
;
2536 DWORD len0
, len1
, len2
;
2538 BYTE
*Buffer
= NULL
;
2541 attr
.Length
= sizeof(attr
);
2542 attr
.RootDirectory
= 0;
2543 attr
.ObjectName
= &nameW
;
2544 attr
.Attributes
= 0;
2545 attr
.SecurityDescriptor
= NULL
;
2546 attr
.SecurityQualityOfService
= NULL
;
2547 RtlInitUnicodeString( &nameW
, SessionW
);
2549 if (NtCreateKey( &Reboot
, KEY_ALL_ACCESS
, &attr
, 0, NULL
, 0, NULL
) != STATUS_SUCCESS
)
2551 WARN("Error creating key for reboot managment [%s]\n",
2552 "SYSTEM\\CurrentControlSet\\Control\\Session Manager");
2556 len0
= strlenW(PreString
);
2557 len1
= strlenW(fn1
) + len0
+ 1;
2560 len2
= strlenW(fn2
) + len0
+ 1;
2561 if (flags
& MOVEFILE_REPLACE_EXISTING
) len2
++; /* Plus 1 because of the leading '!' */
2563 else len2
= 1; /* minimum is the 0 characters for the empty second string */
2565 /* convert characters to bytes */
2566 len0
*= sizeof(WCHAR
);
2567 len1
*= sizeof(WCHAR
);
2568 len2
*= sizeof(WCHAR
);
2570 RtlInitUnicodeString( &nameW
, ValueName
);
2572 /* First we check if the key exists and if so how many bytes it already contains. */
2573 if (NtQueryValueKey( Reboot
, &nameW
, KeyValuePartialInformation
,
2574 NULL
, 0, &DataSize
) == STATUS_BUFFER_OVERFLOW
)
2576 if (!(Buffer
= HeapAlloc( GetProcessHeap(), 0, DataSize
+ len1
+ len2
+ sizeof(WCHAR
) )))
2578 if (NtQueryValueKey( Reboot
, &nameW
, KeyValuePartialInformation
,
2579 Buffer
, DataSize
, &DataSize
)) goto Quit
;
2580 info
= (KEY_VALUE_PARTIAL_INFORMATION
*)Buffer
;
2581 if (info
->Type
!= REG_MULTI_SZ
) goto Quit
;
2582 if (DataSize
> sizeof(info
)) DataSize
-= sizeof(WCHAR
); /* remove terminating null (will be added back later) */
2586 DataSize
= info_size
;
2587 if (!(Buffer
= HeapAlloc( GetProcessHeap(), 0, DataSize
+ len1
+ len2
+ sizeof(WCHAR
) )))
2591 p
= (WCHAR
*)(Buffer
+ DataSize
);
2592 strcpyW( p
, PreString
);
2597 p
= (WCHAR
*)(Buffer
+ DataSize
);
2598 if (flags
& MOVEFILE_REPLACE_EXISTING
)
2600 strcpyW( p
, PreString
);
2606 p
= (WCHAR
*)(Buffer
+ DataSize
);
2608 DataSize
+= sizeof(WCHAR
);
2611 /* add final null */
2612 p
= (WCHAR
*)(Buffer
+ DataSize
);
2614 DataSize
+= sizeof(WCHAR
);
2616 rc
= !NtSetValueKey(Reboot
, &nameW
, 0, REG_MULTI_SZ
, Buffer
+ info_size
, DataSize
- info_size
);
2619 if (Reboot
) NtClose(Reboot
);
2620 if (Buffer
) HeapFree( GetProcessHeap(), 0, Buffer
);
2625 /**************************************************************************
2626 * MoveFileExW (KERNEL32.@)
2628 BOOL WINAPI
MoveFileExW( LPCWSTR fn1
, LPCWSTR fn2
, DWORD flag
)
2630 DOS_FULL_NAME full_name1
, full_name2
;
2632 DWORD attr
= INVALID_FILE_ATTRIBUTES
;
2634 TRACE("(%s,%s,%04lx)\n", debugstr_w(fn1
), debugstr_w(fn2
), flag
);
2636 /* FIXME: <Gerhard W. Gruber>sparhawk@gmx.at
2637 In case of W9x and lesser this function should return 120 (ERROR_CALL_NOT_IMPLEMENTED)
2638 to be really compatible. Most programs wont have any problems though. In case
2639 you encounter one, this is what you should return here. I don't know what's up
2640 with NT 3.5. Is this function available there or not?
2641 Does anybody really care about 3.5? :)
2644 /* Filename1 has to be always set to a valid path. Filename2 may be NULL
2645 if the source file has to be deleted.
2648 SetLastError(ERROR_INVALID_PARAMETER
);
2652 /* This function has to be run through in order to process the name properly.
2653 If the BOOTDELAY flag is set, the file doesn't need to exist though. At least
2654 that is the behaviour on NT 4.0. The operation accepts the filenames as
2655 they are given but it can't reply with a reasonable returncode. Success
2656 means in that case success for entering the values into the registry.
2658 if(!DOSFS_GetFullName( fn1
, TRUE
, &full_name1
))
2660 if(!(flag
& MOVEFILE_DELAY_UNTIL_REBOOT
))
2664 if (fn2
) /* !fn2 means delete fn1 */
2666 if (DOSFS_GetFullName( fn2
, TRUE
, &full_name2
))
2668 if(!(flag
& MOVEFILE_DELAY_UNTIL_REBOOT
))
2670 /* target exists, check if we may overwrite */
2671 if (!(flag
& MOVEFILE_REPLACE_EXISTING
))
2673 SetLastError( ERROR_FILE_EXISTS
);
2680 if (!DOSFS_GetFullName( fn2
, FALSE
, &full_name2
))
2682 if(!(flag
& MOVEFILE_DELAY_UNTIL_REBOOT
))
2687 /* Source name and target path are valid */
2689 if (flag
& MOVEFILE_DELAY_UNTIL_REBOOT
)
2691 /* FIXME: (bon@elektron.ikp.physik.th-darmstadt.de 970706)
2692 Perhaps we should queue these command and execute it
2693 when exiting... What about using on_exit(2)
2695 FIXME("Please move existing file %s to file %s when Wine has finished\n",
2696 debugstr_w(fn1
), debugstr_w(fn2
));
2697 return FILE_AddBootRenameEntry( fn1
, fn2
, flag
);
2700 attr
= GetFileAttributesW( fn1
);
2701 if ( attr
== INVALID_FILE_ATTRIBUTES
) return FALSE
;
2703 /* check if we are allowed to rename the source */
2704 hFile
= FILE_CreateFile( full_name1
.long_name
, 0, 0,
2705 NULL
, OPEN_EXISTING
, 0, 0, TRUE
,
2706 GetDriveTypeW( full_name1
.short_name
) );
2709 if (GetLastError() != ERROR_ACCESS_DENIED
) return FALSE
;
2710 if ( !(attr
& FILE_ATTRIBUTE_DIRECTORY
) ) return FALSE
;
2711 /* if it's a directory we can continue */
2713 else CloseHandle(hFile
);
2715 /* check, if we are allowed to delete the destination,
2716 ** (but the file not being there is fine) */
2717 hFile
= FILE_CreateFile( full_name2
.long_name
, GENERIC_READ
|GENERIC_WRITE
, 0,
2718 NULL
, OPEN_EXISTING
, 0, 0, TRUE
,
2719 GetDriveTypeW( full_name2
.short_name
) );
2720 if(!hFile
&& GetLastError() != ERROR_FILE_NOT_FOUND
) return FALSE
;
2723 if (full_name1
.drive
!= full_name2
.drive
)
2725 if (!(flag
& MOVEFILE_COPY_ALLOWED
))
2727 SetLastError( ERROR_NOT_SAME_DEVICE
);
2730 else if ( attr
& FILE_ATTRIBUTE_DIRECTORY
)
2732 /* Strange, but that's what Windows returns */
2733 SetLastError ( ERROR_ACCESS_DENIED
);
2737 if (rename( full_name1
.long_name
, full_name2
.long_name
) == -1)
2738 /* Try copy/delete unless it's a directory. */
2739 /* FIXME: This does not handle the (unlikely) case that the two locations
2740 are on the same Wine drive, but on different Unix file systems. */
2742 if ( attr
& FILE_ATTRIBUTE_DIRECTORY
)
2749 if ( ! CopyFileW( fn1
, fn2
, !(flag
& MOVEFILE_REPLACE_EXISTING
) ))
2751 if ( ! DeleteFileW ( fn1
) )
2755 if (is_executable( full_name1
.long_name
) != is_executable( full_name2
.long_name
))
2758 if (stat( full_name2
.long_name
, &fstat
) != -1)
2760 if (is_executable( full_name2
.long_name
))
2761 /* set executable bit where read bit is set */
2762 fstat
.st_mode
|= (fstat
.st_mode
& 0444) >> 2;
2764 fstat
.st_mode
&= ~0111;
2765 chmod( full_name2
.long_name
, fstat
.st_mode
);
2770 else /* fn2 == NULL means delete source */
2772 if (flag
& MOVEFILE_DELAY_UNTIL_REBOOT
)
2774 if (flag
& MOVEFILE_COPY_ALLOWED
) {
2775 WARN("Illegal flag\n");
2776 SetLastError( ERROR_GEN_FAILURE
);
2779 /* FIXME: (bon@elektron.ikp.physik.th-darmstadt.de 970706)
2780 Perhaps we should queue these command and execute it
2781 when exiting... What about using on_exit(2)
2783 FIXME("Please delete file %s when Wine has finished\n", debugstr_w(fn1
));
2784 return FILE_AddBootRenameEntry( fn1
, NULL
, flag
);
2787 if (unlink( full_name1
.long_name
) == -1)
2792 return TRUE
; /* successfully deleted */
2796 /**************************************************************************
2797 * MoveFileExA (KERNEL32.@)
2799 BOOL WINAPI
MoveFileExA( LPCSTR fn1
, LPCSTR fn2
, DWORD flag
)
2801 UNICODE_STRING fn1W
, fn2W
;
2806 SetLastError(ERROR_INVALID_PARAMETER
);
2810 RtlCreateUnicodeStringFromAsciiz(&fn1W
, fn1
);
2811 if (fn2
) RtlCreateUnicodeStringFromAsciiz(&fn2W
, fn2
);
2812 else fn2W
.Buffer
= NULL
;
2814 ret
= MoveFileExW( fn1W
.Buffer
, fn2W
.Buffer
, flag
);
2816 RtlFreeUnicodeString(&fn1W
);
2817 RtlFreeUnicodeString(&fn2W
);
2822 /**************************************************************************
2823 * MoveFileW (KERNEL32.@)
2825 * Move file or directory
2827 BOOL WINAPI
MoveFileW( LPCWSTR fn1
, LPCWSTR fn2
)
2829 DOS_FULL_NAME full_name1
, full_name2
;
2834 SetLastError(ERROR_INVALID_PARAMETER
);
2838 TRACE("(%s,%s)\n", debugstr_w(fn1
), debugstr_w(fn2
) );
2840 if (!DOSFS_GetFullName( fn1
, TRUE
, &full_name1
)) return FALSE
;
2841 if (DOSFS_GetFullName( fn2
, TRUE
, &full_name2
)) {
2842 /* The new name must not already exist */
2843 SetLastError(ERROR_ALREADY_EXISTS
);
2846 if (!DOSFS_GetFullName( fn2
, FALSE
, &full_name2
)) return FALSE
;
2848 if (full_name1
.drive
== full_name2
.drive
) /* move */
2849 return MoveFileExW( fn1
, fn2
, MOVEFILE_COPY_ALLOWED
);
2852 if (stat( full_name1
.long_name
, &fstat
))
2854 WARN("Invalid source file %s\n",
2855 full_name1
.long_name
);
2859 if (S_ISDIR(fstat
.st_mode
)) {
2860 /* No Move for directories across file systems */
2861 /* FIXME: Use right error code */
2862 SetLastError( ERROR_GEN_FAILURE
);
2865 return CopyFileW(fn1
, fn2
, TRUE
); /*fail, if exist */
2869 /**************************************************************************
2870 * MoveFileA (KERNEL32.@)
2872 BOOL WINAPI
MoveFileA( LPCSTR fn1
, LPCSTR fn2
)
2874 UNICODE_STRING fn1W
, fn2W
;
2879 SetLastError(ERROR_INVALID_PARAMETER
);
2883 RtlCreateUnicodeStringFromAsciiz(&fn1W
, fn1
);
2884 RtlCreateUnicodeStringFromAsciiz(&fn2W
, fn2
);
2886 ret
= MoveFileW( fn1W
.Buffer
, fn2W
.Buffer
);
2888 RtlFreeUnicodeString(&fn1W
);
2889 RtlFreeUnicodeString(&fn2W
);
2894 /**************************************************************************
2895 * CopyFileW (KERNEL32.@)
2897 BOOL WINAPI
CopyFileW( LPCWSTR source
, LPCWSTR dest
, BOOL fail_if_exists
)
2900 BY_HANDLE_FILE_INFORMATION info
;
2905 if (!source
|| !dest
)
2907 SetLastError(ERROR_INVALID_PARAMETER
);
2911 TRACE("%s -> %s\n", debugstr_w(source
), debugstr_w(dest
));
2913 if ((h1
= CreateFileW(source
, GENERIC_READ
, FILE_SHARE_READ
| FILE_SHARE_WRITE
,
2914 NULL
, OPEN_EXISTING
, 0, 0)) == INVALID_HANDLE_VALUE
)
2916 WARN("Unable to open source %s\n", debugstr_w(source
));
2920 if (!GetFileInformationByHandle( h1
, &info
))
2922 WARN("GetFileInformationByHandle returned error for %s\n", debugstr_w(source
));
2927 if ((h2
= CreateFileW( dest
, GENERIC_WRITE
, FILE_SHARE_READ
| FILE_SHARE_WRITE
, NULL
,
2928 fail_if_exists
? CREATE_NEW
: CREATE_ALWAYS
,
2929 info
.dwFileAttributes
, h1
)) == INVALID_HANDLE_VALUE
)
2931 WARN("Unable to open dest %s\n", debugstr_w(dest
));
2936 while (ReadFile( h1
, buffer
, sizeof(buffer
), &count
, NULL
) && count
)
2942 if (!WriteFile( h2
, p
, count
, &res
, NULL
) || !res
) goto done
;
2955 /**************************************************************************
2956 * CopyFileA (KERNEL32.@)
2958 BOOL WINAPI
CopyFileA( LPCSTR source
, LPCSTR dest
, BOOL fail_if_exists
)
2960 UNICODE_STRING sourceW
, destW
;
2963 if (!source
|| !dest
)
2965 SetLastError(ERROR_INVALID_PARAMETER
);
2969 RtlCreateUnicodeStringFromAsciiz(&sourceW
, source
);
2970 RtlCreateUnicodeStringFromAsciiz(&destW
, dest
);
2972 ret
= CopyFileW(sourceW
.Buffer
, destW
.Buffer
, fail_if_exists
);
2974 RtlFreeUnicodeString(&sourceW
);
2975 RtlFreeUnicodeString(&destW
);
2980 /**************************************************************************
2981 * CopyFileExW (KERNEL32.@)
2983 * This implementation ignores most of the extra parameters passed-in into
2984 * the "ex" version of the method and calls the CopyFile method.
2985 * It will have to be fixed eventually.
2987 BOOL WINAPI
CopyFileExW(LPCWSTR sourceFilename
, LPCWSTR destFilename
,
2988 LPPROGRESS_ROUTINE progressRoutine
, LPVOID appData
,
2989 LPBOOL cancelFlagPointer
, DWORD copyFlags
)
2992 * Interpret the only flag that CopyFile can interpret.
2994 return CopyFileW(sourceFilename
, destFilename
, (copyFlags
& COPY_FILE_FAIL_IF_EXISTS
) != 0);
2997 /**************************************************************************
2998 * CopyFileExA (KERNEL32.@)
3000 BOOL WINAPI
CopyFileExA(LPCSTR sourceFilename
, LPCSTR destFilename
,
3001 LPPROGRESS_ROUTINE progressRoutine
, LPVOID appData
,
3002 LPBOOL cancelFlagPointer
, DWORD copyFlags
)
3004 UNICODE_STRING sourceW
, destW
;
3007 if (!sourceFilename
|| !destFilename
)
3009 SetLastError(ERROR_INVALID_PARAMETER
);
3013 RtlCreateUnicodeStringFromAsciiz(&sourceW
, sourceFilename
);
3014 RtlCreateUnicodeStringFromAsciiz(&destW
, destFilename
);
3016 ret
= CopyFileExW(sourceW
.Buffer
, destW
.Buffer
, progressRoutine
, appData
,
3017 cancelFlagPointer
, copyFlags
);
3019 RtlFreeUnicodeString(&sourceW
);
3020 RtlFreeUnicodeString(&destW
);
3025 /***********************************************************************
3026 * SetFileTime (KERNEL32.@)
3028 BOOL WINAPI
SetFileTime( HANDLE hFile
,
3029 const FILETIME
*lpCreationTime
,
3030 const FILETIME
*lpLastAccessTime
,
3031 const FILETIME
*lpLastWriteTime
)
3034 SERVER_START_REQ( set_file_time
)
3036 req
->handle
= hFile
;
3037 if (lpLastAccessTime
)
3038 RtlTimeToSecondsSince1970( (PLARGE_INTEGER
) lpLastAccessTime
, (DWORD
*)&req
->access_time
);
3040 req
->access_time
= 0; /* FIXME */
3041 if (lpLastWriteTime
)
3042 RtlTimeToSecondsSince1970( (PLARGE_INTEGER
) lpLastWriteTime
, (DWORD
*)&req
->write_time
);
3044 req
->write_time
= 0; /* FIXME */
3045 ret
= !wine_server_call_err( req
);
3052 /**************************************************************************
3053 * LockFile (KERNEL32.@)
3055 BOOL WINAPI
LockFile( HANDLE hFile
, DWORD dwFileOffsetLow
, DWORD dwFileOffsetHigh
,
3056 DWORD nNumberOfBytesToLockLow
, DWORD nNumberOfBytesToLockHigh
)
3060 FIXME("not implemented in server\n");
3062 SERVER_START_REQ( lock_file
)
3064 req
->handle
= hFile
;
3065 req
->offset_low
= dwFileOffsetLow
;
3066 req
->offset_high
= dwFileOffsetHigh
;
3067 req
->count_low
= nNumberOfBytesToLockLow
;
3068 req
->count_high
= nNumberOfBytesToLockHigh
;
3069 ret
= !wine_server_call_err( req
);
3075 /**************************************************************************
3076 * LockFileEx [KERNEL32.@]
3078 * Locks a byte range within an open file for shared or exclusive access.
3085 * Per Microsoft docs, the third parameter (reserved) must be set to 0.
3087 BOOL WINAPI
LockFileEx( HANDLE hFile
, DWORD flags
, DWORD reserved
,
3088 DWORD nNumberOfBytesToLockLow
, DWORD nNumberOfBytesToLockHigh
,
3089 LPOVERLAPPED pOverlapped
)
3091 FIXME("hFile=%p,flags=%ld,reserved=%ld,lowbytes=%ld,highbytes=%ld,overlapped=%p: stub.\n",
3092 hFile
, flags
, reserved
, nNumberOfBytesToLockLow
, nNumberOfBytesToLockHigh
,
3095 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
3098 ERR("reserved == %ld: Supposed to be 0??\n", reserved
);
3099 SetLastError(ERROR_INVALID_PARAMETER
);
3106 /**************************************************************************
3107 * UnlockFile (KERNEL32.@)
3109 BOOL WINAPI
UnlockFile( HANDLE hFile
, DWORD dwFileOffsetLow
, DWORD dwFileOffsetHigh
,
3110 DWORD nNumberOfBytesToUnlockLow
, DWORD nNumberOfBytesToUnlockHigh
)
3114 FIXME("not implemented in server\n");
3116 SERVER_START_REQ( unlock_file
)
3118 req
->handle
= hFile
;
3119 req
->offset_low
= dwFileOffsetLow
;
3120 req
->offset_high
= dwFileOffsetHigh
;
3121 req
->count_low
= nNumberOfBytesToUnlockLow
;
3122 req
->count_high
= nNumberOfBytesToUnlockHigh
;
3123 ret
= !wine_server_call_err( req
);
3130 /**************************************************************************
3131 * UnlockFileEx (KERNEL32.@)
3133 BOOL WINAPI
UnlockFileEx(
3136 DWORD nNumberOfBytesToUnlockLow
,
3137 DWORD nNumberOfBytesToUnlockHigh
,
3138 LPOVERLAPPED lpOverlapped
3141 FIXME("hFile=%p,reserved=%ld,lowbytes=%ld,highbytes=%ld,overlapped=%p: stub.\n",
3142 hFile
, dwReserved
, nNumberOfBytesToUnlockLow
, nNumberOfBytesToUnlockHigh
,
3144 if (dwReserved
== 0)
3145 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
3148 ERR("reserved == %ld: Supposed to be 0??\n", dwReserved
);
3149 SetLastError(ERROR_INVALID_PARAMETER
);
3158 struct DOS_FILE_LOCK
{
3159 struct DOS_FILE_LOCK
* next
;
3163 FILE_OBJECT
* dos_file
;
3164 /* char * unix_name;*/
3167 typedef struct DOS_FILE_LOCK DOS_FILE_LOCK
;
3169 static DOS_FILE_LOCK
*locks
= NULL
;
3170 static void DOS_RemoveFileLocks(FILE_OBJECT
*file
);
3173 /* Locks need to be mirrored because unix file locking is based
3174 * on the pid. Inside of wine there can be multiple WINE processes
3175 * that share the same unix pid.
3176 * Read's and writes should check these locks also - not sure
3177 * how critical that is at this point (FIXME).
3180 static BOOL
DOS_AddLock(FILE_OBJECT
*file
, struct flock
*f
)
3182 DOS_FILE_LOCK
*curr
;
3185 processId
= GetCurrentProcessId();
3187 /* check if lock overlaps a current lock for the same file */
3189 for (curr
= locks
; curr
; curr
= curr
->next
) {
3190 if (strcmp(curr
->unix_name
, file
->unix_name
) == 0) {
3191 if ((f
->l_start
== curr
->base
) && (f
->l_len
== curr
->len
))
3192 return TRUE
;/* region is identic */
3193 if ((f
->l_start
< (curr
->base
+ curr
->len
)) &&
3194 ((f
->l_start
+ f
->l_len
) > curr
->base
)) {
3195 /* region overlaps */
3202 curr
= HeapAlloc( GetProcessHeap(), 0, sizeof(DOS_FILE_LOCK
) );
3203 curr
->processId
= GetCurrentProcessId();
3204 curr
->base
= f
->l_start
;
3205 curr
->len
= f
->l_len
;
3206 /* curr->unix_name = HEAP_strdupA( GetProcessHeap(), 0, file->unix_name);*/
3208 curr
->dos_file
= file
;
3213 static void DOS_RemoveFileLocks(FILE_OBJECT
*file
)
3216 DOS_FILE_LOCK
**curr
;
3219 processId
= GetCurrentProcessId();
3222 if ((*curr
)->dos_file
== file
) {
3224 *curr
= (*curr
)->next
;
3225 /* HeapFree( GetProcessHeap(), 0, rem->unix_name );*/
3226 HeapFree( GetProcessHeap(), 0, rem
);
3229 curr
= &(*curr
)->next
;
3233 static BOOL
DOS_RemoveLock(FILE_OBJECT
*file
, struct flock
*f
)
3236 DOS_FILE_LOCK
**curr
;
3239 processId
= GetCurrentProcessId();
3240 for (curr
= &locks
; *curr
; curr
= &(*curr
)->next
) {
3241 if ((*curr
)->processId
== processId
&&
3242 (*curr
)->dos_file
== file
&&
3243 (*curr
)->base
== f
->l_start
&&
3244 (*curr
)->len
== f
->l_len
) {
3245 /* this is the same lock */
3247 *curr
= (*curr
)->next
;
3248 /* HeapFree( GetProcessHeap(), 0, rem->unix_name );*/
3249 HeapFree( GetProcessHeap(), 0, rem
);
3253 /* no matching lock found */
3258 /**************************************************************************
3259 * LockFile (KERNEL32.@)
3261 BOOL WINAPI
LockFile(
3262 HANDLE hFile
,DWORD dwFileOffsetLow
,DWORD dwFileOffsetHigh
,
3263 DWORD nNumberOfBytesToLockLow
,DWORD nNumberOfBytesToLockHigh
)
3268 TRACE("handle %d offsetlow=%ld offsethigh=%ld nbyteslow=%ld nbyteshigh=%ld\n",
3269 hFile
, dwFileOffsetLow
, dwFileOffsetHigh
,
3270 nNumberOfBytesToLockLow
, nNumberOfBytesToLockHigh
);
3272 if (dwFileOffsetHigh
|| nNumberOfBytesToLockHigh
) {
3273 FIXME("Unimplemented bytes > 32bits\n");
3277 f
.l_start
= dwFileOffsetLow
;
3278 f
.l_len
= nNumberOfBytesToLockLow
;
3279 f
.l_whence
= SEEK_SET
;
3283 if (!(file
= FILE_GetFile(hFile
,0,NULL
))) return FALSE
;
3285 /* shadow locks internally */
3286 if (!DOS_AddLock(file
, &f
)) {
3287 SetLastError( ERROR_LOCK_VIOLATION
);
3291 /* FIXME: Unix locking commented out for now, doesn't work with Excel */
3292 #ifdef USE_UNIX_LOCKS
3293 if (fcntl(file
->unix_handle
, F_SETLK
, &f
) == -1) {
3294 if (errno
== EACCES
|| errno
== EAGAIN
) {
3295 SetLastError( ERROR_LOCK_VIOLATION
);
3300 /* remove our internal copy of the lock */
3301 DOS_RemoveLock(file
, &f
);
3309 /**************************************************************************
3310 * UnlockFile (KERNEL32.@)
3312 BOOL WINAPI
UnlockFile(
3313 HANDLE hFile
,DWORD dwFileOffsetLow
,DWORD dwFileOffsetHigh
,
3314 DWORD nNumberOfBytesToUnlockLow
,DWORD nNumberOfBytesToUnlockHigh
)
3319 TRACE("handle %d offsetlow=%ld offsethigh=%ld nbyteslow=%ld nbyteshigh=%ld\n",
3320 hFile
, dwFileOffsetLow
, dwFileOffsetHigh
,
3321 nNumberOfBytesToUnlockLow
, nNumberOfBytesToUnlockHigh
);
3323 if (dwFileOffsetHigh
|| nNumberOfBytesToUnlockHigh
) {
3324 WARN("Unimplemented bytes > 32bits\n");
3328 f
.l_start
= dwFileOffsetLow
;
3329 f
.l_len
= nNumberOfBytesToUnlockLow
;
3330 f
.l_whence
= SEEK_SET
;
3334 if (!(file
= FILE_GetFile(hFile
,0,NULL
))) return FALSE
;
3336 DOS_RemoveLock(file
, &f
); /* ok if fails - may be another wine */
3338 /* FIXME: Unix locking commented out for now, doesn't work with Excel */
3339 #ifdef USE_UNIX_LOCKS
3340 if (fcntl(file
->unix_handle
, F_SETLK
, &f
) == -1) {
3349 /**************************************************************************
3350 * GetFileAttributesExW (KERNEL32.@)
3352 BOOL WINAPI
GetFileAttributesExW(
3353 LPCWSTR lpFileName
, GET_FILEEX_INFO_LEVELS fInfoLevelId
,
3354 LPVOID lpFileInformation
)
3356 DOS_FULL_NAME full_name
;
3357 BY_HANDLE_FILE_INFORMATION info
;
3359 if (!lpFileName
|| !lpFileInformation
)
3361 SetLastError(ERROR_INVALID_PARAMETER
);
3365 if (fInfoLevelId
== GetFileExInfoStandard
) {
3366 LPWIN32_FILE_ATTRIBUTE_DATA lpFad
=
3367 (LPWIN32_FILE_ATTRIBUTE_DATA
) lpFileInformation
;
3368 if (!DOSFS_GetFullName( lpFileName
, TRUE
, &full_name
)) return FALSE
;
3369 if (!FILE_Stat( full_name
.long_name
, &info
, NULL
)) return FALSE
;
3371 lpFad
->dwFileAttributes
= info
.dwFileAttributes
;
3372 lpFad
->ftCreationTime
= info
.ftCreationTime
;
3373 lpFad
->ftLastAccessTime
= info
.ftLastAccessTime
;
3374 lpFad
->ftLastWriteTime
= info
.ftLastWriteTime
;
3375 lpFad
->nFileSizeHigh
= info
.nFileSizeHigh
;
3376 lpFad
->nFileSizeLow
= info
.nFileSizeLow
;
3379 FIXME("invalid info level %d!\n", fInfoLevelId
);
3387 /**************************************************************************
3388 * GetFileAttributesExA (KERNEL32.@)
3390 BOOL WINAPI
GetFileAttributesExA(
3391 LPCSTR filename
, GET_FILEEX_INFO_LEVELS fInfoLevelId
,
3392 LPVOID lpFileInformation
)
3394 UNICODE_STRING filenameW
;
3397 if (!filename
|| !lpFileInformation
)
3399 SetLastError(ERROR_INVALID_PARAMETER
);
3403 if (RtlCreateUnicodeStringFromAsciiz(&filenameW
, filename
))
3405 ret
= GetFileAttributesExW(filenameW
.Buffer
, fInfoLevelId
, lpFileInformation
);
3406 RtlFreeUnicodeString(&filenameW
);
3409 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
3413 /**************************************************************************
3414 * ReplaceFileW (KERNEL32.@)
3415 * ReplaceFile (KERNEL32.@)
3417 BOOL WINAPI
ReplaceFileW(LPCWSTR lpReplacedFileName
,LPCWSTR lpReplacementFileName
,
3418 LPCWSTR lpBackupFileName
, DWORD dwReplaceFlags
,
3419 LPVOID lpExclude
, LPVOID lpReserved
)
3421 FIXME("(%s,%s,%s,%08lx,%p,%p) stub\n",debugstr_w(lpReplacedFileName
),debugstr_w(lpReplacementFileName
),
3422 debugstr_w(lpBackupFileName
),dwReplaceFlags
,lpExclude
,lpReserved
);
3423 SetLastError(ERROR_UNABLE_TO_MOVE_REPLACEMENT
);
3427 /**************************************************************************
3428 * ReplaceFileA (KERNEL32.@)
3430 BOOL WINAPI
ReplaceFileA(LPCSTR lpReplacedFileName
,LPCSTR lpReplacementFileName
,
3431 LPCSTR lpBackupFileName
, DWORD dwReplaceFlags
,
3432 LPVOID lpExclude
, LPVOID lpReserved
)
3434 FIXME("(%s,%s,%s,%08lx,%p,%p) stub\n",lpReplacedFileName
,lpReplacementFileName
,
3435 lpBackupFileName
,dwReplaceFlags
,lpExclude
,lpReserved
);
3436 SetLastError(ERROR_UNABLE_TO_MOVE_REPLACEMENT
);