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