Eric Pouech | f6a7096 | 2003-06-24 02:32:01 +0000 | [diff] [blame] | 1 | /* |
| 2 | * File handling functions |
| 3 | * |
| 4 | * Copyright 1993 John Burton |
Alexandre Julliard | b592cbb | 2004-05-01 02:44:00 +0000 | [diff] [blame] | 5 | * Copyright 1996, 2004 Alexandre Julliard |
Eric Pouech | f6a7096 | 2003-06-24 02:32:01 +0000 | [diff] [blame] | 6 | * |
| 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. |
| 11 | * |
| 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. |
| 16 | * |
| 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 |
Jonathan Ernst | 360a3f9 | 2006-05-18 14:49:52 +0200 | [diff] [blame] | 19 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA |
Eric Pouech | f6a7096 | 2003-06-24 02:32:01 +0000 | [diff] [blame] | 20 | */ |
| 21 | |
| 22 | #include "config.h" |
| 23 | #include "wine/port.h" |
| 24 | |
Alexandre Julliard | e37c6e1 | 2003-09-05 23:08:26 +0000 | [diff] [blame] | 25 | #include <stdarg.h> |
Hans Leidekker | 84e9eb6 | 2004-10-11 19:53:13 +0000 | [diff] [blame] | 26 | #include <stdio.h> |
Alexandre Julliard | 643617f | 2004-05-01 05:25:07 +0000 | [diff] [blame] | 27 | #include <errno.h> |
Alexandre Julliard | a51f2be | 2005-10-26 13:57:45 +0000 | [diff] [blame] | 28 | #ifdef HAVE_SYS_STAT_H |
| 29 | # include <sys/stat.h> |
| 30 | #endif |
Alexandre Julliard | e37c6e1 | 2003-09-05 23:08:26 +0000 | [diff] [blame] | 31 | |
Eric Pouech | f6a7096 | 2003-06-24 02:32:01 +0000 | [diff] [blame] | 32 | #define NONAMELESSUNION |
| 33 | #define NONAMELESSSTRUCT |
| 34 | #include "winerror.h" |
Alexandre Julliard | e37c6e1 | 2003-09-05 23:08:26 +0000 | [diff] [blame] | 35 | #include "ntstatus.h" |
Ge van Geldorp | 1a1583a | 2005-11-28 17:32:54 +0100 | [diff] [blame] | 36 | #define WIN32_NO_STATUS |
Eric Pouech | f6a7096 | 2003-06-24 02:32:01 +0000 | [diff] [blame] | 37 | #include "windef.h" |
| 38 | #include "winbase.h" |
| 39 | #include "winternl.h" |
Alexandre Julliard | b592cbb | 2004-05-01 02:44:00 +0000 | [diff] [blame] | 40 | #include "winioctl.h" |
Eric Pouech | 9bd4f6b | 2003-06-26 02:08:17 +0000 | [diff] [blame] | 41 | #include "wincon.h" |
Dimitrie O. Paun | 2eaefbd | 2003-12-08 21:58:55 +0000 | [diff] [blame] | 42 | #include "wine/winbase16.h" |
Eric Pouech | f6a7096 | 2003-06-24 02:32:01 +0000 | [diff] [blame] | 43 | #include "kernel_private.h" |
| 44 | |
Alexandre Julliard | 8f03216 | 2004-03-17 20:57:09 +0000 | [diff] [blame] | 45 | #include "wine/exception.h" |
| 46 | #include "excpt.h" |
Eric Pouech | f6a7096 | 2003-06-24 02:32:01 +0000 | [diff] [blame] | 47 | #include "wine/unicode.h" |
| 48 | #include "wine/debug.h" |
Eric Pouech | 4634447 | 2005-01-14 19:54:38 +0000 | [diff] [blame] | 49 | #include "thread.h" |
| 50 | #include "wine/server.h" |
Eric Pouech | f6a7096 | 2003-06-24 02:32:01 +0000 | [diff] [blame] | 51 | |
| 52 | WINE_DEFAULT_DEBUG_CHANNEL(file); |
| 53 | |
Eric Pouech | 768008f | 2004-01-14 04:34:20 +0000 | [diff] [blame] | 54 | HANDLE dos_handles[DOS_TABLE_SIZE]; |
| 55 | |
Alexandre Julliard | 8f03216 | 2004-03-17 20:57:09 +0000 | [diff] [blame] | 56 | /* info structure for FindFirstFile handle */ |
| 57 | typedef struct |
| 58 | { |
Bernd Schmidt | 60fc242 | 2005-11-01 21:37:05 +0000 | [diff] [blame] | 59 | DWORD magic; /* magic number */ |
| 60 | HANDLE handle; /* handle to directory */ |
| 61 | CRITICAL_SECTION cs; /* crit section protecting this structure */ |
| 62 | FINDEX_SEARCH_OPS search_op; /* Flags passed to FindFirst. */ |
| 63 | UNICODE_STRING mask; /* file mask */ |
| 64 | UNICODE_STRING path; /* NT path used to open the directory */ |
| 65 | BOOL is_root; /* is directory the root of the drive? */ |
| 66 | UINT data_pos; /* current position in dir data */ |
| 67 | UINT data_len; /* length of dir data */ |
| 68 | BYTE data[8192]; /* directory data */ |
Alexandre Julliard | 8f03216 | 2004-03-17 20:57:09 +0000 | [diff] [blame] | 69 | } FIND_FIRST_INFO; |
| 70 | |
Alexandre Julliard | f435914 | 2004-06-15 00:55:04 +0000 | [diff] [blame] | 71 | #define FIND_FIRST_MAGIC 0xc0ffee11 |
| 72 | |
Alexandre Julliard | 0d33e5e | 2004-05-13 20:21:25 +0000 | [diff] [blame] | 73 | static BOOL oem_file_apis; |
Alexandre Julliard | 8f03216 | 2004-03-17 20:57:09 +0000 | [diff] [blame] | 74 | |
Alexandre Julliard | 643617f | 2004-05-01 05:25:07 +0000 | [diff] [blame] | 75 | |
| 76 | /*********************************************************************** |
| 77 | * create_file_OF |
| 78 | * |
| 79 | * Wrapper for CreateFile that takes OF_* mode flags. |
| 80 | */ |
Alexandre Julliard | 2f8fd10 | 2004-05-03 20:20:54 +0000 | [diff] [blame] | 81 | static HANDLE create_file_OF( LPCSTR path, INT mode ) |
Alexandre Julliard | 643617f | 2004-05-01 05:25:07 +0000 | [diff] [blame] | 82 | { |
Alexandre Julliard | 2f8fd10 | 2004-05-03 20:20:54 +0000 | [diff] [blame] | 83 | DWORD access, sharing, creation; |
Alexandre Julliard | 643617f | 2004-05-01 05:25:07 +0000 | [diff] [blame] | 84 | |
Alexandre Julliard | 2f8fd10 | 2004-05-03 20:20:54 +0000 | [diff] [blame] | 85 | if (mode & OF_CREATE) |
Alexandre Julliard | 643617f | 2004-05-01 05:25:07 +0000 | [diff] [blame] | 86 | { |
Alexandre Julliard | 2f8fd10 | 2004-05-03 20:20:54 +0000 | [diff] [blame] | 87 | creation = CREATE_ALWAYS; |
| 88 | access = GENERIC_READ | GENERIC_WRITE; |
Alexandre Julliard | 643617f | 2004-05-01 05:25:07 +0000 | [diff] [blame] | 89 | } |
Alexandre Julliard | 2f8fd10 | 2004-05-03 20:20:54 +0000 | [diff] [blame] | 90 | else |
| 91 | { |
| 92 | creation = OPEN_EXISTING; |
| 93 | switch(mode & 0x03) |
| 94 | { |
| 95 | case OF_READ: access = GENERIC_READ; break; |
| 96 | case OF_WRITE: access = GENERIC_WRITE; break; |
| 97 | case OF_READWRITE: access = GENERIC_READ | GENERIC_WRITE; break; |
| 98 | default: access = 0; break; |
| 99 | } |
| 100 | } |
| 101 | |
Alexandre Julliard | 643617f | 2004-05-01 05:25:07 +0000 | [diff] [blame] | 102 | switch(mode & 0x70) |
| 103 | { |
| 104 | case OF_SHARE_EXCLUSIVE: sharing = 0; break; |
| 105 | case OF_SHARE_DENY_WRITE: sharing = FILE_SHARE_READ; break; |
| 106 | case OF_SHARE_DENY_READ: sharing = FILE_SHARE_WRITE; break; |
| 107 | case OF_SHARE_DENY_NONE: |
| 108 | case OF_SHARE_COMPAT: |
| 109 | default: sharing = FILE_SHARE_READ | FILE_SHARE_WRITE; break; |
| 110 | } |
| 111 | return CreateFileA( path, access, sharing, NULL, creation, FILE_ATTRIBUTE_NORMAL, 0 ); |
| 112 | } |
| 113 | |
| 114 | |
| 115 | /*********************************************************************** |
Alexandre Julliard | a51f2be | 2005-10-26 13:57:45 +0000 | [diff] [blame] | 116 | * check_dir_symlink |
| 117 | * |
| 118 | * Check if a dir symlink should be returned by FindNextFile. |
| 119 | */ |
| 120 | static BOOL check_dir_symlink( FIND_FIRST_INFO *info, const FILE_BOTH_DIR_INFORMATION *file_info ) |
| 121 | { |
| 122 | UNICODE_STRING str; |
| 123 | ANSI_STRING unix_name; |
| 124 | struct stat st, parent_st; |
| 125 | BOOL ret = TRUE; |
| 126 | DWORD len; |
| 127 | |
| 128 | str.MaximumLength = info->path.Length + sizeof(WCHAR) + file_info->FileNameLength; |
| 129 | if (!(str.Buffer = HeapAlloc( GetProcessHeap(), 0, str.MaximumLength ))) return TRUE; |
| 130 | memcpy( str.Buffer, info->path.Buffer, info->path.Length ); |
| 131 | len = info->path.Length / sizeof(WCHAR); |
| 132 | if (!len || str.Buffer[len-1] != '\\') str.Buffer[len++] = '\\'; |
| 133 | memcpy( str.Buffer + len, file_info->FileName, file_info->FileNameLength ); |
| 134 | str.Length = len * sizeof(WCHAR) + file_info->FileNameLength; |
| 135 | |
| 136 | unix_name.Buffer = NULL; |
| 137 | if (!wine_nt_to_unix_file_name( &str, &unix_name, OPEN_EXISTING, FALSE ) && |
| 138 | !stat( unix_name.Buffer, &st )) |
| 139 | { |
| 140 | char *p = unix_name.Buffer + unix_name.Length - 1; |
| 141 | |
| 142 | /* skip trailing slashes */ |
| 143 | while (p > unix_name.Buffer && *p == '/') p--; |
| 144 | |
| 145 | while (ret && p > unix_name.Buffer) |
| 146 | { |
| 147 | while (p > unix_name.Buffer && *p != '/') p--; |
| 148 | while (p > unix_name.Buffer && *p == '/') p--; |
| 149 | p[1] = 0; |
| 150 | if (!stat( unix_name.Buffer, &parent_st ) && |
| 151 | parent_st.st_dev == st.st_dev && |
| 152 | parent_st.st_ino == st.st_ino) |
| 153 | { |
| 154 | WARN( "suppressing dir symlink %s pointing to parent %s\n", |
| 155 | debugstr_wn( str.Buffer, str.Length/sizeof(WCHAR) ), |
| 156 | debugstr_a( unix_name.Buffer )); |
| 157 | ret = FALSE; |
| 158 | } |
| 159 | } |
| 160 | } |
| 161 | RtlFreeAnsiString( &unix_name ); |
| 162 | RtlFreeUnicodeString( &str ); |
| 163 | return ret; |
| 164 | } |
| 165 | |
| 166 | |
| 167 | /*********************************************************************** |
Alexandre Julliard | 643617f | 2004-05-01 05:25:07 +0000 | [diff] [blame] | 168 | * FILE_SetDosError |
| 169 | * |
| 170 | * Set the DOS error code from errno. |
| 171 | */ |
| 172 | void FILE_SetDosError(void) |
| 173 | { |
| 174 | int save_errno = errno; /* errno gets overwritten by printf */ |
| 175 | |
| 176 | TRACE("errno = %d %s\n", errno, strerror(errno)); |
| 177 | switch (save_errno) |
| 178 | { |
| 179 | case EAGAIN: |
| 180 | SetLastError( ERROR_SHARING_VIOLATION ); |
| 181 | break; |
| 182 | case EBADF: |
| 183 | SetLastError( ERROR_INVALID_HANDLE ); |
| 184 | break; |
| 185 | case ENOSPC: |
| 186 | SetLastError( ERROR_HANDLE_DISK_FULL ); |
| 187 | break; |
| 188 | case EACCES: |
| 189 | case EPERM: |
| 190 | case EROFS: |
| 191 | SetLastError( ERROR_ACCESS_DENIED ); |
| 192 | break; |
| 193 | case EBUSY: |
| 194 | SetLastError( ERROR_LOCK_VIOLATION ); |
| 195 | break; |
| 196 | case ENOENT: |
| 197 | SetLastError( ERROR_FILE_NOT_FOUND ); |
| 198 | break; |
| 199 | case EISDIR: |
| 200 | SetLastError( ERROR_CANNOT_MAKE ); |
| 201 | break; |
| 202 | case ENFILE: |
| 203 | case EMFILE: |
| 204 | SetLastError( ERROR_TOO_MANY_OPEN_FILES ); |
| 205 | break; |
| 206 | case EEXIST: |
| 207 | SetLastError( ERROR_FILE_EXISTS ); |
| 208 | break; |
| 209 | case EINVAL: |
| 210 | case ESPIPE: |
| 211 | SetLastError( ERROR_SEEK ); |
| 212 | break; |
| 213 | case ENOTEMPTY: |
| 214 | SetLastError( ERROR_DIR_NOT_EMPTY ); |
| 215 | break; |
| 216 | case ENOEXEC: |
| 217 | SetLastError( ERROR_BAD_FORMAT ); |
| 218 | break; |
| 219 | case ENOTDIR: |
| 220 | SetLastError( ERROR_PATH_NOT_FOUND ); |
| 221 | break; |
| 222 | case EXDEV: |
| 223 | SetLastError( ERROR_NOT_SAME_DEVICE ); |
| 224 | break; |
| 225 | default: |
| 226 | WARN("unknown file error: %s\n", strerror(save_errno) ); |
| 227 | SetLastError( ERROR_GEN_FAILURE ); |
| 228 | break; |
| 229 | } |
| 230 | errno = save_errno; |
| 231 | } |
| 232 | |
| 233 | |
Alexandre Julliard | 0d33e5e | 2004-05-13 20:21:25 +0000 | [diff] [blame] | 234 | /*********************************************************************** |
| 235 | * FILE_name_AtoW |
| 236 | * |
| 237 | * Convert a file name to Unicode, taking into account the OEM/Ansi API mode. |
| 238 | * |
| 239 | * If alloc is FALSE uses the TEB static buffer, so it can only be used when |
| 240 | * there is no possibility for the function to do that twice, taking into |
| 241 | * account any called function. |
| 242 | */ |
| 243 | WCHAR *FILE_name_AtoW( LPCSTR name, BOOL alloc ) |
| 244 | { |
| 245 | ANSI_STRING str; |
| 246 | UNICODE_STRING strW, *pstrW; |
| 247 | NTSTATUS status; |
| 248 | |
| 249 | RtlInitAnsiString( &str, name ); |
| 250 | pstrW = alloc ? &strW : &NtCurrentTeb()->StaticUnicodeString; |
| 251 | if (oem_file_apis) |
| 252 | status = RtlOemStringToUnicodeString( pstrW, &str, alloc ); |
| 253 | else |
| 254 | status = RtlAnsiStringToUnicodeString( pstrW, &str, alloc ); |
| 255 | if (status == STATUS_SUCCESS) return pstrW->Buffer; |
| 256 | |
| 257 | if (status == STATUS_BUFFER_OVERFLOW) |
| 258 | SetLastError( ERROR_FILENAME_EXCED_RANGE ); |
| 259 | else |
| 260 | SetLastError( RtlNtStatusToDosError(status) ); |
| 261 | return NULL; |
| 262 | } |
| 263 | |
| 264 | |
| 265 | /*********************************************************************** |
| 266 | * FILE_name_WtoA |
| 267 | * |
| 268 | * Convert a file name back to OEM/Ansi. Returns number of bytes copied. |
| 269 | */ |
| 270 | DWORD FILE_name_WtoA( LPCWSTR src, INT srclen, LPSTR dest, INT destlen ) |
| 271 | { |
| 272 | DWORD ret; |
| 273 | |
| 274 | if (srclen < 0) srclen = strlenW( src ) + 1; |
| 275 | if (oem_file_apis) |
| 276 | RtlUnicodeToOemN( dest, destlen, &ret, src, srclen * sizeof(WCHAR) ); |
| 277 | else |
| 278 | RtlUnicodeToMultiByteN( dest, destlen, &ret, src, srclen * sizeof(WCHAR) ); |
| 279 | return ret; |
| 280 | } |
| 281 | |
| 282 | |
| 283 | /************************************************************************** |
| 284 | * SetFileApisToOEM (KERNEL32.@) |
| 285 | */ |
| 286 | VOID WINAPI SetFileApisToOEM(void) |
| 287 | { |
| 288 | oem_file_apis = TRUE; |
| 289 | } |
| 290 | |
| 291 | |
| 292 | /************************************************************************** |
| 293 | * SetFileApisToANSI (KERNEL32.@) |
| 294 | */ |
| 295 | VOID WINAPI SetFileApisToANSI(void) |
| 296 | { |
| 297 | oem_file_apis = FALSE; |
| 298 | } |
| 299 | |
| 300 | |
| 301 | /****************************************************************************** |
| 302 | * AreFileApisANSI (KERNEL32.@) |
| 303 | * |
| 304 | * Determines if file functions are using ANSI |
| 305 | * |
| 306 | * RETURNS |
| 307 | * TRUE: Set of file functions is using ANSI code page |
| 308 | * FALSE: Set of file functions is using OEM code page |
| 309 | */ |
| 310 | BOOL WINAPI AreFileApisANSI(void) |
| 311 | { |
| 312 | return !oem_file_apis; |
| 313 | } |
| 314 | |
| 315 | |
Eric Pouech | f6a7096 | 2003-06-24 02:32:01 +0000 | [diff] [blame] | 316 | /************************************************************************** |
| 317 | * Operations on file handles * |
| 318 | **************************************************************************/ |
| 319 | |
| 320 | /*********************************************************************** |
Eric Pouech | 768008f | 2004-01-14 04:34:20 +0000 | [diff] [blame] | 321 | * FILE_InitProcessDosHandles |
| 322 | * |
| 323 | * Allocates the default DOS handles for a process. Called either by |
| 324 | * Win32HandleToDosFileHandle below or by the DOSVM stuff. |
| 325 | */ |
| 326 | static void FILE_InitProcessDosHandles( void ) |
| 327 | { |
| 328 | static BOOL init_done /* = FALSE */; |
| 329 | HANDLE cp = GetCurrentProcess(); |
| 330 | |
| 331 | if (init_done) return; |
| 332 | init_done = TRUE; |
| 333 | DuplicateHandle(cp, GetStdHandle(STD_INPUT_HANDLE), cp, &dos_handles[0], |
| 334 | 0, TRUE, DUPLICATE_SAME_ACCESS); |
| 335 | DuplicateHandle(cp, GetStdHandle(STD_OUTPUT_HANDLE), cp, &dos_handles[1], |
| 336 | 0, TRUE, DUPLICATE_SAME_ACCESS); |
| 337 | DuplicateHandle(cp, GetStdHandle(STD_ERROR_HANDLE), cp, &dos_handles[2], |
| 338 | 0, TRUE, DUPLICATE_SAME_ACCESS); |
| 339 | DuplicateHandle(cp, GetStdHandle(STD_ERROR_HANDLE), cp, &dos_handles[3], |
| 340 | 0, TRUE, DUPLICATE_SAME_ACCESS); |
| 341 | DuplicateHandle(cp, GetStdHandle(STD_ERROR_HANDLE), cp, &dos_handles[4], |
| 342 | 0, TRUE, DUPLICATE_SAME_ACCESS); |
| 343 | } |
| 344 | |
| 345 | |
Alexandre Julliard | 643617f | 2004-05-01 05:25:07 +0000 | [diff] [blame] | 346 | /****************************************************************** |
| 347 | * FILE_ReadWriteApc (internal) |
| 348 | */ |
| 349 | static void WINAPI FILE_ReadWriteApc(void* apc_user, PIO_STATUS_BLOCK io_status, ULONG len) |
| 350 | { |
| 351 | LPOVERLAPPED_COMPLETION_ROUTINE cr = (LPOVERLAPPED_COMPLETION_ROUTINE)apc_user; |
| 352 | |
| 353 | cr(RtlNtStatusToDosError(io_status->u.Status), len, (LPOVERLAPPED)io_status); |
| 354 | } |
| 355 | |
| 356 | |
| 357 | /*********************************************************************** |
| 358 | * ReadFileEx (KERNEL32.@) |
| 359 | */ |
| 360 | BOOL WINAPI ReadFileEx(HANDLE hFile, LPVOID buffer, DWORD bytesToRead, |
| 361 | LPOVERLAPPED overlapped, |
| 362 | LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine) |
| 363 | { |
| 364 | LARGE_INTEGER offset; |
| 365 | NTSTATUS status; |
| 366 | PIO_STATUS_BLOCK io_status; |
| 367 | |
Rob Shearman | 95dc472 | 2004-07-09 22:24:59 +0000 | [diff] [blame] | 368 | TRACE("(hFile=%p, buffer=%p, bytes=%lu, ovl=%p, ovl_fn=%p)\n", hFile, buffer, bytesToRead, overlapped, lpCompletionRoutine); |
| 369 | |
Alexandre Julliard | 643617f | 2004-05-01 05:25:07 +0000 | [diff] [blame] | 370 | if (!overlapped) |
| 371 | { |
| 372 | SetLastError(ERROR_INVALID_PARAMETER); |
| 373 | return FALSE; |
| 374 | } |
| 375 | |
Dmitry Timoshkov | 75b93ff | 2005-03-17 19:00:08 +0000 | [diff] [blame] | 376 | offset.u.LowPart = overlapped->u.s.Offset; |
| 377 | offset.u.HighPart = overlapped->u.s.OffsetHigh; |
Alexandre Julliard | 643617f | 2004-05-01 05:25:07 +0000 | [diff] [blame] | 378 | io_status = (PIO_STATUS_BLOCK)overlapped; |
| 379 | io_status->u.Status = STATUS_PENDING; |
| 380 | |
| 381 | status = NtReadFile(hFile, NULL, FILE_ReadWriteApc, lpCompletionRoutine, |
| 382 | io_status, buffer, bytesToRead, &offset, NULL); |
| 383 | |
| 384 | if (status) |
| 385 | { |
| 386 | SetLastError( RtlNtStatusToDosError(status) ); |
| 387 | return FALSE; |
| 388 | } |
| 389 | return TRUE; |
| 390 | } |
| 391 | |
| 392 | |
| 393 | /*********************************************************************** |
| 394 | * ReadFile (KERNEL32.@) |
| 395 | */ |
| 396 | BOOL WINAPI ReadFile( HANDLE hFile, LPVOID buffer, DWORD bytesToRead, |
| 397 | LPDWORD bytesRead, LPOVERLAPPED overlapped ) |
| 398 | { |
| 399 | LARGE_INTEGER offset; |
| 400 | PLARGE_INTEGER poffset = NULL; |
| 401 | IO_STATUS_BLOCK iosb; |
| 402 | PIO_STATUS_BLOCK io_status = &iosb; |
| 403 | HANDLE hEvent = 0; |
| 404 | NTSTATUS status; |
| 405 | |
| 406 | TRACE("%p %p %ld %p %p\n", hFile, buffer, bytesToRead, |
| 407 | bytesRead, overlapped ); |
| 408 | |
| 409 | if (bytesRead) *bytesRead = 0; /* Do this before anything else */ |
| 410 | if (!bytesToRead) return TRUE; |
| 411 | |
Alexandre Julliard | 643617f | 2004-05-01 05:25:07 +0000 | [diff] [blame] | 412 | if (is_console_handle(hFile)) |
| 413 | return ReadConsoleA(hFile, buffer, bytesToRead, bytesRead, NULL); |
| 414 | |
| 415 | if (overlapped != NULL) |
| 416 | { |
Dmitry Timoshkov | 75b93ff | 2005-03-17 19:00:08 +0000 | [diff] [blame] | 417 | offset.u.LowPart = overlapped->u.s.Offset; |
| 418 | offset.u.HighPart = overlapped->u.s.OffsetHigh; |
Alexandre Julliard | 643617f | 2004-05-01 05:25:07 +0000 | [diff] [blame] | 419 | poffset = &offset; |
| 420 | hEvent = overlapped->hEvent; |
| 421 | io_status = (PIO_STATUS_BLOCK)overlapped; |
| 422 | } |
| 423 | io_status->u.Status = STATUS_PENDING; |
| 424 | io_status->Information = 0; |
| 425 | |
| 426 | status = NtReadFile(hFile, hEvent, NULL, NULL, io_status, buffer, bytesToRead, poffset, NULL); |
| 427 | |
| 428 | if (status != STATUS_PENDING && bytesRead) |
| 429 | *bytesRead = io_status->Information; |
| 430 | |
Uwe Bonnes | 52978f6 | 2005-07-11 14:23:46 +0000 | [diff] [blame] | 431 | if (status && status != STATUS_END_OF_FILE && status != STATUS_TIMEOUT) |
Alexandre Julliard | 643617f | 2004-05-01 05:25:07 +0000 | [diff] [blame] | 432 | { |
| 433 | SetLastError( RtlNtStatusToDosError(status) ); |
| 434 | return FALSE; |
| 435 | } |
| 436 | return TRUE; |
| 437 | } |
| 438 | |
| 439 | |
| 440 | /*********************************************************************** |
| 441 | * WriteFileEx (KERNEL32.@) |
| 442 | */ |
| 443 | BOOL WINAPI WriteFileEx(HANDLE hFile, LPCVOID buffer, DWORD bytesToWrite, |
| 444 | LPOVERLAPPED overlapped, |
| 445 | LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine) |
| 446 | { |
| 447 | LARGE_INTEGER offset; |
| 448 | NTSTATUS status; |
| 449 | PIO_STATUS_BLOCK io_status; |
| 450 | |
| 451 | TRACE("%p %p %ld %p %p\n", hFile, buffer, bytesToWrite, overlapped, lpCompletionRoutine); |
| 452 | |
| 453 | if (overlapped == NULL) |
| 454 | { |
| 455 | SetLastError(ERROR_INVALID_PARAMETER); |
| 456 | return FALSE; |
| 457 | } |
Dmitry Timoshkov | 75b93ff | 2005-03-17 19:00:08 +0000 | [diff] [blame] | 458 | offset.u.LowPart = overlapped->u.s.Offset; |
| 459 | offset.u.HighPart = overlapped->u.s.OffsetHigh; |
Alexandre Julliard | 643617f | 2004-05-01 05:25:07 +0000 | [diff] [blame] | 460 | |
| 461 | io_status = (PIO_STATUS_BLOCK)overlapped; |
| 462 | io_status->u.Status = STATUS_PENDING; |
| 463 | |
| 464 | status = NtWriteFile(hFile, NULL, FILE_ReadWriteApc, lpCompletionRoutine, |
| 465 | io_status, buffer, bytesToWrite, &offset, NULL); |
| 466 | |
| 467 | if (status) SetLastError( RtlNtStatusToDosError(status) ); |
| 468 | return !status; |
| 469 | } |
| 470 | |
| 471 | |
| 472 | /*********************************************************************** |
| 473 | * WriteFile (KERNEL32.@) |
| 474 | */ |
| 475 | BOOL WINAPI WriteFile( HANDLE hFile, LPCVOID buffer, DWORD bytesToWrite, |
| 476 | LPDWORD bytesWritten, LPOVERLAPPED overlapped ) |
| 477 | { |
| 478 | HANDLE hEvent = NULL; |
| 479 | LARGE_INTEGER offset; |
| 480 | PLARGE_INTEGER poffset = NULL; |
| 481 | NTSTATUS status; |
| 482 | IO_STATUS_BLOCK iosb; |
| 483 | PIO_STATUS_BLOCK piosb = &iosb; |
| 484 | |
| 485 | TRACE("%p %p %ld %p %p\n", hFile, buffer, bytesToWrite, bytesWritten, overlapped ); |
| 486 | |
| 487 | if (is_console_handle(hFile)) |
| 488 | return WriteConsoleA(hFile, buffer, bytesToWrite, bytesWritten, NULL); |
| 489 | |
Alexandre Julliard | 643617f | 2004-05-01 05:25:07 +0000 | [diff] [blame] | 490 | if (overlapped) |
| 491 | { |
Dmitry Timoshkov | 75b93ff | 2005-03-17 19:00:08 +0000 | [diff] [blame] | 492 | offset.u.LowPart = overlapped->u.s.Offset; |
| 493 | offset.u.HighPart = overlapped->u.s.OffsetHigh; |
Alexandre Julliard | 643617f | 2004-05-01 05:25:07 +0000 | [diff] [blame] | 494 | poffset = &offset; |
| 495 | hEvent = overlapped->hEvent; |
| 496 | piosb = (PIO_STATUS_BLOCK)overlapped; |
| 497 | } |
| 498 | piosb->u.Status = STATUS_PENDING; |
| 499 | piosb->Information = 0; |
| 500 | |
| 501 | status = NtWriteFile(hFile, hEvent, NULL, NULL, piosb, |
| 502 | buffer, bytesToWrite, poffset, NULL); |
Dmitry Timoshkov | e04da6b | 2004-11-28 14:58:11 +0000 | [diff] [blame] | 503 | |
Rein Klazes | 8481c8d | 2005-05-24 12:50:24 +0000 | [diff] [blame] | 504 | /* FIXME: NtWriteFile does not always cause page faults, generate them now */ |
| 505 | if (status == STATUS_INVALID_USER_BUFFER && !IsBadReadPtr( buffer, bytesToWrite )) |
| 506 | { |
| 507 | status = NtWriteFile(hFile, hEvent, NULL, NULL, piosb, |
| 508 | buffer, bytesToWrite, poffset, NULL); |
| 509 | if (status != STATUS_INVALID_USER_BUFFER) |
| 510 | FIXME("Could not access memory (%p,%ld) at first, now OK. Protected by DIBSection code?\n", |
| 511 | buffer, bytesToWrite); |
| 512 | } |
| 513 | |
Dmitry Timoshkov | e04da6b | 2004-11-28 14:58:11 +0000 | [diff] [blame] | 514 | if (status != STATUS_PENDING && bytesWritten) |
| 515 | *bytesWritten = piosb->Information; |
| 516 | |
Uwe Bonnes | 52978f6 | 2005-07-11 14:23:46 +0000 | [diff] [blame] | 517 | if (status && status != STATUS_TIMEOUT) |
Alexandre Julliard | 643617f | 2004-05-01 05:25:07 +0000 | [diff] [blame] | 518 | { |
| 519 | SetLastError( RtlNtStatusToDosError(status) ); |
| 520 | return FALSE; |
| 521 | } |
Alexandre Julliard | 643617f | 2004-05-01 05:25:07 +0000 | [diff] [blame] | 522 | return TRUE; |
| 523 | } |
| 524 | |
| 525 | |
Eric Pouech | 768008f | 2004-01-14 04:34:20 +0000 | [diff] [blame] | 526 | /*********************************************************************** |
Eric Pouech | 9bd4f6b | 2003-06-26 02:08:17 +0000 | [diff] [blame] | 527 | * GetOverlappedResult (KERNEL32.@) |
| 528 | * |
| 529 | * Check the result of an Asynchronous data transfer from a file. |
| 530 | * |
| 531 | * Parameters |
| 532 | * HANDLE hFile [in] handle of file to check on |
| 533 | * LPOVERLAPPED lpOverlapped [in/out] pointer to overlapped |
| 534 | * LPDWORD lpTransferred [in/out] number of bytes transferred |
| 535 | * BOOL bWait [in] wait for the transfer to complete ? |
| 536 | * |
| 537 | * RETURNS |
| 538 | * TRUE on success |
| 539 | * FALSE on failure |
| 540 | * |
| 541 | * If successful (and relevant) lpTransferred will hold the number of |
| 542 | * bytes transferred during the async operation. |
| 543 | * |
| 544 | * BUGS |
| 545 | * |
| 546 | * Currently only works for WaitCommEvent, ReadFile, WriteFile |
| 547 | * with communications ports. |
| 548 | * |
| 549 | */ |
| 550 | BOOL WINAPI GetOverlappedResult(HANDLE hFile, LPOVERLAPPED lpOverlapped, |
| 551 | LPDWORD lpTransferred, BOOL bWait) |
| 552 | { |
Eric Pouech | 1ffddb4 | 2004-08-17 23:37:55 +0000 | [diff] [blame] | 553 | DWORD r = WAIT_OBJECT_0; |
Eric Pouech | 9bd4f6b | 2003-06-26 02:08:17 +0000 | [diff] [blame] | 554 | |
Eric Pouech | 1ffddb4 | 2004-08-17 23:37:55 +0000 | [diff] [blame] | 555 | TRACE( "(%p %p %p %x)\n", hFile, lpOverlapped, lpTransferred, bWait ); |
Eric Pouech | 9bd4f6b | 2003-06-26 02:08:17 +0000 | [diff] [blame] | 556 | |
Eric Pouech | 1ffddb4 | 2004-08-17 23:37:55 +0000 | [diff] [blame] | 557 | if ( lpOverlapped == NULL ) |
Eric Pouech | 9bd4f6b | 2003-06-26 02:08:17 +0000 | [diff] [blame] | 558 | { |
| 559 | ERR("lpOverlapped was null\n"); |
| 560 | return FALSE; |
| 561 | } |
Eric Pouech | 9bd4f6b | 2003-06-26 02:08:17 +0000 | [diff] [blame] | 562 | if ( bWait ) |
| 563 | { |
Eric Pouech | 1ffddb4 | 2004-08-17 23:37:55 +0000 | [diff] [blame] | 564 | if ( lpOverlapped->hEvent ) |
| 565 | { |
| 566 | do |
| 567 | { |
| 568 | TRACE( "waiting on %p\n", lpOverlapped ); |
| 569 | r = WaitForSingleObjectEx( lpOverlapped->hEvent, INFINITE, TRUE ); |
| 570 | TRACE( "wait on %p returned %ld\n", lpOverlapped, r ); |
| 571 | } while ( r == WAIT_IO_COMPLETION ); |
| 572 | } |
| 573 | else |
| 574 | { |
| 575 | /* busy loop */ |
Eric Pouech | 4634447 | 2005-01-14 19:54:38 +0000 | [diff] [blame] | 576 | while ( ((volatile OVERLAPPED*)lpOverlapped)->Internal == STATUS_PENDING ) |
Eric Pouech | 1ffddb4 | 2004-08-17 23:37:55 +0000 | [diff] [blame] | 577 | Sleep( 10 ); |
| 578 | } |
Eric Pouech | 9bd4f6b | 2003-06-26 02:08:17 +0000 | [diff] [blame] | 579 | } |
| 580 | else if ( lpOverlapped->Internal == STATUS_PENDING ) |
| 581 | { |
| 582 | /* Wait in order to give APCs a chance to run. */ |
| 583 | /* This is cheating, so we must set the event again in case of success - |
| 584 | it may be a non-manual reset event. */ |
Eric Pouech | 1ffddb4 | 2004-08-17 23:37:55 +0000 | [diff] [blame] | 585 | do |
| 586 | { |
| 587 | TRACE( "waiting on %p\n", lpOverlapped ); |
| 588 | r = WaitForSingleObjectEx( lpOverlapped->hEvent, 0, TRUE ); |
| 589 | TRACE( "wait on %p returned %ld\n", lpOverlapped, r ); |
| 590 | } while ( r == WAIT_IO_COMPLETION ); |
| 591 | if ( r == WAIT_OBJECT_0 && lpOverlapped->hEvent ) |
| 592 | NtSetEvent( lpOverlapped->hEvent, NULL ); |
Eric Pouech | 9bd4f6b | 2003-06-26 02:08:17 +0000 | [diff] [blame] | 593 | } |
Eric Pouech | 1ffddb4 | 2004-08-17 23:37:55 +0000 | [diff] [blame] | 594 | if ( r == WAIT_FAILED ) |
| 595 | { |
Eric Pouech | 4634447 | 2005-01-14 19:54:38 +0000 | [diff] [blame] | 596 | WARN("wait operation failed\n"); |
Eric Pouech | 1ffddb4 | 2004-08-17 23:37:55 +0000 | [diff] [blame] | 597 | return FALSE; |
| 598 | } |
| 599 | if (lpTransferred) *lpTransferred = lpOverlapped->InternalHigh; |
Eric Pouech | 9bd4f6b | 2003-06-26 02:08:17 +0000 | [diff] [blame] | 600 | |
| 601 | switch ( lpOverlapped->Internal ) |
| 602 | { |
| 603 | case STATUS_SUCCESS: |
| 604 | return TRUE; |
| 605 | case STATUS_PENDING: |
Eric Pouech | 1ffddb4 | 2004-08-17 23:37:55 +0000 | [diff] [blame] | 606 | SetLastError( ERROR_IO_INCOMPLETE ); |
| 607 | if ( bWait ) ERR("PENDING status after waiting!\n"); |
Eric Pouech | 9bd4f6b | 2003-06-26 02:08:17 +0000 | [diff] [blame] | 608 | return FALSE; |
| 609 | default: |
Eric Pouech | 1ffddb4 | 2004-08-17 23:37:55 +0000 | [diff] [blame] | 610 | SetLastError( RtlNtStatusToDosError( lpOverlapped->Internal ) ); |
Eric Pouech | 9bd4f6b | 2003-06-26 02:08:17 +0000 | [diff] [blame] | 611 | return FALSE; |
| 612 | } |
| 613 | } |
| 614 | |
| 615 | /*********************************************************************** |
| 616 | * CancelIo (KERNEL32.@) |
Robert Shearman | 277dfb8 | 2006-04-03 16:26:10 +0100 | [diff] [blame] | 617 | * |
| 618 | * Cancels pending I/O operations initiated by the current thread on a file. |
| 619 | * |
| 620 | * PARAMS |
| 621 | * handle [I] File handle. |
| 622 | * |
| 623 | * RETURNS |
| 624 | * Success: TRUE. |
| 625 | * Failure: FALSE, check GetLastError(). |
Eric Pouech | 9bd4f6b | 2003-06-26 02:08:17 +0000 | [diff] [blame] | 626 | */ |
| 627 | BOOL WINAPI CancelIo(HANDLE handle) |
| 628 | { |
Eric Pouech | 4634447 | 2005-01-14 19:54:38 +0000 | [diff] [blame] | 629 | IO_STATUS_BLOCK io_status; |
Eric Pouech | 9bd4f6b | 2003-06-26 02:08:17 +0000 | [diff] [blame] | 630 | |
Eric Pouech | 4634447 | 2005-01-14 19:54:38 +0000 | [diff] [blame] | 631 | NtCancelIoFile(handle, &io_status); |
| 632 | if (io_status.u.Status) |
Eric Pouech | 9bd4f6b | 2003-06-26 02:08:17 +0000 | [diff] [blame] | 633 | { |
Eric Pouech | 4634447 | 2005-01-14 19:54:38 +0000 | [diff] [blame] | 634 | SetLastError( RtlNtStatusToDosError( io_status.u.Status ) ); |
| 635 | return FALSE; |
Eric Pouech | 9bd4f6b | 2003-06-26 02:08:17 +0000 | [diff] [blame] | 636 | } |
Eric Pouech | 9bd4f6b | 2003-06-26 02:08:17 +0000 | [diff] [blame] | 637 | return TRUE; |
| 638 | } |
| 639 | |
| 640 | /*********************************************************************** |
Eric Pouech | f6a7096 | 2003-06-24 02:32:01 +0000 | [diff] [blame] | 641 | * _hread (KERNEL32.@) |
| 642 | */ |
| 643 | LONG WINAPI _hread( HFILE hFile, LPVOID buffer, LONG count) |
| 644 | { |
| 645 | return _lread( hFile, buffer, count ); |
| 646 | } |
| 647 | |
| 648 | |
| 649 | /*********************************************************************** |
| 650 | * _hwrite (KERNEL32.@) |
| 651 | * |
| 652 | * experimentation yields that _lwrite: |
| 653 | * o truncates the file at the current position with |
| 654 | * a 0 len write |
| 655 | * o returns 0 on a 0 length write |
| 656 | * o works with console handles |
| 657 | * |
| 658 | */ |
| 659 | LONG WINAPI _hwrite( HFILE handle, LPCSTR buffer, LONG count ) |
| 660 | { |
| 661 | DWORD result; |
| 662 | |
| 663 | TRACE("%d %p %ld\n", handle, buffer, count ); |
| 664 | |
| 665 | if (!count) |
| 666 | { |
| 667 | /* Expand or truncate at current position */ |
| 668 | if (!SetEndOfFile( (HANDLE)handle )) return HFILE_ERROR; |
| 669 | return 0; |
| 670 | } |
| 671 | if (!WriteFile( (HANDLE)handle, buffer, count, &result, NULL )) |
| 672 | return HFILE_ERROR; |
| 673 | return result; |
| 674 | } |
| 675 | |
| 676 | |
| 677 | /*********************************************************************** |
| 678 | * _lclose (KERNEL32.@) |
| 679 | */ |
| 680 | HFILE WINAPI _lclose( HFILE hFile ) |
| 681 | { |
| 682 | TRACE("handle %d\n", hFile ); |
| 683 | return CloseHandle( (HANDLE)hFile ) ? 0 : HFILE_ERROR; |
| 684 | } |
| 685 | |
| 686 | |
| 687 | /*********************************************************************** |
| 688 | * _lcreat (KERNEL32.@) |
| 689 | */ |
| 690 | HFILE WINAPI _lcreat( LPCSTR path, INT attr ) |
| 691 | { |
| 692 | /* Mask off all flags not explicitly allowed by the doc */ |
| 693 | attr &= FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM; |
| 694 | TRACE("%s %02x\n", path, attr ); |
| 695 | return (HFILE)CreateFileA( path, GENERIC_READ | GENERIC_WRITE, |
| 696 | FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, |
| 697 | CREATE_ALWAYS, attr, 0 ); |
| 698 | } |
| 699 | |
| 700 | |
| 701 | /*********************************************************************** |
| 702 | * _lopen (KERNEL32.@) |
| 703 | */ |
| 704 | HFILE WINAPI _lopen( LPCSTR path, INT mode ) |
| 705 | { |
Alexandre Julliard | 643617f | 2004-05-01 05:25:07 +0000 | [diff] [blame] | 706 | TRACE("(%s,%04x)\n", debugstr_a(path), mode ); |
Alexandre Julliard | 2f8fd10 | 2004-05-03 20:20:54 +0000 | [diff] [blame] | 707 | return (HFILE)create_file_OF( path, mode & ~OF_CREATE ); |
Eric Pouech | f6a7096 | 2003-06-24 02:32:01 +0000 | [diff] [blame] | 708 | } |
| 709 | |
Eric Pouech | f6a7096 | 2003-06-24 02:32:01 +0000 | [diff] [blame] | 710 | /*********************************************************************** |
| 711 | * _lread (KERNEL32.@) |
| 712 | */ |
| 713 | UINT WINAPI _lread( HFILE handle, LPVOID buffer, UINT count ) |
| 714 | { |
| 715 | DWORD result; |
Francois Gouget | 1614f91 | 2004-01-16 21:23:32 +0000 | [diff] [blame] | 716 | if (!ReadFile( (HANDLE)handle, buffer, count, &result, NULL )) |
| 717 | return HFILE_ERROR; |
Eric Pouech | f6a7096 | 2003-06-24 02:32:01 +0000 | [diff] [blame] | 718 | return result; |
| 719 | } |
| 720 | |
| 721 | |
| 722 | /*********************************************************************** |
| 723 | * _llseek (KERNEL32.@) |
| 724 | */ |
| 725 | LONG WINAPI _llseek( HFILE hFile, LONG lOffset, INT nOrigin ) |
| 726 | { |
| 727 | return SetFilePointer( (HANDLE)hFile, lOffset, NULL, nOrigin ); |
| 728 | } |
| 729 | |
| 730 | |
| 731 | /*********************************************************************** |
| 732 | * _lwrite (KERNEL32.@) |
| 733 | */ |
| 734 | UINT WINAPI _lwrite( HFILE hFile, LPCSTR buffer, UINT count ) |
| 735 | { |
| 736 | return (UINT)_hwrite( hFile, buffer, (LONG)count ); |
| 737 | } |
| 738 | |
| 739 | |
| 740 | /*********************************************************************** |
| 741 | * FlushFileBuffers (KERNEL32.@) |
| 742 | */ |
| 743 | BOOL WINAPI FlushFileBuffers( HANDLE hFile ) |
| 744 | { |
| 745 | NTSTATUS nts; |
| 746 | IO_STATUS_BLOCK ioblk; |
| 747 | |
| 748 | if (is_console_handle( hFile )) |
| 749 | { |
| 750 | /* this will fail (as expected) for an output handle */ |
Dmitry Timoshkov | a8f025f | 2004-12-22 14:51:46 +0000 | [diff] [blame] | 751 | return FlushConsoleInputBuffer( hFile ); |
Eric Pouech | f6a7096 | 2003-06-24 02:32:01 +0000 | [diff] [blame] | 752 | } |
| 753 | nts = NtFlushBuffersFile( hFile, &ioblk ); |
| 754 | if (nts != STATUS_SUCCESS) |
| 755 | { |
| 756 | SetLastError( RtlNtStatusToDosError( nts ) ); |
| 757 | return FALSE; |
| 758 | } |
| 759 | |
| 760 | return TRUE; |
| 761 | } |
| 762 | |
| 763 | |
| 764 | /*********************************************************************** |
Alexandre Julliard | b592cbb | 2004-05-01 02:44:00 +0000 | [diff] [blame] | 765 | * GetFileType (KERNEL32.@) |
| 766 | */ |
| 767 | DWORD WINAPI GetFileType( HANDLE hFile ) |
| 768 | { |
| 769 | FILE_FS_DEVICE_INFORMATION info; |
| 770 | IO_STATUS_BLOCK io; |
| 771 | NTSTATUS status; |
| 772 | |
| 773 | if (is_console_handle( hFile )) return FILE_TYPE_CHAR; |
| 774 | |
| 775 | status = NtQueryVolumeInformationFile( hFile, &io, &info, sizeof(info), FileFsDeviceInformation ); |
| 776 | if (status != STATUS_SUCCESS) |
| 777 | { |
| 778 | SetLastError( RtlNtStatusToDosError(status) ); |
| 779 | return FILE_TYPE_UNKNOWN; |
| 780 | } |
| 781 | |
| 782 | switch(info.DeviceType) |
| 783 | { |
| 784 | case FILE_DEVICE_NULL: |
| 785 | case FILE_DEVICE_SERIAL_PORT: |
| 786 | case FILE_DEVICE_PARALLEL_PORT: |
Hans Leidekker | e0de496 | 2006-02-13 13:22:34 +0100 | [diff] [blame] | 787 | case FILE_DEVICE_TAPE: |
Alexandre Julliard | b592cbb | 2004-05-01 02:44:00 +0000 | [diff] [blame] | 788 | case FILE_DEVICE_UNKNOWN: |
| 789 | return FILE_TYPE_CHAR; |
| 790 | case FILE_DEVICE_NAMED_PIPE: |
| 791 | return FILE_TYPE_PIPE; |
| 792 | default: |
| 793 | return FILE_TYPE_DISK; |
| 794 | } |
| 795 | } |
| 796 | |
| 797 | |
| 798 | /*********************************************************************** |
Alexandre Julliard | d4874d6 | 2004-04-30 21:03:09 +0000 | [diff] [blame] | 799 | * GetFileInformationByHandle (KERNEL32.@) |
| 800 | */ |
| 801 | BOOL WINAPI GetFileInformationByHandle( HANDLE hFile, BY_HANDLE_FILE_INFORMATION *info ) |
| 802 | { |
| 803 | FILE_ALL_INFORMATION all_info; |
| 804 | IO_STATUS_BLOCK io; |
| 805 | NTSTATUS status; |
| 806 | |
| 807 | status = NtQueryInformationFile( hFile, &io, &all_info, sizeof(all_info), FileAllInformation ); |
| 808 | if (status == STATUS_SUCCESS) |
| 809 | { |
| 810 | info->dwFileAttributes = all_info.BasicInformation.FileAttributes; |
| 811 | info->ftCreationTime.dwHighDateTime = all_info.BasicInformation.CreationTime.u.HighPart; |
| 812 | info->ftCreationTime.dwLowDateTime = all_info.BasicInformation.CreationTime.u.LowPart; |
| 813 | info->ftLastAccessTime.dwHighDateTime = all_info.BasicInformation.LastAccessTime.u.HighPart; |
| 814 | info->ftLastAccessTime.dwLowDateTime = all_info.BasicInformation.LastAccessTime.u.LowPart; |
| 815 | info->ftLastWriteTime.dwHighDateTime = all_info.BasicInformation.LastWriteTime.u.HighPart; |
| 816 | info->ftLastWriteTime.dwLowDateTime = all_info.BasicInformation.LastWriteTime.u.LowPart; |
| 817 | info->dwVolumeSerialNumber = 0; /* FIXME */ |
| 818 | info->nFileSizeHigh = all_info.StandardInformation.EndOfFile.u.HighPart; |
| 819 | info->nFileSizeLow = all_info.StandardInformation.EndOfFile.u.LowPart; |
| 820 | info->nNumberOfLinks = all_info.StandardInformation.NumberOfLinks; |
| 821 | info->nFileIndexHigh = all_info.InternalInformation.IndexNumber.u.HighPart; |
| 822 | info->nFileIndexLow = all_info.InternalInformation.IndexNumber.u.LowPart; |
| 823 | return TRUE; |
| 824 | } |
| 825 | SetLastError( RtlNtStatusToDosError(status) ); |
| 826 | return FALSE; |
| 827 | } |
| 828 | |
| 829 | |
| 830 | /*********************************************************************** |
Eric Pouech | f6a7096 | 2003-06-24 02:32:01 +0000 | [diff] [blame] | 831 | * GetFileSize (KERNEL32.@) |
Robert Shearman | 277dfb8 | 2006-04-03 16:26:10 +0100 | [diff] [blame] | 832 | * |
| 833 | * Retrieve the size of a file. |
| 834 | * |
| 835 | * PARAMS |
| 836 | * hFile [I] File to retrieve size of. |
| 837 | * filesizehigh [O] On return, the high bits of the file size. |
| 838 | * |
| 839 | * RETURNS |
| 840 | * Success: The low bits of the file size. |
| 841 | * Failure: INVALID_FILE_SIZE. As this is could also be a success value, |
| 842 | * check GetLastError() for values other than ERROR_SUCCESS. |
Eric Pouech | f6a7096 | 2003-06-24 02:32:01 +0000 | [diff] [blame] | 843 | */ |
| 844 | DWORD WINAPI GetFileSize( HANDLE hFile, LPDWORD filesizehigh ) |
| 845 | { |
Alexandre Julliard | d4874d6 | 2004-04-30 21:03:09 +0000 | [diff] [blame] | 846 | LARGE_INTEGER size; |
| 847 | if (!GetFileSizeEx( hFile, &size )) return INVALID_FILE_SIZE; |
| 848 | if (filesizehigh) *filesizehigh = size.u.HighPart; |
| 849 | if (size.u.LowPart == INVALID_FILE_SIZE) SetLastError(0); |
| 850 | return size.u.LowPart; |
Eric Pouech | f6a7096 | 2003-06-24 02:32:01 +0000 | [diff] [blame] | 851 | } |
| 852 | |
| 853 | |
| 854 | /*********************************************************************** |
| 855 | * GetFileSizeEx (KERNEL32.@) |
Robert Shearman | 277dfb8 | 2006-04-03 16:26:10 +0100 | [diff] [blame] | 856 | * |
| 857 | * Retrieve the size of a file. |
| 858 | * |
| 859 | * PARAMS |
| 860 | * hFile [I] File to retrieve size of. |
| 861 | * lpFileSIze [O] On return, the size of the file. |
| 862 | * |
| 863 | * RETURNS |
| 864 | * Success: TRUE. |
| 865 | * Failure: FALSE, check GetLastError(). |
Eric Pouech | f6a7096 | 2003-06-24 02:32:01 +0000 | [diff] [blame] | 866 | */ |
| 867 | BOOL WINAPI GetFileSizeEx( HANDLE hFile, PLARGE_INTEGER lpFileSize ) |
| 868 | { |
Alexandre Julliard | d4874d6 | 2004-04-30 21:03:09 +0000 | [diff] [blame] | 869 | FILE_END_OF_FILE_INFORMATION info; |
| 870 | IO_STATUS_BLOCK io; |
| 871 | NTSTATUS status; |
Eric Pouech | f6a7096 | 2003-06-24 02:32:01 +0000 | [diff] [blame] | 872 | |
Alexandre Julliard | d4874d6 | 2004-04-30 21:03:09 +0000 | [diff] [blame] | 873 | status = NtQueryInformationFile( hFile, &io, &info, sizeof(info), FileEndOfFileInformation ); |
| 874 | if (status == STATUS_SUCCESS) |
Eric Pouech | f6a7096 | 2003-06-24 02:32:01 +0000 | [diff] [blame] | 875 | { |
Alexandre Julliard | d4874d6 | 2004-04-30 21:03:09 +0000 | [diff] [blame] | 876 | *lpFileSize = info.EndOfFile; |
| 877 | return TRUE; |
Eric Pouech | f6a7096 | 2003-06-24 02:32:01 +0000 | [diff] [blame] | 878 | } |
Alexandre Julliard | d4874d6 | 2004-04-30 21:03:09 +0000 | [diff] [blame] | 879 | SetLastError( RtlNtStatusToDosError(status) ); |
| 880 | return FALSE; |
| 881 | } |
Eric Pouech | f6a7096 | 2003-06-24 02:32:01 +0000 | [diff] [blame] | 882 | |
Alexandre Julliard | d4874d6 | 2004-04-30 21:03:09 +0000 | [diff] [blame] | 883 | |
Alexandre Julliard | b592cbb | 2004-05-01 02:44:00 +0000 | [diff] [blame] | 884 | /************************************************************************** |
| 885 | * SetEndOfFile (KERNEL32.@) |
Robert Shearman | 277dfb8 | 2006-04-03 16:26:10 +0100 | [diff] [blame] | 886 | * |
| 887 | * Sets the current position as the end of the file. |
| 888 | * |
| 889 | * PARAMS |
| 890 | * hFile [I] File handle. |
| 891 | * |
| 892 | * RETURNS |
| 893 | * Success: TRUE. |
| 894 | * Failure: FALSE, check GetLastError(). |
Alexandre Julliard | b592cbb | 2004-05-01 02:44:00 +0000 | [diff] [blame] | 895 | */ |
| 896 | BOOL WINAPI SetEndOfFile( HANDLE hFile ) |
| 897 | { |
| 898 | FILE_POSITION_INFORMATION pos; |
| 899 | FILE_END_OF_FILE_INFORMATION eof; |
| 900 | IO_STATUS_BLOCK io; |
| 901 | NTSTATUS status; |
| 902 | |
| 903 | status = NtQueryInformationFile( hFile, &io, &pos, sizeof(pos), FilePositionInformation ); |
| 904 | if (status == STATUS_SUCCESS) |
| 905 | { |
| 906 | eof.EndOfFile = pos.CurrentByteOffset; |
| 907 | status = NtSetInformationFile( hFile, &io, &eof, sizeof(eof), FileEndOfFileInformation ); |
| 908 | } |
| 909 | if (status == STATUS_SUCCESS) return TRUE; |
| 910 | SetLastError( RtlNtStatusToDosError(status) ); |
| 911 | return FALSE; |
| 912 | } |
| 913 | |
| 914 | |
Alexandre Julliard | d4874d6 | 2004-04-30 21:03:09 +0000 | [diff] [blame] | 915 | /*********************************************************************** |
Alexandre Julliard | 643617f | 2004-05-01 05:25:07 +0000 | [diff] [blame] | 916 | * SetFilePointer (KERNEL32.@) |
| 917 | */ |
Alexandre Julliard | 410db2a | 2004-06-14 19:40:44 +0000 | [diff] [blame] | 918 | DWORD WINAPI SetFilePointer( HANDLE hFile, LONG distance, LONG *highword, DWORD method ) |
Alexandre Julliard | 643617f | 2004-05-01 05:25:07 +0000 | [diff] [blame] | 919 | { |
Alexandre Julliard | 410db2a | 2004-06-14 19:40:44 +0000 | [diff] [blame] | 920 | LARGE_INTEGER dist, newpos; |
Alexandre Julliard | 643617f | 2004-05-01 05:25:07 +0000 | [diff] [blame] | 921 | |
Alexandre Julliard | 410db2a | 2004-06-14 19:40:44 +0000 | [diff] [blame] | 922 | if (highword) |
Alexandre Julliard | 643617f | 2004-05-01 05:25:07 +0000 | [diff] [blame] | 923 | { |
Alexandre Julliard | 410db2a | 2004-06-14 19:40:44 +0000 | [diff] [blame] | 924 | dist.u.LowPart = distance; |
| 925 | dist.u.HighPart = *highword; |
Alexandre Julliard | 643617f | 2004-05-01 05:25:07 +0000 | [diff] [blame] | 926 | } |
Alexandre Julliard | 410db2a | 2004-06-14 19:40:44 +0000 | [diff] [blame] | 927 | else dist.QuadPart = distance; |
Alexandre Julliard | 643617f | 2004-05-01 05:25:07 +0000 | [diff] [blame] | 928 | |
Alexandre Julliard | 410db2a | 2004-06-14 19:40:44 +0000 | [diff] [blame] | 929 | if (!SetFilePointerEx( hFile, dist, &newpos, method )) return INVALID_SET_FILE_POINTER; |
Alexandre Julliard | 643617f | 2004-05-01 05:25:07 +0000 | [diff] [blame] | 930 | |
Alexandre Julliard | 410db2a | 2004-06-14 19:40:44 +0000 | [diff] [blame] | 931 | if (highword) *highword = newpos.u.HighPart; |
| 932 | if (newpos.u.LowPart == INVALID_SET_FILE_POINTER) SetLastError( 0 ); |
| 933 | return newpos.u.LowPart; |
Alexandre Julliard | 643617f | 2004-05-01 05:25:07 +0000 | [diff] [blame] | 934 | } |
| 935 | |
| 936 | |
| 937 | /*********************************************************************** |
Mike McCormack | 6122eeb | 2004-06-14 17:56:50 +0000 | [diff] [blame] | 938 | * SetFilePointerEx (KERNEL32.@) |
| 939 | */ |
| 940 | BOOL WINAPI SetFilePointerEx( HANDLE hFile, LARGE_INTEGER distance, |
| 941 | LARGE_INTEGER *newpos, DWORD method ) |
| 942 | { |
| 943 | static const int whence[3] = { SEEK_SET, SEEK_CUR, SEEK_END }; |
| 944 | BOOL ret = FALSE; |
| 945 | NTSTATUS status; |
| 946 | int fd; |
| 947 | |
| 948 | TRACE("handle %p offset %s newpos %p origin %ld\n", |
| 949 | hFile, wine_dbgstr_longlong(distance.QuadPart), newpos, method ); |
| 950 | |
| 951 | if (method > FILE_END) |
| 952 | { |
| 953 | SetLastError( ERROR_INVALID_PARAMETER ); |
| 954 | return ret; |
| 955 | } |
| 956 | |
Alexandre Julliard | 6a27b48 | 2004-08-18 00:04:58 +0000 | [diff] [blame] | 957 | if (!(status = wine_server_handle_to_fd( hFile, 0, &fd, NULL ))) |
Mike McCormack | 6122eeb | 2004-06-14 17:56:50 +0000 | [diff] [blame] | 958 | { |
| 959 | off_t pos, res; |
| 960 | |
| 961 | pos = distance.QuadPart; |
| 962 | if ((res = lseek( fd, pos, whence[method] )) == (off_t)-1) |
| 963 | { |
| 964 | /* also check EPERM due to SuSE7 2.2.16 lseek() EPERM kernel bug */ |
| 965 | if (((errno == EINVAL) || (errno == EPERM)) && (method != FILE_BEGIN) && (pos < 0)) |
| 966 | SetLastError( ERROR_NEGATIVE_SEEK ); |
| 967 | else |
| 968 | FILE_SetDosError(); |
| 969 | } |
| 970 | else |
| 971 | { |
| 972 | ret = TRUE; |
| 973 | if( newpos ) |
| 974 | newpos->QuadPart = res; |
| 975 | } |
| 976 | wine_server_release_fd( hFile, fd ); |
| 977 | } |
| 978 | else SetLastError( RtlNtStatusToDosError(status) ); |
| 979 | |
| 980 | return ret; |
| 981 | } |
| 982 | |
| 983 | /*********************************************************************** |
Alexandre Julliard | d4874d6 | 2004-04-30 21:03:09 +0000 | [diff] [blame] | 984 | * GetFileTime (KERNEL32.@) |
| 985 | */ |
| 986 | BOOL WINAPI GetFileTime( HANDLE hFile, FILETIME *lpCreationTime, |
| 987 | FILETIME *lpLastAccessTime, FILETIME *lpLastWriteTime ) |
| 988 | { |
| 989 | FILE_BASIC_INFORMATION info; |
| 990 | IO_STATUS_BLOCK io; |
| 991 | NTSTATUS status; |
| 992 | |
| 993 | status = NtQueryInformationFile( hFile, &io, &info, sizeof(info), FileBasicInformation ); |
| 994 | if (status == STATUS_SUCCESS) |
Eric Pouech | f6a7096 | 2003-06-24 02:32:01 +0000 | [diff] [blame] | 995 | { |
Alexandre Julliard | d4874d6 | 2004-04-30 21:03:09 +0000 | [diff] [blame] | 996 | if (lpCreationTime) |
| 997 | { |
| 998 | lpCreationTime->dwHighDateTime = info.CreationTime.u.HighPart; |
| 999 | lpCreationTime->dwLowDateTime = info.CreationTime.u.LowPart; |
| 1000 | } |
| 1001 | if (lpLastAccessTime) |
| 1002 | { |
| 1003 | lpLastAccessTime->dwHighDateTime = info.LastAccessTime.u.HighPart; |
| 1004 | lpLastAccessTime->dwLowDateTime = info.LastAccessTime.u.LowPart; |
| 1005 | } |
| 1006 | if (lpLastWriteTime) |
| 1007 | { |
| 1008 | lpLastWriteTime->dwHighDateTime = info.LastWriteTime.u.HighPart; |
| 1009 | lpLastWriteTime->dwLowDateTime = info.LastWriteTime.u.LowPart; |
| 1010 | } |
| 1011 | return TRUE; |
Eric Pouech | f6a7096 | 2003-06-24 02:32:01 +0000 | [diff] [blame] | 1012 | } |
Alexandre Julliard | d4874d6 | 2004-04-30 21:03:09 +0000 | [diff] [blame] | 1013 | SetLastError( RtlNtStatusToDosError(status) ); |
| 1014 | return FALSE; |
Eric Pouech | f6a7096 | 2003-06-24 02:32:01 +0000 | [diff] [blame] | 1015 | } |
| 1016 | |
| 1017 | |
Alexandre Julliard | 174e2a6 | 2004-04-20 00:36:29 +0000 | [diff] [blame] | 1018 | /*********************************************************************** |
| 1019 | * SetFileTime (KERNEL32.@) |
| 1020 | */ |
| 1021 | BOOL WINAPI SetFileTime( HANDLE hFile, const FILETIME *ctime, |
| 1022 | const FILETIME *atime, const FILETIME *mtime ) |
| 1023 | { |
| 1024 | FILE_BASIC_INFORMATION info; |
| 1025 | IO_STATUS_BLOCK io; |
| 1026 | NTSTATUS status; |
| 1027 | |
| 1028 | memset( &info, 0, sizeof(info) ); |
| 1029 | if (ctime) |
| 1030 | { |
| 1031 | info.CreationTime.u.HighPart = ctime->dwHighDateTime; |
| 1032 | info.CreationTime.u.LowPart = ctime->dwLowDateTime; |
| 1033 | } |
| 1034 | if (atime) |
| 1035 | { |
| 1036 | info.LastAccessTime.u.HighPart = atime->dwHighDateTime; |
| 1037 | info.LastAccessTime.u.LowPart = atime->dwLowDateTime; |
| 1038 | } |
| 1039 | if (mtime) |
| 1040 | { |
| 1041 | info.LastWriteTime.u.HighPart = mtime->dwHighDateTime; |
| 1042 | info.LastWriteTime.u.LowPart = mtime->dwLowDateTime; |
| 1043 | } |
| 1044 | |
| 1045 | status = NtSetInformationFile( hFile, &io, &info, sizeof(info), FileBasicInformation ); |
| 1046 | if (status == STATUS_SUCCESS) return TRUE; |
| 1047 | SetLastError( RtlNtStatusToDosError(status) ); |
| 1048 | return FALSE; |
| 1049 | } |
| 1050 | |
| 1051 | |
Eric Pouech | f6a7096 | 2003-06-24 02:32:01 +0000 | [diff] [blame] | 1052 | /************************************************************************** |
| 1053 | * LockFile (KERNEL32.@) |
| 1054 | */ |
| 1055 | BOOL WINAPI LockFile( HANDLE hFile, DWORD offset_low, DWORD offset_high, |
| 1056 | DWORD count_low, DWORD count_high ) |
| 1057 | { |
| 1058 | NTSTATUS status; |
| 1059 | LARGE_INTEGER count, offset; |
| 1060 | |
| 1061 | TRACE( "%p %lx%08lx %lx%08lx\n", |
| 1062 | hFile, offset_high, offset_low, count_high, count_low ); |
| 1063 | |
Ge van Geldorp | 399901e | 2004-01-23 01:51:33 +0000 | [diff] [blame] | 1064 | count.u.LowPart = count_low; |
| 1065 | count.u.HighPart = count_high; |
| 1066 | offset.u.LowPart = offset_low; |
| 1067 | offset.u.HighPart = offset_high; |
Eric Pouech | f6a7096 | 2003-06-24 02:32:01 +0000 | [diff] [blame] | 1068 | |
| 1069 | status = NtLockFile( hFile, 0, NULL, NULL, |
| 1070 | NULL, &offset, &count, NULL, TRUE, TRUE ); |
| 1071 | |
| 1072 | if (status != STATUS_SUCCESS) SetLastError( RtlNtStatusToDosError(status) ); |
| 1073 | return !status; |
| 1074 | } |
| 1075 | |
| 1076 | |
| 1077 | /************************************************************************** |
| 1078 | * LockFileEx [KERNEL32.@] |
| 1079 | * |
| 1080 | * Locks a byte range within an open file for shared or exclusive access. |
| 1081 | * |
| 1082 | * RETURNS |
| 1083 | * success: TRUE |
| 1084 | * failure: FALSE |
| 1085 | * |
| 1086 | * NOTES |
| 1087 | * Per Microsoft docs, the third parameter (reserved) must be set to 0. |
| 1088 | */ |
| 1089 | BOOL WINAPI LockFileEx( HANDLE hFile, DWORD flags, DWORD reserved, |
| 1090 | DWORD count_low, DWORD count_high, LPOVERLAPPED overlapped ) |
| 1091 | { |
| 1092 | NTSTATUS status; |
| 1093 | LARGE_INTEGER count, offset; |
| 1094 | |
| 1095 | if (reserved) |
| 1096 | { |
| 1097 | SetLastError( ERROR_INVALID_PARAMETER ); |
| 1098 | return FALSE; |
| 1099 | } |
| 1100 | |
| 1101 | TRACE( "%p %lx%08lx %lx%08lx flags %lx\n", |
Dmitry Timoshkov | 75b93ff | 2005-03-17 19:00:08 +0000 | [diff] [blame] | 1102 | hFile, overlapped->u.s.OffsetHigh, overlapped->u.s.Offset, |
Eric Pouech | f6a7096 | 2003-06-24 02:32:01 +0000 | [diff] [blame] | 1103 | count_high, count_low, flags ); |
| 1104 | |
Ge van Geldorp | 399901e | 2004-01-23 01:51:33 +0000 | [diff] [blame] | 1105 | count.u.LowPart = count_low; |
| 1106 | count.u.HighPart = count_high; |
Dmitry Timoshkov | 75b93ff | 2005-03-17 19:00:08 +0000 | [diff] [blame] | 1107 | offset.u.LowPart = overlapped->u.s.Offset; |
| 1108 | offset.u.HighPart = overlapped->u.s.OffsetHigh; |
Eric Pouech | f6a7096 | 2003-06-24 02:32:01 +0000 | [diff] [blame] | 1109 | |
| 1110 | status = NtLockFile( hFile, overlapped->hEvent, NULL, NULL, |
| 1111 | NULL, &offset, &count, NULL, |
| 1112 | flags & LOCKFILE_FAIL_IMMEDIATELY, |
| 1113 | flags & LOCKFILE_EXCLUSIVE_LOCK ); |
| 1114 | |
| 1115 | if (status) SetLastError( RtlNtStatusToDosError(status) ); |
| 1116 | return !status; |
| 1117 | } |
| 1118 | |
| 1119 | |
| 1120 | /************************************************************************** |
| 1121 | * UnlockFile (KERNEL32.@) |
| 1122 | */ |
| 1123 | BOOL WINAPI UnlockFile( HANDLE hFile, DWORD offset_low, DWORD offset_high, |
| 1124 | DWORD count_low, DWORD count_high ) |
| 1125 | { |
| 1126 | NTSTATUS status; |
| 1127 | LARGE_INTEGER count, offset; |
| 1128 | |
Ge van Geldorp | 399901e | 2004-01-23 01:51:33 +0000 | [diff] [blame] | 1129 | count.u.LowPart = count_low; |
| 1130 | count.u.HighPart = count_high; |
| 1131 | offset.u.LowPart = offset_low; |
| 1132 | offset.u.HighPart = offset_high; |
Eric Pouech | f6a7096 | 2003-06-24 02:32:01 +0000 | [diff] [blame] | 1133 | |
| 1134 | status = NtUnlockFile( hFile, NULL, &offset, &count, NULL); |
| 1135 | if (status) SetLastError( RtlNtStatusToDosError(status) ); |
| 1136 | return !status; |
| 1137 | } |
| 1138 | |
| 1139 | |
| 1140 | /************************************************************************** |
| 1141 | * UnlockFileEx (KERNEL32.@) |
| 1142 | */ |
| 1143 | BOOL WINAPI UnlockFileEx( HANDLE hFile, DWORD reserved, DWORD count_low, DWORD count_high, |
| 1144 | LPOVERLAPPED overlapped ) |
| 1145 | { |
| 1146 | if (reserved) |
| 1147 | { |
| 1148 | SetLastError( ERROR_INVALID_PARAMETER ); |
| 1149 | return FALSE; |
| 1150 | } |
| 1151 | if (overlapped->hEvent) FIXME("Unimplemented overlapped operation\n"); |
| 1152 | |
Dmitry Timoshkov | 75b93ff | 2005-03-17 19:00:08 +0000 | [diff] [blame] | 1153 | return UnlockFile( hFile, overlapped->u.s.Offset, overlapped->u.s.OffsetHigh, count_low, count_high ); |
Eric Pouech | f6a7096 | 2003-06-24 02:32:01 +0000 | [diff] [blame] | 1154 | } |
| 1155 | |
Eric Pouech | 768008f | 2004-01-14 04:34:20 +0000 | [diff] [blame] | 1156 | |
| 1157 | /*********************************************************************** |
| 1158 | * Win32HandleToDosFileHandle (KERNEL32.21) |
| 1159 | * |
| 1160 | * Allocate a DOS handle for a Win32 handle. The Win32 handle is no |
| 1161 | * longer valid after this function (even on failure). |
| 1162 | * |
| 1163 | * Note: this is not exactly right, since on Win95 the Win32 handles |
| 1164 | * are on top of DOS handles and we do it the other way |
| 1165 | * around. Should be good enough though. |
| 1166 | */ |
| 1167 | HFILE WINAPI Win32HandleToDosFileHandle( HANDLE handle ) |
| 1168 | { |
| 1169 | int i; |
| 1170 | |
| 1171 | if (!handle || (handle == INVALID_HANDLE_VALUE)) |
| 1172 | return HFILE_ERROR; |
| 1173 | |
| 1174 | FILE_InitProcessDosHandles(); |
| 1175 | for (i = 0; i < DOS_TABLE_SIZE; i++) |
| 1176 | if (!dos_handles[i]) |
| 1177 | { |
| 1178 | dos_handles[i] = handle; |
| 1179 | TRACE("Got %d for h32 %p\n", i, handle ); |
| 1180 | return (HFILE)i; |
| 1181 | } |
| 1182 | CloseHandle( handle ); |
| 1183 | SetLastError( ERROR_TOO_MANY_OPEN_FILES ); |
| 1184 | return HFILE_ERROR; |
| 1185 | } |
| 1186 | |
| 1187 | |
| 1188 | /*********************************************************************** |
| 1189 | * DosFileHandleToWin32Handle (KERNEL32.20) |
| 1190 | * |
| 1191 | * Return the Win32 handle for a DOS handle. |
| 1192 | * |
| 1193 | * Note: this is not exactly right, since on Win95 the Win32 handles |
| 1194 | * are on top of DOS handles and we do it the other way |
| 1195 | * around. Should be good enough though. |
| 1196 | */ |
| 1197 | HANDLE WINAPI DosFileHandleToWin32Handle( HFILE handle ) |
| 1198 | { |
| 1199 | HFILE16 hfile = (HFILE16)handle; |
| 1200 | if (hfile < 5) FILE_InitProcessDosHandles(); |
| 1201 | if ((hfile >= DOS_TABLE_SIZE) || !dos_handles[hfile]) |
| 1202 | { |
| 1203 | SetLastError( ERROR_INVALID_HANDLE ); |
| 1204 | return INVALID_HANDLE_VALUE; |
| 1205 | } |
| 1206 | return dos_handles[hfile]; |
| 1207 | } |
| 1208 | |
| 1209 | |
Alexandre Julliard | 643617f | 2004-05-01 05:25:07 +0000 | [diff] [blame] | 1210 | /************************************************************************* |
| 1211 | * SetHandleCount (KERNEL32.@) |
| 1212 | */ |
| 1213 | UINT WINAPI SetHandleCount( UINT count ) |
| 1214 | { |
| 1215 | return min( 256, count ); |
| 1216 | } |
| 1217 | |
| 1218 | |
Eric Pouech | 768008f | 2004-01-14 04:34:20 +0000 | [diff] [blame] | 1219 | /*********************************************************************** |
| 1220 | * DisposeLZ32Handle (KERNEL32.22) |
| 1221 | * |
| 1222 | * Note: this is not entirely correct, we should only close the |
| 1223 | * 32-bit handle and not the 16-bit one, but we cannot do |
| 1224 | * this because of the way our DOS handles are implemented. |
| 1225 | * It shouldn't break anything though. |
| 1226 | */ |
| 1227 | void WINAPI DisposeLZ32Handle( HANDLE handle ) |
| 1228 | { |
| 1229 | int i; |
| 1230 | |
| 1231 | if (!handle || (handle == INVALID_HANDLE_VALUE)) return; |
| 1232 | |
| 1233 | for (i = 5; i < DOS_TABLE_SIZE; i++) |
| 1234 | if (dos_handles[i] == handle) |
| 1235 | { |
| 1236 | dos_handles[i] = 0; |
| 1237 | CloseHandle( handle ); |
| 1238 | break; |
| 1239 | } |
| 1240 | } |
| 1241 | |
Eric Pouech | f6a7096 | 2003-06-24 02:32:01 +0000 | [diff] [blame] | 1242 | /************************************************************************** |
| 1243 | * Operations on file names * |
| 1244 | **************************************************************************/ |
| 1245 | |
Alexandre Julliard | 643617f | 2004-05-01 05:25:07 +0000 | [diff] [blame] | 1246 | |
| 1247 | /************************************************************************* |
| 1248 | * CreateFileW [KERNEL32.@] Creates or opens a file or other object |
| 1249 | * |
| 1250 | * Creates or opens an object, and returns a handle that can be used to |
| 1251 | * access that object. |
| 1252 | * |
| 1253 | * PARAMS |
| 1254 | * |
| 1255 | * filename [in] pointer to filename to be accessed |
| 1256 | * access [in] access mode requested |
| 1257 | * sharing [in] share mode |
| 1258 | * sa [in] pointer to security attributes |
| 1259 | * creation [in] how to create the file |
| 1260 | * attributes [in] attributes for newly created file |
| 1261 | * template [in] handle to file with extended attributes to copy |
| 1262 | * |
| 1263 | * RETURNS |
| 1264 | * Success: Open handle to specified file |
| 1265 | * Failure: INVALID_HANDLE_VALUE |
| 1266 | */ |
| 1267 | HANDLE WINAPI CreateFileW( LPCWSTR filename, DWORD access, DWORD sharing, |
| 1268 | LPSECURITY_ATTRIBUTES sa, DWORD creation, |
| 1269 | DWORD attributes, HANDLE template ) |
| 1270 | { |
| 1271 | NTSTATUS status; |
| 1272 | UINT options; |
| 1273 | OBJECT_ATTRIBUTES attr; |
| 1274 | UNICODE_STRING nameW; |
| 1275 | IO_STATUS_BLOCK io; |
| 1276 | HANDLE ret; |
| 1277 | DWORD dosdev; |
| 1278 | static const WCHAR bkslashes_with_dotW[] = {'\\','\\','.','\\',0}; |
| 1279 | static const WCHAR coninW[] = {'C','O','N','I','N','$',0}; |
| 1280 | static const WCHAR conoutW[] = {'C','O','N','O','U','T','$',0}; |
| 1281 | |
Alexandre Julliard | 643617f | 2004-05-01 05:25:07 +0000 | [diff] [blame] | 1282 | static const UINT nt_disposition[5] = |
| 1283 | { |
| 1284 | FILE_CREATE, /* CREATE_NEW */ |
| 1285 | FILE_OVERWRITE_IF, /* CREATE_ALWAYS */ |
| 1286 | FILE_OPEN, /* OPEN_EXISTING */ |
| 1287 | FILE_OPEN_IF, /* OPEN_ALWAYS */ |
| 1288 | FILE_OVERWRITE /* TRUNCATE_EXISTING */ |
| 1289 | }; |
| 1290 | |
| 1291 | |
| 1292 | /* sanity checks */ |
| 1293 | |
| 1294 | if (!filename || !filename[0]) |
| 1295 | { |
| 1296 | SetLastError( ERROR_PATH_NOT_FOUND ); |
| 1297 | return INVALID_HANDLE_VALUE; |
| 1298 | } |
| 1299 | |
Dmitry Timoshkov | 567bed8 | 2004-12-21 16:12:49 +0000 | [diff] [blame] | 1300 | TRACE("%s %s%s%s%s%s%s creation %ld attributes 0x%lx\n", debugstr_w(filename), |
Alexandre Julliard | 643617f | 2004-05-01 05:25:07 +0000 | [diff] [blame] | 1301 | (access & GENERIC_READ)?"GENERIC_READ ":"", |
| 1302 | (access & GENERIC_WRITE)?"GENERIC_WRITE ":"", |
| 1303 | (!access)?"QUERY_ACCESS ":"", |
| 1304 | (sharing & FILE_SHARE_READ)?"FILE_SHARE_READ ":"", |
| 1305 | (sharing & FILE_SHARE_WRITE)?"FILE_SHARE_WRITE ":"", |
| 1306 | (sharing & FILE_SHARE_DELETE)?"FILE_SHARE_DELETE ":"", |
Dmitry Timoshkov | 567bed8 | 2004-12-21 16:12:49 +0000 | [diff] [blame] | 1307 | creation, attributes); |
Alexandre Julliard | 643617f | 2004-05-01 05:25:07 +0000 | [diff] [blame] | 1308 | |
| 1309 | /* Open a console for CONIN$ or CONOUT$ */ |
| 1310 | |
| 1311 | if (!strcmpiW(filename, coninW) || !strcmpiW(filename, conoutW)) |
| 1312 | { |
| 1313 | ret = OpenConsoleW(filename, access, (sa && sa->bInheritHandle), creation); |
| 1314 | goto done; |
| 1315 | } |
| 1316 | |
| 1317 | if (!strncmpW(filename, bkslashes_with_dotW, 4)) |
| 1318 | { |
| 1319 | static const WCHAR pipeW[] = {'P','I','P','E','\\',0}; |
Mike McCormack | 2ab6a77 | 2005-03-30 19:02:15 +0000 | [diff] [blame] | 1320 | static const WCHAR mailslotW[] = {'M','A','I','L','S','L','O','T','\\',0}; |
Alexandre Julliard | 643617f | 2004-05-01 05:25:07 +0000 | [diff] [blame] | 1321 | |
| 1322 | if ((isalphaW(filename[4]) && filename[5] == ':' && filename[6] == '\0') || |
Mike McCormack | 2ab6a77 | 2005-03-30 19:02:15 +0000 | [diff] [blame] | 1323 | !strncmpiW( filename + 4, pipeW, 5 ) || |
| 1324 | !strncmpiW( filename + 4, mailslotW, 9 )) |
Alexandre Julliard | 643617f | 2004-05-01 05:25:07 +0000 | [diff] [blame] | 1325 | { |
| 1326 | dosdev = 0; |
| 1327 | } |
| 1328 | else if ((dosdev = RtlIsDosDeviceName_U( filename + 4 ))) |
| 1329 | { |
| 1330 | dosdev += MAKELONG( 0, 4*sizeof(WCHAR) ); /* adjust position to start of filename */ |
| 1331 | } |
Alexandre Julliard | 67505c0 | 2005-12-12 14:27:45 +0100 | [diff] [blame] | 1332 | else if (!(GetVersion() & 0x80000000)) |
| 1333 | { |
| 1334 | dosdev = 0; |
| 1335 | } |
Alexandre Julliard | 643617f | 2004-05-01 05:25:07 +0000 | [diff] [blame] | 1336 | else if (filename[4]) |
| 1337 | { |
| 1338 | ret = VXD_Open( filename+4, access, sa ); |
| 1339 | goto done; |
| 1340 | } |
| 1341 | else |
| 1342 | { |
| 1343 | SetLastError( ERROR_INVALID_NAME ); |
| 1344 | return INVALID_HANDLE_VALUE; |
| 1345 | } |
| 1346 | } |
| 1347 | else dosdev = RtlIsDosDeviceName_U( filename ); |
| 1348 | |
| 1349 | if (dosdev) |
| 1350 | { |
| 1351 | static const WCHAR conW[] = {'C','O','N'}; |
| 1352 | |
| 1353 | if (LOWORD(dosdev) == sizeof(conW) && |
Rein Klazes | 8032418 | 2005-01-11 15:09:01 +0000 | [diff] [blame] | 1354 | !memicmpW( filename + HIWORD(dosdev)/sizeof(WCHAR), conW, sizeof(conW)/sizeof(WCHAR))) |
Alexandre Julliard | 643617f | 2004-05-01 05:25:07 +0000 | [diff] [blame] | 1355 | { |
| 1356 | switch (access & (GENERIC_READ|GENERIC_WRITE)) |
| 1357 | { |
| 1358 | case GENERIC_READ: |
| 1359 | ret = OpenConsoleW(coninW, access, (sa && sa->bInheritHandle), creation); |
| 1360 | goto done; |
| 1361 | case GENERIC_WRITE: |
| 1362 | ret = OpenConsoleW(conoutW, access, (sa && sa->bInheritHandle), creation); |
| 1363 | goto done; |
| 1364 | default: |
| 1365 | SetLastError( ERROR_FILE_NOT_FOUND ); |
| 1366 | return INVALID_HANDLE_VALUE; |
| 1367 | } |
| 1368 | } |
| 1369 | } |
| 1370 | |
Dmitry Timoshkov | 567bed8 | 2004-12-21 16:12:49 +0000 | [diff] [blame] | 1371 | if (creation < CREATE_NEW || creation > TRUNCATE_EXISTING) |
| 1372 | { |
| 1373 | SetLastError( ERROR_INVALID_PARAMETER ); |
| 1374 | return INVALID_HANDLE_VALUE; |
| 1375 | } |
| 1376 | |
Alexandre Julliard | 643617f | 2004-05-01 05:25:07 +0000 | [diff] [blame] | 1377 | if (!RtlDosPathNameToNtPathName_U( filename, &nameW, NULL, NULL )) |
| 1378 | { |
| 1379 | SetLastError( ERROR_PATH_NOT_FOUND ); |
| 1380 | return INVALID_HANDLE_VALUE; |
| 1381 | } |
| 1382 | |
| 1383 | /* now call NtCreateFile */ |
| 1384 | |
| 1385 | options = 0; |
| 1386 | if (attributes & FILE_FLAG_BACKUP_SEMANTICS) |
| 1387 | options |= FILE_OPEN_FOR_BACKUP_INTENT; |
| 1388 | else |
| 1389 | options |= FILE_NON_DIRECTORY_FILE; |
| 1390 | if (attributes & FILE_FLAG_DELETE_ON_CLOSE) |
Alexandre Julliard | 8b0feb2 | 2006-01-27 15:50:38 +0100 | [diff] [blame] | 1391 | { |
Alexandre Julliard | 643617f | 2004-05-01 05:25:07 +0000 | [diff] [blame] | 1392 | options |= FILE_DELETE_ON_CLOSE; |
Alexandre Julliard | 8b0feb2 | 2006-01-27 15:50:38 +0100 | [diff] [blame] | 1393 | access |= DELETE; |
| 1394 | } |
Alexandre Julliard | 643617f | 2004-05-01 05:25:07 +0000 | [diff] [blame] | 1395 | if (!(attributes & FILE_FLAG_OVERLAPPED)) |
| 1396 | options |= FILE_SYNCHRONOUS_IO_ALERT; |
| 1397 | if (attributes & FILE_FLAG_RANDOM_ACCESS) |
| 1398 | options |= FILE_RANDOM_ACCESS; |
| 1399 | attributes &= FILE_ATTRIBUTE_VALID_FLAGS; |
| 1400 | |
| 1401 | attr.Length = sizeof(attr); |
| 1402 | attr.RootDirectory = 0; |
| 1403 | attr.Attributes = OBJ_CASE_INSENSITIVE; |
| 1404 | attr.ObjectName = &nameW; |
| 1405 | attr.SecurityDescriptor = sa ? sa->lpSecurityDescriptor : NULL; |
| 1406 | attr.SecurityQualityOfService = NULL; |
| 1407 | |
| 1408 | if (sa && sa->bInheritHandle) attr.Attributes |= OBJ_INHERIT; |
| 1409 | |
| 1410 | status = NtCreateFile( &ret, access, &attr, &io, NULL, attributes, |
| 1411 | sharing, nt_disposition[creation - CREATE_NEW], |
| 1412 | options, NULL, 0 ); |
| 1413 | if (status) |
| 1414 | { |
| 1415 | WARN("Unable to create file %s (status %lx)\n", debugstr_w(filename), status); |
| 1416 | ret = INVALID_HANDLE_VALUE; |
| 1417 | |
| 1418 | /* In the case file creation was rejected due to CREATE_NEW flag |
| 1419 | * was specified and file with that name already exists, correct |
| 1420 | * last error is ERROR_FILE_EXISTS and not ERROR_ALREADY_EXISTS. |
| 1421 | * Note: RtlNtStatusToDosError is not the subject to blame here. |
| 1422 | */ |
| 1423 | if (status == STATUS_OBJECT_NAME_COLLISION) |
| 1424 | SetLastError( ERROR_FILE_EXISTS ); |
| 1425 | else |
| 1426 | SetLastError( RtlNtStatusToDosError(status) ); |
| 1427 | } |
| 1428 | else SetLastError(0); |
| 1429 | RtlFreeUnicodeString( &nameW ); |
| 1430 | |
| 1431 | done: |
| 1432 | if (!ret) ret = INVALID_HANDLE_VALUE; |
| 1433 | TRACE("returning %p\n", ret); |
| 1434 | return ret; |
| 1435 | } |
| 1436 | |
| 1437 | |
| 1438 | |
| 1439 | /************************************************************************* |
| 1440 | * CreateFileA (KERNEL32.@) |
Markus Amsler | b8d9b61 | 2005-11-08 11:01:03 +0000 | [diff] [blame] | 1441 | * |
| 1442 | * See CreateFileW. |
Alexandre Julliard | 643617f | 2004-05-01 05:25:07 +0000 | [diff] [blame] | 1443 | */ |
| 1444 | HANDLE WINAPI CreateFileA( LPCSTR filename, DWORD access, DWORD sharing, |
Alexandre Julliard | 0d33e5e | 2004-05-13 20:21:25 +0000 | [diff] [blame] | 1445 | LPSECURITY_ATTRIBUTES sa, DWORD creation, |
| 1446 | DWORD attributes, HANDLE template) |
Alexandre Julliard | 643617f | 2004-05-01 05:25:07 +0000 | [diff] [blame] | 1447 | { |
Alexandre Julliard | 0d33e5e | 2004-05-13 20:21:25 +0000 | [diff] [blame] | 1448 | WCHAR *nameW; |
Alexandre Julliard | 643617f | 2004-05-01 05:25:07 +0000 | [diff] [blame] | 1449 | |
Alexandre Julliard | 0d33e5e | 2004-05-13 20:21:25 +0000 | [diff] [blame] | 1450 | if (!(nameW = FILE_name_AtoW( filename, FALSE ))) return INVALID_HANDLE_VALUE; |
| 1451 | return CreateFileW( nameW, access, sharing, sa, creation, attributes, template ); |
Alexandre Julliard | 643617f | 2004-05-01 05:25:07 +0000 | [diff] [blame] | 1452 | } |
| 1453 | |
| 1454 | |
Alexandre Julliard | c4c4da4 | 2004-04-03 00:05:24 +0000 | [diff] [blame] | 1455 | /*********************************************************************** |
| 1456 | * DeleteFileW (KERNEL32.@) |
Robert Shearman | 277dfb8 | 2006-04-03 16:26:10 +0100 | [diff] [blame] | 1457 | * |
| 1458 | * Delete a file. |
| 1459 | * |
| 1460 | * PARAMS |
| 1461 | * path [I] Path to the file to delete. |
| 1462 | * |
| 1463 | * RETURNS |
| 1464 | * Success: TRUE. |
| 1465 | * Failure: FALSE, check GetLastError(). |
Alexandre Julliard | c4c4da4 | 2004-04-03 00:05:24 +0000 | [diff] [blame] | 1466 | */ |
| 1467 | BOOL WINAPI DeleteFileW( LPCWSTR path ) |
| 1468 | { |
Eric Pouech | 6d0712a | 2004-11-21 15:29:44 +0000 | [diff] [blame] | 1469 | UNICODE_STRING nameW; |
| 1470 | OBJECT_ATTRIBUTES attr; |
| 1471 | NTSTATUS status; |
Alexandre Julliard | c4c4da4 | 2004-04-03 00:05:24 +0000 | [diff] [blame] | 1472 | |
| 1473 | TRACE("%s\n", debugstr_w(path) ); |
| 1474 | |
Eric Pouech | 6d0712a | 2004-11-21 15:29:44 +0000 | [diff] [blame] | 1475 | if (!RtlDosPathNameToNtPathName_U( path, &nameW, NULL, NULL )) |
| 1476 | { |
| 1477 | SetLastError( ERROR_PATH_NOT_FOUND ); |
| 1478 | return FALSE; |
| 1479 | } |
Alexandre Julliard | c4c4da4 | 2004-04-03 00:05:24 +0000 | [diff] [blame] | 1480 | |
Eric Pouech | 6d0712a | 2004-11-21 15:29:44 +0000 | [diff] [blame] | 1481 | attr.Length = sizeof(attr); |
| 1482 | attr.RootDirectory = 0; |
| 1483 | attr.Attributes = OBJ_CASE_INSENSITIVE; |
| 1484 | attr.ObjectName = &nameW; |
| 1485 | attr.SecurityDescriptor = NULL; |
| 1486 | attr.SecurityQualityOfService = NULL; |
| 1487 | |
| 1488 | status = NtDeleteFile(&attr); |
| 1489 | RtlFreeUnicodeString( &nameW ); |
| 1490 | if (status) |
| 1491 | { |
| 1492 | SetLastError( RtlNtStatusToDosError(status) ); |
| 1493 | return FALSE; |
| 1494 | } |
Alexandre Julliard | c4c4da4 | 2004-04-03 00:05:24 +0000 | [diff] [blame] | 1495 | return TRUE; |
| 1496 | } |
| 1497 | |
| 1498 | |
| 1499 | /*********************************************************************** |
| 1500 | * DeleteFileA (KERNEL32.@) |
Robert Shearman | 277dfb8 | 2006-04-03 16:26:10 +0100 | [diff] [blame] | 1501 | * |
| 1502 | * See DeleteFileW. |
Alexandre Julliard | c4c4da4 | 2004-04-03 00:05:24 +0000 | [diff] [blame] | 1503 | */ |
| 1504 | BOOL WINAPI DeleteFileA( LPCSTR path ) |
| 1505 | { |
Alexandre Julliard | 0d33e5e | 2004-05-13 20:21:25 +0000 | [diff] [blame] | 1506 | WCHAR *pathW; |
Alexandre Julliard | c4c4da4 | 2004-04-03 00:05:24 +0000 | [diff] [blame] | 1507 | |
Alexandre Julliard | 0d33e5e | 2004-05-13 20:21:25 +0000 | [diff] [blame] | 1508 | if (!(pathW = FILE_name_AtoW( path, FALSE ))) return FALSE; |
| 1509 | return DeleteFileW( pathW ); |
Alexandre Julliard | c4c4da4 | 2004-04-03 00:05:24 +0000 | [diff] [blame] | 1510 | } |
| 1511 | |
| 1512 | |
Eric Pouech | f6a7096 | 2003-06-24 02:32:01 +0000 | [diff] [blame] | 1513 | /************************************************************************** |
| 1514 | * ReplaceFileW (KERNEL32.@) |
| 1515 | * ReplaceFile (KERNEL32.@) |
| 1516 | */ |
| 1517 | BOOL WINAPI ReplaceFileW(LPCWSTR lpReplacedFileName,LPCWSTR lpReplacementFileName, |
| 1518 | LPCWSTR lpBackupFileName, DWORD dwReplaceFlags, |
| 1519 | LPVOID lpExclude, LPVOID lpReserved) |
| 1520 | { |
| 1521 | FIXME("(%s,%s,%s,%08lx,%p,%p) stub\n",debugstr_w(lpReplacedFileName),debugstr_w(lpReplacementFileName), |
| 1522 | debugstr_w(lpBackupFileName),dwReplaceFlags,lpExclude,lpReserved); |
| 1523 | SetLastError(ERROR_UNABLE_TO_MOVE_REPLACEMENT); |
| 1524 | return FALSE; |
| 1525 | } |
| 1526 | |
| 1527 | |
| 1528 | /************************************************************************** |
| 1529 | * ReplaceFileA (KERNEL32.@) |
| 1530 | */ |
| 1531 | BOOL WINAPI ReplaceFileA(LPCSTR lpReplacedFileName,LPCSTR lpReplacementFileName, |
| 1532 | LPCSTR lpBackupFileName, DWORD dwReplaceFlags, |
| 1533 | LPVOID lpExclude, LPVOID lpReserved) |
| 1534 | { |
| 1535 | FIXME("(%s,%s,%s,%08lx,%p,%p) stub\n",lpReplacedFileName,lpReplacementFileName, |
| 1536 | lpBackupFileName,dwReplaceFlags,lpExclude,lpReserved); |
| 1537 | SetLastError(ERROR_UNABLE_TO_MOVE_REPLACEMENT); |
| 1538 | return FALSE; |
| 1539 | } |
Alexandre Julliard | 8f03216 | 2004-03-17 20:57:09 +0000 | [diff] [blame] | 1540 | |
| 1541 | |
| 1542 | /************************************************************************* |
| 1543 | * FindFirstFileExW (KERNEL32.@) |
| 1544 | */ |
| 1545 | HANDLE WINAPI FindFirstFileExW( LPCWSTR filename, FINDEX_INFO_LEVELS level, |
| 1546 | LPVOID data, FINDEX_SEARCH_OPS search_op, |
| 1547 | LPVOID filter, DWORD flags) |
| 1548 | { |
Alexandre Julliard | a9832be | 2004-04-17 00:26:54 +0000 | [diff] [blame] | 1549 | WCHAR *mask, *p; |
Alexandre Julliard | 8f03216 | 2004-03-17 20:57:09 +0000 | [diff] [blame] | 1550 | FIND_FIRST_INFO *info = NULL; |
Alexandre Julliard | a9832be | 2004-04-17 00:26:54 +0000 | [diff] [blame] | 1551 | UNICODE_STRING nt_name; |
| 1552 | OBJECT_ATTRIBUTES attr; |
| 1553 | IO_STATUS_BLOCK io; |
| 1554 | NTSTATUS status; |
Alexandre Julliard | 8f03216 | 2004-03-17 20:57:09 +0000 | [diff] [blame] | 1555 | |
Christian Costa | fe0460f | 2004-05-22 03:13:56 +0000 | [diff] [blame] | 1556 | TRACE("%s %d %p %d %p %lx\n", debugstr_w(filename), level, data, search_op, filter, flags); |
| 1557 | |
Bernd Schmidt | 60fc242 | 2005-11-01 21:37:05 +0000 | [diff] [blame] | 1558 | if ((search_op != FindExSearchNameMatch && search_op != FindExSearchLimitToDirectories) |
| 1559 | || flags != 0) |
Alexandre Julliard | 8f03216 | 2004-03-17 20:57:09 +0000 | [diff] [blame] | 1560 | { |
| 1561 | FIXME("options not implemented 0x%08x 0x%08lx\n", search_op, flags ); |
| 1562 | return INVALID_HANDLE_VALUE; |
| 1563 | } |
| 1564 | if (level != FindExInfoStandard) |
| 1565 | { |
| 1566 | FIXME("info level %d not implemented\n", level ); |
| 1567 | return INVALID_HANDLE_VALUE; |
| 1568 | } |
Alexandre Julliard | a9832be | 2004-04-17 00:26:54 +0000 | [diff] [blame] | 1569 | |
| 1570 | if (!RtlDosPathNameToNtPathName_U( filename, &nt_name, &mask, NULL )) |
Alexandre Julliard | 8f03216 | 2004-03-17 20:57:09 +0000 | [diff] [blame] | 1571 | { |
| 1572 | SetLastError( ERROR_PATH_NOT_FOUND ); |
| 1573 | return INVALID_HANDLE_VALUE; |
| 1574 | } |
Alexandre Julliard | 8f03216 | 2004-03-17 20:57:09 +0000 | [diff] [blame] | 1575 | |
| 1576 | if (!mask || !*mask) |
| 1577 | { |
| 1578 | SetLastError( ERROR_FILE_NOT_FOUND ); |
| 1579 | goto error; |
| 1580 | } |
| 1581 | |
| 1582 | if (!(info = HeapAlloc( GetProcessHeap(), 0, sizeof(*info)))) |
| 1583 | { |
| 1584 | SetLastError( ERROR_NOT_ENOUGH_MEMORY ); |
| 1585 | goto error; |
| 1586 | } |
| 1587 | |
| 1588 | if (!RtlCreateUnicodeString( &info->mask, mask )) |
| 1589 | { |
| 1590 | SetLastError( ERROR_NOT_ENOUGH_MEMORY ); |
| 1591 | goto error; |
| 1592 | } |
Alexandre Julliard | a9832be | 2004-04-17 00:26:54 +0000 | [diff] [blame] | 1593 | |
| 1594 | /* truncate dir name before mask */ |
Alexandre Julliard | 8f03216 | 2004-03-17 20:57:09 +0000 | [diff] [blame] | 1595 | *mask = 0; |
Alexandre Julliard | a9832be | 2004-04-17 00:26:54 +0000 | [diff] [blame] | 1596 | nt_name.Length = (mask - nt_name.Buffer) * sizeof(WCHAR); |
Alexandre Julliard | 8f03216 | 2004-03-17 20:57:09 +0000 | [diff] [blame] | 1597 | |
| 1598 | /* check if path is the root of the drive */ |
| 1599 | info->is_root = FALSE; |
Alexandre Julliard | a9832be | 2004-04-17 00:26:54 +0000 | [diff] [blame] | 1600 | p = nt_name.Buffer + 4; /* skip \??\ prefix */ |
| 1601 | if (p[0] && p[1] == ':') |
Alexandre Julliard | 8f03216 | 2004-03-17 20:57:09 +0000 | [diff] [blame] | 1602 | { |
Alexandre Julliard | a9832be | 2004-04-17 00:26:54 +0000 | [diff] [blame] | 1603 | p += 2; |
Alexandre Julliard | 8f03216 | 2004-03-17 20:57:09 +0000 | [diff] [blame] | 1604 | while (*p == '\\') p++; |
| 1605 | info->is_root = (*p == 0); |
| 1606 | } |
| 1607 | |
Alexandre Julliard | a9832be | 2004-04-17 00:26:54 +0000 | [diff] [blame] | 1608 | attr.Length = sizeof(attr); |
| 1609 | attr.RootDirectory = 0; |
| 1610 | attr.Attributes = OBJ_CASE_INSENSITIVE; |
| 1611 | attr.ObjectName = &nt_name; |
| 1612 | attr.SecurityDescriptor = NULL; |
| 1613 | attr.SecurityQualityOfService = NULL; |
| 1614 | |
| 1615 | status = NtOpenFile( &info->handle, GENERIC_READ, &attr, &io, |
| 1616 | FILE_SHARE_READ | FILE_SHARE_WRITE, |
| 1617 | FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT ); |
| 1618 | |
| 1619 | if (status != STATUS_SUCCESS) |
Alexandre Julliard | 8f03216 | 2004-03-17 20:57:09 +0000 | [diff] [blame] | 1620 | { |
| 1621 | RtlFreeUnicodeString( &info->mask ); |
Alexandre Julliard | a9832be | 2004-04-17 00:26:54 +0000 | [diff] [blame] | 1622 | SetLastError( RtlNtStatusToDosError(status) ); |
Alexandre Julliard | 8f03216 | 2004-03-17 20:57:09 +0000 | [diff] [blame] | 1623 | goto error; |
| 1624 | } |
| 1625 | |
| 1626 | RtlInitializeCriticalSection( &info->cs ); |
Alexandre Julliard | a51f2be | 2005-10-26 13:57:45 +0000 | [diff] [blame] | 1627 | info->path = nt_name; |
Alexandre Julliard | f435914 | 2004-06-15 00:55:04 +0000 | [diff] [blame] | 1628 | info->magic = FIND_FIRST_MAGIC; |
Alexandre Julliard | 8f03216 | 2004-03-17 20:57:09 +0000 | [diff] [blame] | 1629 | info->data_pos = 0; |
| 1630 | info->data_len = 0; |
Bernd Schmidt | 60fc242 | 2005-11-01 21:37:05 +0000 | [diff] [blame] | 1631 | info->search_op = search_op; |
Alexandre Julliard | 8f03216 | 2004-03-17 20:57:09 +0000 | [diff] [blame] | 1632 | |
| 1633 | if (!FindNextFileW( (HANDLE)info, data )) |
| 1634 | { |
| 1635 | TRACE( "%s not found\n", debugstr_w(filename) ); |
| 1636 | FindClose( (HANDLE)info ); |
| 1637 | SetLastError( ERROR_FILE_NOT_FOUND ); |
| 1638 | return INVALID_HANDLE_VALUE; |
| 1639 | } |
| 1640 | return (HANDLE)info; |
| 1641 | |
| 1642 | error: |
Michael Stefaniuc | 5ad7d85 | 2004-12-23 17:06:43 +0000 | [diff] [blame] | 1643 | HeapFree( GetProcessHeap(), 0, info ); |
Alexandre Julliard | a9832be | 2004-04-17 00:26:54 +0000 | [diff] [blame] | 1644 | RtlFreeUnicodeString( &nt_name ); |
Alexandre Julliard | 8f03216 | 2004-03-17 20:57:09 +0000 | [diff] [blame] | 1645 | return INVALID_HANDLE_VALUE; |
| 1646 | } |
| 1647 | |
| 1648 | |
| 1649 | /************************************************************************* |
| 1650 | * FindNextFileW (KERNEL32.@) |
| 1651 | */ |
| 1652 | BOOL WINAPI FindNextFileW( HANDLE handle, WIN32_FIND_DATAW *data ) |
| 1653 | { |
| 1654 | FIND_FIRST_INFO *info; |
| 1655 | FILE_BOTH_DIR_INFORMATION *dir_info; |
| 1656 | BOOL ret = FALSE; |
| 1657 | |
Christian Costa | fe0460f | 2004-05-22 03:13:56 +0000 | [diff] [blame] | 1658 | TRACE("%p %p\n", handle, data); |
Alexandre Julliard | f435914 | 2004-06-15 00:55:04 +0000 | [diff] [blame] | 1659 | |
| 1660 | if (!handle || handle == INVALID_HANDLE_VALUE) |
Alexandre Julliard | 8f03216 | 2004-03-17 20:57:09 +0000 | [diff] [blame] | 1661 | { |
| 1662 | SetLastError( ERROR_INVALID_HANDLE ); |
| 1663 | return ret; |
| 1664 | } |
| 1665 | info = (FIND_FIRST_INFO *)handle; |
Alexandre Julliard | f435914 | 2004-06-15 00:55:04 +0000 | [diff] [blame] | 1666 | if (info->magic != FIND_FIRST_MAGIC) |
| 1667 | { |
| 1668 | SetLastError( ERROR_INVALID_HANDLE ); |
| 1669 | return ret; |
| 1670 | } |
Alexandre Julliard | 8f03216 | 2004-03-17 20:57:09 +0000 | [diff] [blame] | 1671 | |
| 1672 | RtlEnterCriticalSection( &info->cs ); |
| 1673 | |
| 1674 | for (;;) |
| 1675 | { |
| 1676 | if (info->data_pos >= info->data_len) /* need to read some more data */ |
| 1677 | { |
| 1678 | IO_STATUS_BLOCK io; |
| 1679 | |
| 1680 | NtQueryDirectoryFile( info->handle, 0, NULL, NULL, &io, info->data, sizeof(info->data), |
| 1681 | FileBothDirectoryInformation, FALSE, &info->mask, FALSE ); |
| 1682 | if (io.u.Status) |
| 1683 | { |
| 1684 | SetLastError( RtlNtStatusToDosError( io.u.Status ) ); |
| 1685 | break; |
| 1686 | } |
| 1687 | info->data_len = io.Information; |
| 1688 | info->data_pos = 0; |
| 1689 | } |
| 1690 | |
| 1691 | dir_info = (FILE_BOTH_DIR_INFORMATION *)(info->data + info->data_pos); |
| 1692 | |
| 1693 | if (dir_info->NextEntryOffset) info->data_pos += dir_info->NextEntryOffset; |
| 1694 | else info->data_pos = info->data_len; |
| 1695 | |
| 1696 | /* don't return '.' and '..' in the root of the drive */ |
| 1697 | if (info->is_root) |
| 1698 | { |
| 1699 | if (dir_info->FileNameLength == sizeof(WCHAR) && dir_info->FileName[0] == '.') continue; |
| 1700 | if (dir_info->FileNameLength == 2 * sizeof(WCHAR) && |
| 1701 | dir_info->FileName[0] == '.' && dir_info->FileName[1] == '.') continue; |
| 1702 | } |
| 1703 | |
Alexandre Julliard | a51f2be | 2005-10-26 13:57:45 +0000 | [diff] [blame] | 1704 | /* check for dir symlink */ |
| 1705 | if ((dir_info->FileAttributes & FILE_ATTRIBUTE_DIRECTORY) && |
| 1706 | (dir_info->FileAttributes & FILE_ATTRIBUTE_REPARSE_POINT)) |
| 1707 | { |
| 1708 | if (!check_dir_symlink( info, dir_info )) continue; |
| 1709 | } |
Bernd Schmidt | 60fc242 | 2005-11-01 21:37:05 +0000 | [diff] [blame] | 1710 | if (info->search_op == FindExSearchLimitToDirectories && |
| 1711 | (dir_info->FileAttributes & FILE_ATTRIBUTE_DIRECTORY) == 0) |
| 1712 | continue; |
Alexandre Julliard | a51f2be | 2005-10-26 13:57:45 +0000 | [diff] [blame] | 1713 | |
Alexandre Julliard | 8f03216 | 2004-03-17 20:57:09 +0000 | [diff] [blame] | 1714 | data->dwFileAttributes = dir_info->FileAttributes; |
| 1715 | data->ftCreationTime = *(FILETIME *)&dir_info->CreationTime; |
| 1716 | data->ftLastAccessTime = *(FILETIME *)&dir_info->LastAccessTime; |
| 1717 | data->ftLastWriteTime = *(FILETIME *)&dir_info->LastWriteTime; |
| 1718 | data->nFileSizeHigh = dir_info->EndOfFile.QuadPart >> 32; |
| 1719 | data->nFileSizeLow = (DWORD)dir_info->EndOfFile.QuadPart; |
| 1720 | data->dwReserved0 = 0; |
| 1721 | data->dwReserved1 = 0; |
| 1722 | |
| 1723 | memcpy( data->cFileName, dir_info->FileName, dir_info->FileNameLength ); |
| 1724 | data->cFileName[dir_info->FileNameLength/sizeof(WCHAR)] = 0; |
| 1725 | memcpy( data->cAlternateFileName, dir_info->ShortName, dir_info->ShortNameLength ); |
| 1726 | data->cAlternateFileName[dir_info->ShortNameLength/sizeof(WCHAR)] = 0; |
| 1727 | |
| 1728 | TRACE("returning %s (%s)\n", |
| 1729 | debugstr_w(data->cFileName), debugstr_w(data->cAlternateFileName) ); |
| 1730 | |
| 1731 | ret = TRUE; |
| 1732 | break; |
| 1733 | } |
| 1734 | |
| 1735 | RtlLeaveCriticalSection( &info->cs ); |
| 1736 | return ret; |
| 1737 | } |
| 1738 | |
| 1739 | |
| 1740 | /************************************************************************* |
| 1741 | * FindClose (KERNEL32.@) |
| 1742 | */ |
| 1743 | BOOL WINAPI FindClose( HANDLE handle ) |
| 1744 | { |
| 1745 | FIND_FIRST_INFO *info = (FIND_FIRST_INFO *)handle; |
| 1746 | |
Alexandre Julliard | f435914 | 2004-06-15 00:55:04 +0000 | [diff] [blame] | 1747 | if (!handle || handle == INVALID_HANDLE_VALUE) |
| 1748 | { |
| 1749 | SetLastError( ERROR_INVALID_HANDLE ); |
| 1750 | return FALSE; |
| 1751 | } |
Alexandre Julliard | 8f03216 | 2004-03-17 20:57:09 +0000 | [diff] [blame] | 1752 | |
| 1753 | __TRY |
| 1754 | { |
Alexandre Julliard | f435914 | 2004-06-15 00:55:04 +0000 | [diff] [blame] | 1755 | if (info->magic == FIND_FIRST_MAGIC) |
| 1756 | { |
| 1757 | RtlEnterCriticalSection( &info->cs ); |
| 1758 | if (info->magic == FIND_FIRST_MAGIC) /* in case someone else freed it in the meantime */ |
| 1759 | { |
| 1760 | info->magic = 0; |
| 1761 | if (info->handle) CloseHandle( info->handle ); |
| 1762 | info->handle = 0; |
| 1763 | RtlFreeUnicodeString( &info->mask ); |
| 1764 | info->mask.Buffer = NULL; |
Alexandre Julliard | a51f2be | 2005-10-26 13:57:45 +0000 | [diff] [blame] | 1765 | RtlFreeUnicodeString( &info->path ); |
Alexandre Julliard | f435914 | 2004-06-15 00:55:04 +0000 | [diff] [blame] | 1766 | info->data_pos = 0; |
| 1767 | info->data_len = 0; |
| 1768 | RtlLeaveCriticalSection( &info->cs ); |
| 1769 | RtlDeleteCriticalSection( &info->cs ); |
| 1770 | HeapFree( GetProcessHeap(), 0, info ); |
| 1771 | } |
| 1772 | } |
Alexandre Julliard | 8f03216 | 2004-03-17 20:57:09 +0000 | [diff] [blame] | 1773 | } |
Alexandre Julliard | ae964ac | 2005-12-16 17:17:57 +0100 | [diff] [blame] | 1774 | __EXCEPT_PAGE_FAULT |
Alexandre Julliard | 8f03216 | 2004-03-17 20:57:09 +0000 | [diff] [blame] | 1775 | { |
| 1776 | WARN("Illegal handle %p\n", handle); |
| 1777 | SetLastError( ERROR_INVALID_HANDLE ); |
| 1778 | return FALSE; |
| 1779 | } |
| 1780 | __ENDTRY |
| 1781 | |
Alexandre Julliard | 8f03216 | 2004-03-17 20:57:09 +0000 | [diff] [blame] | 1782 | return TRUE; |
Alexandre Julliard | 8f03216 | 2004-03-17 20:57:09 +0000 | [diff] [blame] | 1783 | } |
| 1784 | |
| 1785 | |
| 1786 | /************************************************************************* |
| 1787 | * FindFirstFileA (KERNEL32.@) |
| 1788 | */ |
| 1789 | HANDLE WINAPI FindFirstFileA( LPCSTR lpFileName, WIN32_FIND_DATAA *lpFindData ) |
| 1790 | { |
| 1791 | return FindFirstFileExA(lpFileName, FindExInfoStandard, lpFindData, |
| 1792 | FindExSearchNameMatch, NULL, 0); |
| 1793 | } |
| 1794 | |
| 1795 | /************************************************************************* |
| 1796 | * FindFirstFileExA (KERNEL32.@) |
| 1797 | */ |
| 1798 | HANDLE WINAPI FindFirstFileExA( LPCSTR lpFileName, FINDEX_INFO_LEVELS fInfoLevelId, |
| 1799 | LPVOID lpFindFileData, FINDEX_SEARCH_OPS fSearchOp, |
| 1800 | LPVOID lpSearchFilter, DWORD dwAdditionalFlags) |
| 1801 | { |
| 1802 | HANDLE handle; |
| 1803 | WIN32_FIND_DATAA *dataA; |
| 1804 | WIN32_FIND_DATAW dataW; |
Alexandre Julliard | 0d33e5e | 2004-05-13 20:21:25 +0000 | [diff] [blame] | 1805 | WCHAR *nameW; |
Alexandre Julliard | 8f03216 | 2004-03-17 20:57:09 +0000 | [diff] [blame] | 1806 | |
Alexandre Julliard | 0d33e5e | 2004-05-13 20:21:25 +0000 | [diff] [blame] | 1807 | if (!(nameW = FILE_name_AtoW( lpFileName, FALSE ))) return INVALID_HANDLE_VALUE; |
Alexandre Julliard | 8f03216 | 2004-03-17 20:57:09 +0000 | [diff] [blame] | 1808 | |
Alexandre Julliard | 0d33e5e | 2004-05-13 20:21:25 +0000 | [diff] [blame] | 1809 | handle = FindFirstFileExW(nameW, fInfoLevelId, &dataW, fSearchOp, lpSearchFilter, dwAdditionalFlags); |
Alexandre Julliard | 8f03216 | 2004-03-17 20:57:09 +0000 | [diff] [blame] | 1810 | if (handle == INVALID_HANDLE_VALUE) return handle; |
| 1811 | |
| 1812 | dataA = (WIN32_FIND_DATAA *) lpFindFileData; |
| 1813 | dataA->dwFileAttributes = dataW.dwFileAttributes; |
| 1814 | dataA->ftCreationTime = dataW.ftCreationTime; |
| 1815 | dataA->ftLastAccessTime = dataW.ftLastAccessTime; |
| 1816 | dataA->ftLastWriteTime = dataW.ftLastWriteTime; |
| 1817 | dataA->nFileSizeHigh = dataW.nFileSizeHigh; |
| 1818 | dataA->nFileSizeLow = dataW.nFileSizeLow; |
Alexandre Julliard | 0d33e5e | 2004-05-13 20:21:25 +0000 | [diff] [blame] | 1819 | FILE_name_WtoA( dataW.cFileName, -1, dataA->cFileName, sizeof(dataA->cFileName) ); |
| 1820 | FILE_name_WtoA( dataW.cAlternateFileName, -1, dataA->cAlternateFileName, |
| 1821 | sizeof(dataA->cAlternateFileName) ); |
Alexandre Julliard | 8f03216 | 2004-03-17 20:57:09 +0000 | [diff] [blame] | 1822 | return handle; |
| 1823 | } |
| 1824 | |
| 1825 | |
| 1826 | /************************************************************************* |
| 1827 | * FindFirstFileW (KERNEL32.@) |
| 1828 | */ |
| 1829 | HANDLE WINAPI FindFirstFileW( LPCWSTR lpFileName, WIN32_FIND_DATAW *lpFindData ) |
| 1830 | { |
| 1831 | return FindFirstFileExW(lpFileName, FindExInfoStandard, lpFindData, |
| 1832 | FindExSearchNameMatch, NULL, 0); |
| 1833 | } |
| 1834 | |
| 1835 | |
| 1836 | /************************************************************************* |
| 1837 | * FindNextFileA (KERNEL32.@) |
| 1838 | */ |
| 1839 | BOOL WINAPI FindNextFileA( HANDLE handle, WIN32_FIND_DATAA *data ) |
| 1840 | { |
| 1841 | WIN32_FIND_DATAW dataW; |
| 1842 | |
| 1843 | if (!FindNextFileW( handle, &dataW )) return FALSE; |
| 1844 | data->dwFileAttributes = dataW.dwFileAttributes; |
| 1845 | data->ftCreationTime = dataW.ftCreationTime; |
| 1846 | data->ftLastAccessTime = dataW.ftLastAccessTime; |
| 1847 | data->ftLastWriteTime = dataW.ftLastWriteTime; |
| 1848 | data->nFileSizeHigh = dataW.nFileSizeHigh; |
| 1849 | data->nFileSizeLow = dataW.nFileSizeLow; |
Alexandre Julliard | 0d33e5e | 2004-05-13 20:21:25 +0000 | [diff] [blame] | 1850 | FILE_name_WtoA( dataW.cFileName, -1, data->cFileName, sizeof(data->cFileName) ); |
| 1851 | FILE_name_WtoA( dataW.cAlternateFileName, -1, data->cAlternateFileName, |
| 1852 | sizeof(data->cAlternateFileName) ); |
Alexandre Julliard | 8f03216 | 2004-03-17 20:57:09 +0000 | [diff] [blame] | 1853 | return TRUE; |
| 1854 | } |
Alexandre Julliard | 5bfafc9 | 2004-03-25 05:36:08 +0000 | [diff] [blame] | 1855 | |
| 1856 | |
Alexandre Julliard | 174e2a6 | 2004-04-20 00:36:29 +0000 | [diff] [blame] | 1857 | /************************************************************************** |
| 1858 | * GetFileAttributesW (KERNEL32.@) |
| 1859 | */ |
| 1860 | DWORD WINAPI GetFileAttributesW( LPCWSTR name ) |
| 1861 | { |
| 1862 | FILE_BASIC_INFORMATION info; |
| 1863 | UNICODE_STRING nt_name; |
| 1864 | OBJECT_ATTRIBUTES attr; |
| 1865 | NTSTATUS status; |
| 1866 | |
Christian Costa | fe0460f | 2004-05-22 03:13:56 +0000 | [diff] [blame] | 1867 | TRACE("%s\n", debugstr_w(name)); |
| 1868 | |
Alexandre Julliard | 174e2a6 | 2004-04-20 00:36:29 +0000 | [diff] [blame] | 1869 | if (!RtlDosPathNameToNtPathName_U( name, &nt_name, NULL, NULL )) |
| 1870 | { |
| 1871 | SetLastError( ERROR_PATH_NOT_FOUND ); |
| 1872 | return INVALID_FILE_ATTRIBUTES; |
| 1873 | } |
| 1874 | |
| 1875 | attr.Length = sizeof(attr); |
| 1876 | attr.RootDirectory = 0; |
| 1877 | attr.Attributes = OBJ_CASE_INSENSITIVE; |
| 1878 | attr.ObjectName = &nt_name; |
| 1879 | attr.SecurityDescriptor = NULL; |
| 1880 | attr.SecurityQualityOfService = NULL; |
| 1881 | |
| 1882 | status = NtQueryAttributesFile( &attr, &info ); |
| 1883 | RtlFreeUnicodeString( &nt_name ); |
| 1884 | |
| 1885 | if (status == STATUS_SUCCESS) return info.FileAttributes; |
| 1886 | |
| 1887 | /* NtQueryAttributesFile fails on devices, but GetFileAttributesW succeeds */ |
| 1888 | if (RtlIsDosDeviceName_U( name )) return FILE_ATTRIBUTE_ARCHIVE; |
| 1889 | |
| 1890 | SetLastError( RtlNtStatusToDosError(status) ); |
| 1891 | return INVALID_FILE_ATTRIBUTES; |
| 1892 | } |
| 1893 | |
| 1894 | |
| 1895 | /************************************************************************** |
| 1896 | * GetFileAttributesA (KERNEL32.@) |
| 1897 | */ |
| 1898 | DWORD WINAPI GetFileAttributesA( LPCSTR name ) |
| 1899 | { |
Alexandre Julliard | 0d33e5e | 2004-05-13 20:21:25 +0000 | [diff] [blame] | 1900 | WCHAR *nameW; |
Alexandre Julliard | 174e2a6 | 2004-04-20 00:36:29 +0000 | [diff] [blame] | 1901 | |
Alexandre Julliard | 0d33e5e | 2004-05-13 20:21:25 +0000 | [diff] [blame] | 1902 | if (!(nameW = FILE_name_AtoW( name, FALSE ))) return INVALID_FILE_ATTRIBUTES; |
| 1903 | return GetFileAttributesW( nameW ); |
Alexandre Julliard | 174e2a6 | 2004-04-20 00:36:29 +0000 | [diff] [blame] | 1904 | } |
| 1905 | |
| 1906 | |
| 1907 | /************************************************************************** |
| 1908 | * SetFileAttributesW (KERNEL32.@) |
| 1909 | */ |
| 1910 | BOOL WINAPI SetFileAttributesW( LPCWSTR name, DWORD attributes ) |
| 1911 | { |
| 1912 | UNICODE_STRING nt_name; |
| 1913 | OBJECT_ATTRIBUTES attr; |
| 1914 | IO_STATUS_BLOCK io; |
| 1915 | NTSTATUS status; |
| 1916 | HANDLE handle; |
| 1917 | |
Christian Costa | fe0460f | 2004-05-22 03:13:56 +0000 | [diff] [blame] | 1918 | TRACE("%s %lx\n", debugstr_w(name), attributes); |
| 1919 | |
Alexandre Julliard | 174e2a6 | 2004-04-20 00:36:29 +0000 | [diff] [blame] | 1920 | if (!RtlDosPathNameToNtPathName_U( name, &nt_name, NULL, NULL )) |
| 1921 | { |
| 1922 | SetLastError( ERROR_PATH_NOT_FOUND ); |
| 1923 | return FALSE; |
| 1924 | } |
| 1925 | |
| 1926 | attr.Length = sizeof(attr); |
| 1927 | attr.RootDirectory = 0; |
| 1928 | attr.Attributes = OBJ_CASE_INSENSITIVE; |
| 1929 | attr.ObjectName = &nt_name; |
| 1930 | attr.SecurityDescriptor = NULL; |
| 1931 | attr.SecurityQualityOfService = NULL; |
| 1932 | |
| 1933 | status = NtOpenFile( &handle, 0, &attr, &io, 0, FILE_SYNCHRONOUS_IO_NONALERT ); |
| 1934 | RtlFreeUnicodeString( &nt_name ); |
| 1935 | |
| 1936 | if (status == STATUS_SUCCESS) |
| 1937 | { |
| 1938 | FILE_BASIC_INFORMATION info; |
| 1939 | |
| 1940 | memset( &info, 0, sizeof(info) ); |
| 1941 | info.FileAttributes = attributes | FILE_ATTRIBUTE_NORMAL; /* make sure it's not zero */ |
| 1942 | status = NtSetInformationFile( handle, &io, &info, sizeof(info), FileBasicInformation ); |
| 1943 | NtClose( handle ); |
| 1944 | } |
| 1945 | |
| 1946 | if (status == STATUS_SUCCESS) return TRUE; |
| 1947 | SetLastError( RtlNtStatusToDosError(status) ); |
| 1948 | return FALSE; |
| 1949 | } |
| 1950 | |
| 1951 | |
| 1952 | /************************************************************************** |
| 1953 | * SetFileAttributesA (KERNEL32.@) |
| 1954 | */ |
| 1955 | BOOL WINAPI SetFileAttributesA( LPCSTR name, DWORD attributes ) |
| 1956 | { |
Alexandre Julliard | 0d33e5e | 2004-05-13 20:21:25 +0000 | [diff] [blame] | 1957 | WCHAR *nameW; |
Alexandre Julliard | 174e2a6 | 2004-04-20 00:36:29 +0000 | [diff] [blame] | 1958 | |
Alexandre Julliard | 0d33e5e | 2004-05-13 20:21:25 +0000 | [diff] [blame] | 1959 | if (!(nameW = FILE_name_AtoW( name, FALSE ))) return FALSE; |
| 1960 | return SetFileAttributesW( nameW, attributes ); |
Alexandre Julliard | 174e2a6 | 2004-04-20 00:36:29 +0000 | [diff] [blame] | 1961 | } |
| 1962 | |
| 1963 | |
Alexandre Julliard | e440932 | 2004-04-20 04:06:49 +0000 | [diff] [blame] | 1964 | /************************************************************************** |
| 1965 | * GetFileAttributesExW (KERNEL32.@) |
| 1966 | */ |
| 1967 | BOOL WINAPI GetFileAttributesExW( LPCWSTR name, GET_FILEEX_INFO_LEVELS level, LPVOID ptr ) |
| 1968 | { |
| 1969 | FILE_NETWORK_OPEN_INFORMATION info; |
| 1970 | WIN32_FILE_ATTRIBUTE_DATA *data = ptr; |
| 1971 | UNICODE_STRING nt_name; |
| 1972 | OBJECT_ATTRIBUTES attr; |
| 1973 | NTSTATUS status; |
Christian Costa | fe0460f | 2004-05-22 03:13:56 +0000 | [diff] [blame] | 1974 | |
| 1975 | TRACE("%s %d %p\n", debugstr_w(name), level, ptr); |
Alexandre Julliard | e440932 | 2004-04-20 04:06:49 +0000 | [diff] [blame] | 1976 | |
| 1977 | if (level != GetFileExInfoStandard) |
| 1978 | { |
| 1979 | SetLastError( ERROR_INVALID_PARAMETER ); |
| 1980 | return FALSE; |
| 1981 | } |
| 1982 | |
| 1983 | if (!RtlDosPathNameToNtPathName_U( name, &nt_name, NULL, NULL )) |
| 1984 | { |
| 1985 | SetLastError( ERROR_PATH_NOT_FOUND ); |
| 1986 | return FALSE; |
| 1987 | } |
| 1988 | |
| 1989 | attr.Length = sizeof(attr); |
| 1990 | attr.RootDirectory = 0; |
| 1991 | attr.Attributes = OBJ_CASE_INSENSITIVE; |
| 1992 | attr.ObjectName = &nt_name; |
| 1993 | attr.SecurityDescriptor = NULL; |
| 1994 | attr.SecurityQualityOfService = NULL; |
| 1995 | |
| 1996 | status = NtQueryFullAttributesFile( &attr, &info ); |
| 1997 | RtlFreeUnicodeString( &nt_name ); |
| 1998 | |
| 1999 | if (status != STATUS_SUCCESS) |
| 2000 | { |
| 2001 | SetLastError( RtlNtStatusToDosError(status) ); |
| 2002 | return FALSE; |
| 2003 | } |
| 2004 | |
| 2005 | data->dwFileAttributes = info.FileAttributes; |
| 2006 | data->ftCreationTime.dwLowDateTime = info.CreationTime.u.LowPart; |
| 2007 | data->ftCreationTime.dwHighDateTime = info.CreationTime.u.HighPart; |
| 2008 | data->ftLastAccessTime.dwLowDateTime = info.LastAccessTime.u.LowPart; |
| 2009 | data->ftLastAccessTime.dwHighDateTime = info.LastAccessTime.u.HighPart; |
| 2010 | data->ftLastWriteTime.dwLowDateTime = info.LastWriteTime.u.LowPart; |
| 2011 | data->ftLastWriteTime.dwHighDateTime = info.LastWriteTime.u.HighPart; |
| 2012 | data->nFileSizeLow = info.EndOfFile.u.LowPart; |
| 2013 | data->nFileSizeHigh = info.EndOfFile.u.HighPart; |
| 2014 | return TRUE; |
| 2015 | } |
| 2016 | |
| 2017 | |
| 2018 | /************************************************************************** |
| 2019 | * GetFileAttributesExA (KERNEL32.@) |
| 2020 | */ |
| 2021 | BOOL WINAPI GetFileAttributesExA( LPCSTR name, GET_FILEEX_INFO_LEVELS level, LPVOID ptr ) |
| 2022 | { |
Alexandre Julliard | 0d33e5e | 2004-05-13 20:21:25 +0000 | [diff] [blame] | 2023 | WCHAR *nameW; |
Alexandre Julliard | e440932 | 2004-04-20 04:06:49 +0000 | [diff] [blame] | 2024 | |
Alexandre Julliard | 0d33e5e | 2004-05-13 20:21:25 +0000 | [diff] [blame] | 2025 | if (!(nameW = FILE_name_AtoW( name, FALSE ))) return FALSE; |
| 2026 | return GetFileAttributesExW( nameW, level, ptr ); |
Alexandre Julliard | e440932 | 2004-04-20 04:06:49 +0000 | [diff] [blame] | 2027 | } |
| 2028 | |
| 2029 | |
| 2030 | /****************************************************************************** |
| 2031 | * GetCompressedFileSizeW (KERNEL32.@) |
| 2032 | * |
Markus Amsler | b8d9b61 | 2005-11-08 11:01:03 +0000 | [diff] [blame] | 2033 | * Get the actual number of bytes used on disk. |
| 2034 | * |
Alexandre Julliard | e440932 | 2004-04-20 04:06:49 +0000 | [diff] [blame] | 2035 | * RETURNS |
| 2036 | * Success: Low-order doubleword of number of bytes |
| 2037 | * Failure: INVALID_FILE_SIZE |
| 2038 | */ |
| 2039 | DWORD WINAPI GetCompressedFileSizeW( |
| 2040 | LPCWSTR name, /* [in] Pointer to name of file */ |
| 2041 | LPDWORD size_high ) /* [out] Receives high-order doubleword of size */ |
| 2042 | { |
| 2043 | UNICODE_STRING nt_name; |
| 2044 | OBJECT_ATTRIBUTES attr; |
| 2045 | IO_STATUS_BLOCK io; |
| 2046 | NTSTATUS status; |
| 2047 | HANDLE handle; |
| 2048 | DWORD ret = INVALID_FILE_SIZE; |
| 2049 | |
Christian Costa | fe0460f | 2004-05-22 03:13:56 +0000 | [diff] [blame] | 2050 | TRACE("%s %p\n", debugstr_w(name), size_high); |
| 2051 | |
Alexandre Julliard | e440932 | 2004-04-20 04:06:49 +0000 | [diff] [blame] | 2052 | if (!RtlDosPathNameToNtPathName_U( name, &nt_name, NULL, NULL )) |
| 2053 | { |
| 2054 | SetLastError( ERROR_PATH_NOT_FOUND ); |
| 2055 | return INVALID_FILE_SIZE; |
| 2056 | } |
| 2057 | |
| 2058 | attr.Length = sizeof(attr); |
| 2059 | attr.RootDirectory = 0; |
| 2060 | attr.Attributes = OBJ_CASE_INSENSITIVE; |
| 2061 | attr.ObjectName = &nt_name; |
| 2062 | attr.SecurityDescriptor = NULL; |
| 2063 | attr.SecurityQualityOfService = NULL; |
| 2064 | |
| 2065 | status = NtOpenFile( &handle, 0, &attr, &io, 0, FILE_SYNCHRONOUS_IO_NONALERT ); |
| 2066 | RtlFreeUnicodeString( &nt_name ); |
| 2067 | |
| 2068 | if (status == STATUS_SUCCESS) |
| 2069 | { |
| 2070 | /* we don't support compressed files, simply return the file size */ |
| 2071 | ret = GetFileSize( handle, size_high ); |
| 2072 | NtClose( handle ); |
| 2073 | } |
| 2074 | else SetLastError( RtlNtStatusToDosError(status) ); |
| 2075 | |
| 2076 | return ret; |
| 2077 | } |
| 2078 | |
| 2079 | |
| 2080 | /****************************************************************************** |
| 2081 | * GetCompressedFileSizeA (KERNEL32.@) |
Markus Amsler | b8d9b61 | 2005-11-08 11:01:03 +0000 | [diff] [blame] | 2082 | * |
| 2083 | * See GetCompressedFileSizeW. |
Alexandre Julliard | e440932 | 2004-04-20 04:06:49 +0000 | [diff] [blame] | 2084 | */ |
| 2085 | DWORD WINAPI GetCompressedFileSizeA( LPCSTR name, LPDWORD size_high ) |
| 2086 | { |
Alexandre Julliard | 0d33e5e | 2004-05-13 20:21:25 +0000 | [diff] [blame] | 2087 | WCHAR *nameW; |
Alexandre Julliard | e440932 | 2004-04-20 04:06:49 +0000 | [diff] [blame] | 2088 | |
Alexandre Julliard | 0d33e5e | 2004-05-13 20:21:25 +0000 | [diff] [blame] | 2089 | if (!(nameW = FILE_name_AtoW( name, FALSE ))) return INVALID_FILE_SIZE; |
| 2090 | return GetCompressedFileSizeW( nameW, size_high ); |
Alexandre Julliard | e440932 | 2004-04-20 04:06:49 +0000 | [diff] [blame] | 2091 | } |
| 2092 | |
| 2093 | |
Alexandre Julliard | 5bfafc9 | 2004-03-25 05:36:08 +0000 | [diff] [blame] | 2094 | /*********************************************************************** |
| 2095 | * OpenFile (KERNEL32.@) |
| 2096 | */ |
| 2097 | HFILE WINAPI OpenFile( LPCSTR name, OFSTRUCT *ofs, UINT mode ) |
| 2098 | { |
| 2099 | HANDLE handle; |
| 2100 | FILETIME filetime; |
| 2101 | WORD filedatetime[2]; |
| 2102 | |
| 2103 | if (!ofs) return HFILE_ERROR; |
| 2104 | |
| 2105 | TRACE("%s %s %s %s%s%s%s%s%s%s%s%s\n",name, |
| 2106 | ((mode & 0x3 )==OF_READ)?"OF_READ": |
| 2107 | ((mode & 0x3 )==OF_WRITE)?"OF_WRITE": |
| 2108 | ((mode & 0x3 )==OF_READWRITE)?"OF_READWRITE":"unknown", |
| 2109 | ((mode & 0x70 )==OF_SHARE_COMPAT)?"OF_SHARE_COMPAT": |
| 2110 | ((mode & 0x70 )==OF_SHARE_DENY_NONE)?"OF_SHARE_DENY_NONE": |
| 2111 | ((mode & 0x70 )==OF_SHARE_DENY_READ)?"OF_SHARE_DENY_READ": |
| 2112 | ((mode & 0x70 )==OF_SHARE_DENY_WRITE)?"OF_SHARE_DENY_WRITE": |
| 2113 | ((mode & 0x70 )==OF_SHARE_EXCLUSIVE)?"OF_SHARE_EXCLUSIVE":"unknown", |
| 2114 | ((mode & OF_PARSE )==OF_PARSE)?"OF_PARSE ":"", |
| 2115 | ((mode & OF_DELETE )==OF_DELETE)?"OF_DELETE ":"", |
| 2116 | ((mode & OF_VERIFY )==OF_VERIFY)?"OF_VERIFY ":"", |
| 2117 | ((mode & OF_SEARCH )==OF_SEARCH)?"OF_SEARCH ":"", |
| 2118 | ((mode & OF_CANCEL )==OF_CANCEL)?"OF_CANCEL ":"", |
| 2119 | ((mode & OF_CREATE )==OF_CREATE)?"OF_CREATE ":"", |
| 2120 | ((mode & OF_PROMPT )==OF_PROMPT)?"OF_PROMPT ":"", |
| 2121 | ((mode & OF_EXIST )==OF_EXIST)?"OF_EXIST ":"", |
| 2122 | ((mode & OF_REOPEN )==OF_REOPEN)?"OF_REOPEN ":"" |
| 2123 | ); |
| 2124 | |
| 2125 | |
| 2126 | ofs->cBytes = sizeof(OFSTRUCT); |
| 2127 | ofs->nErrCode = 0; |
| 2128 | if (mode & OF_REOPEN) name = ofs->szPathName; |
| 2129 | |
| 2130 | if (!name) return HFILE_ERROR; |
| 2131 | |
| 2132 | TRACE("%s %04x\n", name, mode ); |
| 2133 | |
| 2134 | /* the watcom 10.6 IDE relies on a valid path returned in ofs->szPathName |
| 2135 | Are there any cases where getting the path here is wrong? |
| 2136 | Uwe Bonnes 1997 Apr 2 */ |
| 2137 | if (!GetFullPathNameA( name, sizeof(ofs->szPathName), ofs->szPathName, NULL )) goto error; |
| 2138 | |
| 2139 | /* OF_PARSE simply fills the structure */ |
| 2140 | |
| 2141 | if (mode & OF_PARSE) |
| 2142 | { |
| 2143 | ofs->fFixedDisk = (GetDriveTypeA( ofs->szPathName ) != DRIVE_REMOVABLE); |
| 2144 | TRACE("(%s): OF_PARSE, res = '%s'\n", name, ofs->szPathName ); |
| 2145 | return 0; |
| 2146 | } |
| 2147 | |
| 2148 | /* OF_CREATE is completely different from all other options, so |
| 2149 | handle it first */ |
| 2150 | |
| 2151 | if (mode & OF_CREATE) |
| 2152 | { |
Alexandre Julliard | 2f8fd10 | 2004-05-03 20:20:54 +0000 | [diff] [blame] | 2153 | if ((handle = create_file_OF( name, mode )) == INVALID_HANDLE_VALUE) |
Alexandre Julliard | 5bfafc9 | 2004-03-25 05:36:08 +0000 | [diff] [blame] | 2154 | goto error; |
| 2155 | } |
| 2156 | else |
| 2157 | { |
| 2158 | /* Now look for the file */ |
| 2159 | |
| 2160 | if (!SearchPathA( NULL, name, NULL, sizeof(ofs->szPathName), ofs->szPathName, NULL )) |
| 2161 | goto error; |
| 2162 | |
| 2163 | TRACE("found %s\n", debugstr_a(ofs->szPathName) ); |
| 2164 | |
| 2165 | if (mode & OF_DELETE) |
| 2166 | { |
| 2167 | if (!DeleteFileA( ofs->szPathName )) goto error; |
| 2168 | TRACE("(%s): OF_DELETE return = OK\n", name); |
| 2169 | return TRUE; |
| 2170 | } |
| 2171 | |
| 2172 | handle = (HANDLE)_lopen( ofs->szPathName, mode ); |
| 2173 | if (handle == INVALID_HANDLE_VALUE) goto error; |
| 2174 | |
| 2175 | GetFileTime( handle, NULL, NULL, &filetime ); |
| 2176 | FileTimeToDosDateTime( &filetime, &filedatetime[0], &filedatetime[1] ); |
| 2177 | if ((mode & OF_VERIFY) && (mode & OF_REOPEN)) |
| 2178 | { |
| 2179 | if (ofs->Reserved1 != filedatetime[0] || ofs->Reserved2 != filedatetime[1] ) |
| 2180 | { |
| 2181 | CloseHandle( handle ); |
| 2182 | WARN("(%s): OF_VERIFY failed\n", name ); |
| 2183 | /* FIXME: what error here? */ |
| 2184 | SetLastError( ERROR_FILE_NOT_FOUND ); |
| 2185 | goto error; |
| 2186 | } |
| 2187 | } |
| 2188 | ofs->Reserved1 = filedatetime[0]; |
| 2189 | ofs->Reserved2 = filedatetime[1]; |
| 2190 | } |
| 2191 | TRACE("(%s): OK, return = %p\n", name, handle ); |
| 2192 | if (mode & OF_EXIST) /* Return TRUE instead of a handle */ |
| 2193 | { |
| 2194 | CloseHandle( handle ); |
| 2195 | return TRUE; |
| 2196 | } |
| 2197 | else return (HFILE)handle; |
| 2198 | |
| 2199 | error: /* We get here if there was an error opening the file */ |
| 2200 | ofs->nErrCode = GetLastError(); |
| 2201 | WARN("(%s): return = HFILE_ERROR error= %d\n", name,ofs->nErrCode ); |
Alexandre Julliard | 7886cac | 2005-10-18 10:39:15 +0000 | [diff] [blame] | 2202 | return HFILE_ERROR; |
Alexandre Julliard | 5bfafc9 | 2004-03-25 05:36:08 +0000 | [diff] [blame] | 2203 | } |