Use a linked list instead of a DPA for the hook list.
[wine.git] / files / file.c
blobe805994cc60e0be93a814efeac98f7c43240c306
1 /*
2 * File handling functions
4 * Copyright 1993 John Burton
5 * Copyright 1996 Alexandre Julliard
7 * TODO:
8 * Fix the CopyFileEx methods to implement the "extented" functionality.
9 * Right now, they simply call the CopyFile method.
12 #include "config.h"
14 #include <assert.h>
15 #include <ctype.h>
16 #include <errno.h>
17 #include <fcntl.h>
18 #include <stdlib.h>
19 #include <string.h>
20 #ifdef HAVE_SYS_ERRNO_H
21 #include <sys/errno.h>
22 #endif
23 #include <sys/types.h>
24 #include <sys/stat.h>
25 #ifdef HAVE_SYS_MMAN_H
26 #include <sys/mman.h>
27 #endif
28 #include <sys/time.h>
29 #include <time.h>
30 #include <unistd.h>
31 #include <utime.h>
33 #include "winerror.h"
34 #include "windef.h"
35 #include "winbase.h"
36 #include "wine/winbase16.h"
37 #include "wine/winestring.h"
38 #include "drive.h"
39 #include "device.h"
40 #include "file.h"
41 #include "global.h"
42 #include "heap.h"
43 #include "msdos.h"
44 #include "options.h"
45 #include "ldt.h"
46 #include "process.h"
47 #include "task.h"
48 #include "wincon.h"
49 #include "debugtools.h"
51 #include "server.h"
53 DEFAULT_DEBUG_CHANNEL(file)
55 #if defined(MAP_ANONYMOUS) && !defined(MAP_ANON)
56 #define MAP_ANON MAP_ANONYMOUS
57 #endif
59 /* Size of per-process table of DOS handles */
60 #define DOS_TABLE_SIZE 256
63 /***********************************************************************
64 * FILE_ConvertOFMode
66 * Convert OF_* mode into flags for CreateFile.
68 static void FILE_ConvertOFMode( INT mode, DWORD *access, DWORD *sharing )
70 switch(mode & 0x03)
72 case OF_READ: *access = GENERIC_READ; break;
73 case OF_WRITE: *access = GENERIC_WRITE; break;
74 case OF_READWRITE: *access = GENERIC_READ | GENERIC_WRITE; break;
75 default: *access = 0; break;
77 switch(mode & 0x70)
79 case OF_SHARE_EXCLUSIVE: *sharing = 0; break;
80 case OF_SHARE_DENY_WRITE: *sharing = FILE_SHARE_READ; break;
81 case OF_SHARE_DENY_READ: *sharing = FILE_SHARE_WRITE; break;
82 case OF_SHARE_DENY_NONE:
83 case OF_SHARE_COMPAT:
84 default: *sharing = FILE_SHARE_READ | FILE_SHARE_WRITE; break;
89 #if 0
90 /***********************************************************************
91 * FILE_ShareDeny
93 * PARAMS
94 * oldmode[I] mode how file was first opened
95 * mode[I] mode how the file should get opened
96 * RETURNS
97 * TRUE: deny open
98 * FALSE: allow open
100 * Look what we have to do with the given SHARE modes
102 * Ralph Brown's interrupt list gives following explication, I guess
103 * the same holds for Windows, DENY ALL should be OF_SHARE_COMPAT
105 * FIXME: Validate this function
106 ========from Ralph Brown's list =========
107 (Table 0750)
108 Values of DOS file sharing behavior:
109 | Second and subsequent Opens
110 First |Compat Deny Deny Deny Deny
111 Open | All Write Read None
112 |R W RW R W RW R W RW R W RW R W RW
113 - - - - -| - - - - - - - - - - - - - - - - -
114 Compat R |Y Y Y N N N 1 N N N N N 1 N N
115 W |Y Y Y N N N N N N N N N N N N
116 RW|Y Y Y N N N N N N N N N N N N
117 - - - - -|
118 Deny R |C C C N N N N N N N N N N N N
119 All W |C C C N N N N N N N N N N N N
120 RW|C C C N N N N N N N N N N N N
121 - - - - -|
122 Deny R |2 C C N N N Y N N N N N Y N N
123 Write W |C C C N N N N N N Y N N Y N N
124 RW|C C C N N N N N N N N N Y N N
125 - - - - -|
126 Deny R |C C C N N N N Y N N N N N Y N
127 Read W |C C C N N N N N N N Y N N Y N
128 RW|C C C N N N N N N N N N N Y N
129 - - - - -|
130 Deny R |2 C C N N N Y Y Y N N N Y Y Y
131 None W |C C C N N N N N N Y Y Y Y Y Y
132 RW|C C C N N N N N N N N N Y Y Y
133 Legend: Y = open succeeds, N = open fails with error code 05h
134 C = open fails, INT 24 generated
135 1 = open succeeds if file read-only, else fails with error code
136 2 = open succeeds if file read-only, else fails with INT 24
137 ========end of description from Ralph Brown's List =====
138 For every "Y" in the table we return FALSE
139 For every "N" we set the DOS_ERROR and return TRUE
140 For all other cases we barf,set the DOS_ERROR and return TRUE
143 static BOOL FILE_ShareDeny( int mode, int oldmode)
145 int oldsharemode = oldmode & 0x70;
146 int sharemode = mode & 0x70;
147 int oldopenmode = oldmode & 3;
148 int openmode = mode & 3;
150 switch (oldsharemode)
152 case OF_SHARE_COMPAT:
153 if (sharemode == OF_SHARE_COMPAT) return FALSE;
154 if (openmode == OF_READ) goto test_ro_err05 ;
155 goto fail_error05;
156 case OF_SHARE_EXCLUSIVE:
157 if (sharemode == OF_SHARE_COMPAT) goto fail_int24;
158 goto fail_error05;
159 case OF_SHARE_DENY_WRITE:
160 if (openmode != OF_READ)
162 if (sharemode == OF_SHARE_COMPAT) goto fail_int24;
163 goto fail_error05;
165 switch (sharemode)
167 case OF_SHARE_COMPAT:
168 if (oldopenmode == OF_READ) goto test_ro_int24 ;
169 goto fail_int24;
170 case OF_SHARE_DENY_NONE :
171 return FALSE;
172 case OF_SHARE_DENY_WRITE :
173 if (oldopenmode == OF_READ) return FALSE;
174 case OF_SHARE_DENY_READ :
175 if (oldopenmode == OF_WRITE) return FALSE;
176 case OF_SHARE_EXCLUSIVE:
177 default:
178 goto fail_error05;
180 break;
181 case OF_SHARE_DENY_READ:
182 if (openmode != OF_WRITE)
184 if (sharemode == OF_SHARE_COMPAT) goto fail_int24;
185 goto fail_error05;
187 switch (sharemode)
189 case OF_SHARE_COMPAT:
190 goto fail_int24;
191 case OF_SHARE_DENY_NONE :
192 return FALSE;
193 case OF_SHARE_DENY_WRITE :
194 if (oldopenmode == OF_READ) return FALSE;
195 case OF_SHARE_DENY_READ :
196 if (oldopenmode == OF_WRITE) return FALSE;
197 case OF_SHARE_EXCLUSIVE:
198 default:
199 goto fail_error05;
201 break;
202 case OF_SHARE_DENY_NONE:
203 switch (sharemode)
205 case OF_SHARE_COMPAT:
206 goto fail_int24;
207 case OF_SHARE_DENY_NONE :
208 return FALSE;
209 case OF_SHARE_DENY_WRITE :
210 if (oldopenmode == OF_READ) return FALSE;
211 case OF_SHARE_DENY_READ :
212 if (oldopenmode == OF_WRITE) return FALSE;
213 case OF_SHARE_EXCLUSIVE:
214 default:
215 goto fail_error05;
217 default:
218 ERR("unknown mode\n");
220 ERR("shouldn't happen\n");
221 ERR("Please report to bon@elektron.ikp.physik.tu-darmstadt.de\n");
222 return TRUE;
224 test_ro_int24:
225 if (oldmode == OF_READ)
226 return FALSE;
227 /* Fall through */
228 fail_int24:
229 FIXME("generate INT24 missing\n");
230 /* Is this the right error? */
231 SetLastError( ERROR_ACCESS_DENIED );
232 return TRUE;
234 test_ro_err05:
235 if (oldmode == OF_READ)
236 return FALSE;
237 /* fall through */
238 fail_error05:
239 TRACE("Access Denied, oldmode 0x%02x mode 0x%02x\n",oldmode,mode);
240 SetLastError( ERROR_ACCESS_DENIED );
241 return TRUE;
243 #endif
246 /***********************************************************************
247 * FILE_SetDosError
249 * Set the DOS error code from errno.
251 void FILE_SetDosError(void)
253 int save_errno = errno; /* errno gets overwritten by printf */
255 TRACE("errno = %d %s\n", errno, strerror(errno));
256 switch (save_errno)
258 case EAGAIN:
259 SetLastError( ERROR_SHARING_VIOLATION );
260 break;
261 case EBADF:
262 SetLastError( ERROR_INVALID_HANDLE );
263 break;
264 case ENOSPC:
265 SetLastError( ERROR_HANDLE_DISK_FULL );
266 break;
267 case EACCES:
268 case EPERM:
269 case EROFS:
270 SetLastError( ERROR_ACCESS_DENIED );
271 break;
272 case EBUSY:
273 SetLastError( ERROR_LOCK_VIOLATION );
274 break;
275 case ENOENT:
276 SetLastError( ERROR_FILE_NOT_FOUND );
277 break;
278 case EISDIR:
279 SetLastError( ERROR_CANNOT_MAKE );
280 break;
281 case ENFILE:
282 case EMFILE:
283 SetLastError( ERROR_NO_MORE_FILES );
284 break;
285 case EEXIST:
286 SetLastError( ERROR_FILE_EXISTS );
287 break;
288 case EINVAL:
289 case ESPIPE:
290 SetLastError( ERROR_SEEK );
291 break;
292 case ENOTEMPTY:
293 SetLastError( ERROR_DIR_NOT_EMPTY );
294 break;
295 default:
296 perror( "int21: unknown errno" );
297 SetLastError( ERROR_GEN_FAILURE );
298 break;
300 errno = save_errno;
304 /***********************************************************************
305 * FILE_DupUnixHandle
307 * Duplicate a Unix handle into a task handle.
309 HFILE FILE_DupUnixHandle( int fd, DWORD access )
311 int unix_handle;
312 struct alloc_file_handle_request *req = get_req_buffer();
314 if ((unix_handle = dup(fd)) == -1)
316 FILE_SetDosError();
317 return INVALID_HANDLE_VALUE;
319 req->access = access;
320 server_call_fd( REQ_ALLOC_FILE_HANDLE, unix_handle, NULL );
321 return req->handle;
325 /***********************************************************************
326 * FILE_CreateFile
328 * Implementation of CreateFile. Takes a Unix path name.
330 HANDLE FILE_CreateFile( LPCSTR filename, DWORD access, DWORD sharing,
331 LPSECURITY_ATTRIBUTES sa, DWORD creation,
332 DWORD attributes, HANDLE template )
334 struct create_file_request *req = get_req_buffer();
336 req->access = access;
337 req->inherit = (sa && (sa->nLength>=sizeof(*sa)) && sa->bInheritHandle);
338 req->sharing = sharing;
339 req->create = creation;
340 req->attrs = attributes;
341 lstrcpynA( req->name, filename, server_remaining(req->name) );
342 SetLastError(0);
343 server_call( REQ_CREATE_FILE );
345 /* If write access failed, retry without GENERIC_WRITE */
347 if ((req->handle == -1) && !Options.failReadOnly &&
348 (access & GENERIC_WRITE))
350 DWORD lasterror = GetLastError();
351 if ((lasterror == ERROR_ACCESS_DENIED) || (lasterror == ERROR_WRITE_PROTECT))
352 return FILE_CreateFile( filename, access & ~GENERIC_WRITE, sharing,
353 sa, creation, attributes, template );
355 return req->handle;
359 /***********************************************************************
360 * FILE_CreateDevice
362 * Same as FILE_CreateFile but for a device
364 HFILE FILE_CreateDevice( int client_id, DWORD access, LPSECURITY_ATTRIBUTES sa )
366 struct create_device_request *req = get_req_buffer();
368 req->access = access;
369 req->inherit = (sa && (sa->nLength>=sizeof(*sa)) && sa->bInheritHandle);
370 req->id = client_id;
371 SetLastError(0);
372 server_call( REQ_CREATE_DEVICE );
373 return req->handle;
377 /*************************************************************************
378 * CreateFile32A [KERNEL32.45] Creates or opens a file or other object
380 * Creates or opens an object, and returns a handle that can be used to
381 * access that object.
383 * PARAMS
385 * filename [I] pointer to filename to be accessed
386 * access [I] access mode requested
387 * sharing [I] share mode
388 * sa [I] pointer to security attributes
389 * creation [I] how to create the file
390 * attributes [I] attributes for newly created file
391 * template [I] handle to file with extended attributes to copy
393 * RETURNS
394 * Success: Open handle to specified file
395 * Failure: INVALID_HANDLE_VALUE
397 * NOTES
398 * Should call SetLastError() on failure.
400 * BUGS
402 * Doesn't support character devices, pipes, template files, or a
403 * lot of the 'attributes' flags yet.
405 HANDLE WINAPI CreateFileA( LPCSTR filename, DWORD access, DWORD sharing,
406 LPSECURITY_ATTRIBUTES sa, DWORD creation,
407 DWORD attributes, HANDLE template )
409 DOS_FULL_NAME full_name;
411 if (!filename)
413 SetLastError( ERROR_INVALID_PARAMETER );
414 return HFILE_ERROR;
416 TRACE("%s %s%s%s%s%s%s%s\n",filename,
417 ((access & GENERIC_READ)==GENERIC_READ)?"GENERIC_READ ":"",
418 ((access & GENERIC_WRITE)==GENERIC_WRITE)?"GENERIC_WRITE ":"",
419 (!access)?"QUERY_ACCESS ":"",
420 ((sharing & FILE_SHARE_READ)==FILE_SHARE_READ)?"FILE_SHARE_READ ":"",
421 ((sharing & FILE_SHARE_WRITE)==FILE_SHARE_WRITE)?"FILE_SHARE_WRITE ":"",
422 ((sharing & FILE_SHARE_DELETE)==FILE_SHARE_DELETE)?"FILE_SHARE_DELETE ":"",
423 (creation ==CREATE_NEW)?"CREATE_NEW":
424 (creation ==CREATE_ALWAYS)?"CREATE_ALWAYS ":
425 (creation ==OPEN_EXISTING)?"OPEN_EXISTING ":
426 (creation ==OPEN_ALWAYS)?"OPEN_ALWAYS ":
427 (creation ==TRUNCATE_EXISTING)?"TRUNCATE_EXISTING ":"");
429 /* If the name starts with '\\?\', ignore the first 4 chars. */
430 if (!strncmp(filename, "\\\\?\\", 4))
432 filename += 4;
433 if (!strncmp(filename, "UNC\\", 4))
435 FIXME("UNC name (%s) not supported.\n", filename );
436 SetLastError( ERROR_PATH_NOT_FOUND );
437 return HFILE_ERROR;
441 if (!strncmp(filename, "\\\\.\\", 4)) {
442 if (!DOSFS_GetDevice( filename ))
443 return DEVICE_Open( filename+4, access, sa );
444 else
445 filename+=4; /* fall into DOSFS_Device case below */
448 /* If the name still starts with '\\', it's a UNC name. */
449 if (!strncmp(filename, "\\\\", 2))
451 FIXME("UNC name (%s) not supported.\n", filename );
452 SetLastError( ERROR_PATH_NOT_FOUND );
453 return HFILE_ERROR;
456 /* If the name contains a DOS wild card (* or ?), do no create a file */
457 if(strchr(filename,'*') || strchr(filename,'?'))
458 return HFILE_ERROR;
460 /* Open a console for CONIN$ or CONOUT$ */
461 if (!lstrcmpiA(filename, "CONIN$")) return CONSOLE_OpenHandle( FALSE, access, sa );
462 if (!lstrcmpiA(filename, "CONOUT$")) return CONSOLE_OpenHandle( TRUE, access, sa );
464 if (DOSFS_GetDevice( filename ))
466 HFILE ret;
468 TRACE("opening device '%s'\n", filename );
470 if (HFILE_ERROR!=(ret=DOSFS_OpenDevice( filename, access )))
471 return ret;
473 /* Do not silence this please. It is a critical error. -MM */
474 ERR("Couldn't open device '%s'!\n",filename);
475 SetLastError( ERROR_FILE_NOT_FOUND );
476 return HFILE_ERROR;
479 /* check for filename, don't check for last entry if creating */
480 if (!DOSFS_GetFullName( filename,
481 (creation == OPEN_EXISTING) || (creation == TRUNCATE_EXISTING), &full_name ))
482 return HFILE_ERROR;
484 return FILE_CreateFile( full_name.long_name, access, sharing,
485 sa, creation, attributes, template );
490 /*************************************************************************
491 * CreateFile32W (KERNEL32.48)
493 HANDLE WINAPI CreateFileW( LPCWSTR filename, DWORD access, DWORD sharing,
494 LPSECURITY_ATTRIBUTES sa, DWORD creation,
495 DWORD attributes, HANDLE template)
497 LPSTR afn = HEAP_strdupWtoA( GetProcessHeap(), 0, filename );
498 HANDLE res = CreateFileA( afn, access, sharing, sa, creation, attributes, template );
499 HeapFree( GetProcessHeap(), 0, afn );
500 return res;
504 /***********************************************************************
505 * FILE_FillInfo
507 * Fill a file information from a struct stat.
509 static void FILE_FillInfo( struct stat *st, BY_HANDLE_FILE_INFORMATION *info )
511 if (S_ISDIR(st->st_mode))
512 info->dwFileAttributes = FILE_ATTRIBUTE_DIRECTORY;
513 else
514 info->dwFileAttributes = FILE_ATTRIBUTE_ARCHIVE;
515 if (!(st->st_mode & S_IWUSR))
516 info->dwFileAttributes |= FILE_ATTRIBUTE_READONLY;
518 DOSFS_UnixTimeToFileTime( st->st_mtime, &info->ftCreationTime, 0 );
519 DOSFS_UnixTimeToFileTime( st->st_mtime, &info->ftLastWriteTime, 0 );
520 DOSFS_UnixTimeToFileTime( st->st_atime, &info->ftLastAccessTime, 0 );
522 info->dwVolumeSerialNumber = 0; /* FIXME */
523 info->nFileSizeHigh = 0;
524 info->nFileSizeLow = S_ISDIR(st->st_mode) ? 0 : st->st_size;
525 info->nNumberOfLinks = st->st_nlink;
526 info->nFileIndexHigh = 0;
527 info->nFileIndexLow = st->st_ino;
531 /***********************************************************************
532 * FILE_Stat
534 * Stat a Unix path name. Return TRUE if OK.
536 BOOL FILE_Stat( LPCSTR unixName, BY_HANDLE_FILE_INFORMATION *info )
538 struct stat st;
540 if (!unixName || !info) return FALSE;
542 if (stat( unixName, &st ) == -1)
544 FILE_SetDosError();
545 return FALSE;
547 FILE_FillInfo( &st, info );
548 return TRUE;
552 /***********************************************************************
553 * GetFileInformationByHandle (KERNEL32.219)
555 DWORD WINAPI GetFileInformationByHandle( HANDLE hFile,
556 BY_HANDLE_FILE_INFORMATION *info )
558 struct get_file_info_request *req = get_req_buffer();
560 if (!info) return 0;
561 req->handle = hFile;
562 if (server_call( REQ_GET_FILE_INFO )) return 0;
563 DOSFS_UnixTimeToFileTime( req->write_time, &info->ftCreationTime, 0 );
564 DOSFS_UnixTimeToFileTime( req->write_time, &info->ftLastWriteTime, 0 );
565 DOSFS_UnixTimeToFileTime( req->access_time, &info->ftLastAccessTime, 0 );
566 info->dwFileAttributes = req->attr;
567 info->dwVolumeSerialNumber = req->serial;
568 info->nFileSizeHigh = req->size_high;
569 info->nFileSizeLow = req->size_low;
570 info->nNumberOfLinks = req->links;
571 info->nFileIndexHigh = req->index_high;
572 info->nFileIndexLow = req->index_low;
573 return 1;
577 /**************************************************************************
578 * GetFileAttributes16 (KERNEL.420)
580 DWORD WINAPI GetFileAttributes16( LPCSTR name )
582 return GetFileAttributesA( name );
586 /**************************************************************************
587 * GetFileAttributes32A (KERNEL32.217)
589 DWORD WINAPI GetFileAttributesA( LPCSTR name )
591 DOS_FULL_NAME full_name;
592 BY_HANDLE_FILE_INFORMATION info;
594 if (name == NULL || *name=='\0') return -1;
596 if (!DOSFS_GetFullName( name, TRUE, &full_name )) return -1;
597 if (!FILE_Stat( full_name.long_name, &info )) return -1;
598 return info.dwFileAttributes;
602 /**************************************************************************
603 * GetFileAttributes32W (KERNEL32.218)
605 DWORD WINAPI GetFileAttributesW( LPCWSTR name )
607 LPSTR nameA = HEAP_strdupWtoA( GetProcessHeap(), 0, name );
608 DWORD res = GetFileAttributesA( nameA );
609 HeapFree( GetProcessHeap(), 0, nameA );
610 return res;
614 /***********************************************************************
615 * GetFileSize (KERNEL32.220)
617 DWORD WINAPI GetFileSize( HANDLE hFile, LPDWORD filesizehigh )
619 BY_HANDLE_FILE_INFORMATION info;
620 if (!GetFileInformationByHandle( hFile, &info )) return 0;
621 if (filesizehigh) *filesizehigh = info.nFileSizeHigh;
622 return info.nFileSizeLow;
626 /***********************************************************************
627 * GetFileTime (KERNEL32.221)
629 BOOL WINAPI GetFileTime( HANDLE hFile, FILETIME *lpCreationTime,
630 FILETIME *lpLastAccessTime,
631 FILETIME *lpLastWriteTime )
633 BY_HANDLE_FILE_INFORMATION info;
634 if (!GetFileInformationByHandle( hFile, &info )) return FALSE;
635 if (lpCreationTime) *lpCreationTime = info.ftCreationTime;
636 if (lpLastAccessTime) *lpLastAccessTime = info.ftLastAccessTime;
637 if (lpLastWriteTime) *lpLastWriteTime = info.ftLastWriteTime;
638 return TRUE;
641 /***********************************************************************
642 * CompareFileTime (KERNEL32.28)
644 INT WINAPI CompareFileTime( LPFILETIME x, LPFILETIME y )
646 if (!x || !y) return -1;
648 if (x->dwHighDateTime > y->dwHighDateTime)
649 return 1;
650 if (x->dwHighDateTime < y->dwHighDateTime)
651 return -1;
652 if (x->dwLowDateTime > y->dwLowDateTime)
653 return 1;
654 if (x->dwLowDateTime < y->dwLowDateTime)
655 return -1;
656 return 0;
659 /***********************************************************************
660 * FILE_GetTempFileName : utility for GetTempFileName
662 static UINT FILE_GetTempFileName( LPCSTR path, LPCSTR prefix, UINT unique,
663 LPSTR buffer, BOOL isWin16 )
665 static UINT unique_temp;
666 DOS_FULL_NAME full_name;
667 int i;
668 LPSTR p;
669 UINT num;
671 if ( !path || !prefix || !buffer ) return 0;
673 if (!unique_temp) unique_temp = time(NULL) & 0xffff;
674 num = unique ? (unique & 0xffff) : (unique_temp++ & 0xffff);
676 strcpy( buffer, path );
677 p = buffer + strlen(buffer);
679 /* add a \, if there isn't one and path is more than just the drive letter ... */
680 if ( !((strlen(buffer) == 2) && (buffer[1] == ':'))
681 && ((p == buffer) || (p[-1] != '\\'))) *p++ = '\\';
683 if (isWin16) *p++ = '~';
684 for (i = 3; (i > 0) && (*prefix); i--) *p++ = *prefix++;
685 sprintf( p, "%04x.tmp", num );
687 /* Now try to create it */
689 if (!unique)
693 HFILE handle = CreateFileA( buffer, GENERIC_WRITE, 0, NULL,
694 CREATE_NEW, FILE_ATTRIBUTE_NORMAL, -1 );
695 if (handle != INVALID_HANDLE_VALUE)
696 { /* We created it */
697 TRACE("created %s\n",
698 buffer);
699 CloseHandle( handle );
700 break;
702 if (GetLastError() != ERROR_FILE_EXISTS)
703 break; /* No need to go on */
704 num++;
705 sprintf( p, "%04x.tmp", num );
706 } while (num != (unique & 0xffff));
709 /* Get the full path name */
711 if (DOSFS_GetFullName( buffer, FALSE, &full_name ))
713 /* Check if we have write access in the directory */
714 if ((p = strrchr( full_name.long_name, '/' ))) *p = '\0';
715 if (access( full_name.long_name, W_OK ) == -1)
716 WARN("returns '%s', which doesn't seem to be writeable.\n",
717 buffer);
719 TRACE("returning %s\n", buffer );
720 return unique ? unique : num;
724 /***********************************************************************
725 * GetTempFileName32A (KERNEL32.290)
727 UINT WINAPI GetTempFileNameA( LPCSTR path, LPCSTR prefix, UINT unique,
728 LPSTR buffer)
730 return FILE_GetTempFileName(path, prefix, unique, buffer, FALSE);
733 /***********************************************************************
734 * GetTempFileName32W (KERNEL32.291)
736 UINT WINAPI GetTempFileNameW( LPCWSTR path, LPCWSTR prefix, UINT unique,
737 LPWSTR buffer )
739 LPSTR patha,prefixa;
740 char buffera[144];
741 UINT ret;
743 if (!path) return 0;
744 patha = HEAP_strdupWtoA( GetProcessHeap(), 0, path );
745 prefixa = HEAP_strdupWtoA( GetProcessHeap(), 0, prefix );
746 ret = FILE_GetTempFileName( patha, prefixa, unique, buffera, FALSE );
747 lstrcpyAtoW( buffer, buffera );
748 HeapFree( GetProcessHeap(), 0, patha );
749 HeapFree( GetProcessHeap(), 0, prefixa );
750 return ret;
754 /***********************************************************************
755 * GetTempFileName16 (KERNEL.97)
757 UINT16 WINAPI GetTempFileName16( BYTE drive, LPCSTR prefix, UINT16 unique,
758 LPSTR buffer )
760 char temppath[144];
762 if (!(drive & ~TF_FORCEDRIVE)) /* drive 0 means current default drive */
763 drive |= DRIVE_GetCurrentDrive() + 'A';
765 if ((drive & TF_FORCEDRIVE) &&
766 !DRIVE_IsValid( toupper(drive & ~TF_FORCEDRIVE) - 'A' ))
768 drive &= ~TF_FORCEDRIVE;
769 WARN("invalid drive %d specified\n", drive );
772 if (drive & TF_FORCEDRIVE)
773 sprintf(temppath,"%c:", drive & ~TF_FORCEDRIVE );
774 else
775 GetTempPathA( 132, temppath );
776 return (UINT16)FILE_GetTempFileName( temppath, prefix, unique, buffer, TRUE );
779 /***********************************************************************
780 * FILE_DoOpenFile
782 * Implementation of OpenFile16() and OpenFile32().
784 static HFILE FILE_DoOpenFile( LPCSTR name, OFSTRUCT *ofs, UINT mode,
785 BOOL win32 )
787 HFILE hFileRet;
788 FILETIME filetime;
789 WORD filedatetime[2];
790 DOS_FULL_NAME full_name;
791 DWORD access, sharing;
792 char *p;
794 if (!ofs) return HFILE_ERROR;
796 TRACE("%s %s %s %s%s%s%s%s%s%s%s%s\n",name,
797 ((mode & 0x3 )==OF_READ)?"OF_READ":
798 ((mode & 0x3 )==OF_WRITE)?"OF_WRITE":
799 ((mode & 0x3 )==OF_READWRITE)?"OF_READWRITE":"unknown",
800 ((mode & 0x70 )==OF_SHARE_COMPAT)?"OF_SHARE_COMPAT":
801 ((mode & 0x70 )==OF_SHARE_DENY_NONE)?"OF_SHARE_DENY_NONE":
802 ((mode & 0x70 )==OF_SHARE_DENY_READ)?"OF_SHARE_DENY_READ":
803 ((mode & 0x70 )==OF_SHARE_DENY_WRITE)?"OF_SHARE_DENY_WRITE":
804 ((mode & 0x70 )==OF_SHARE_EXCLUSIVE)?"OF_SHARE_EXCLUSIVE":"unknown",
805 ((mode & OF_PARSE )==OF_PARSE)?"OF_PARSE ":"",
806 ((mode & OF_DELETE )==OF_DELETE)?"OF_DELETE ":"",
807 ((mode & OF_VERIFY )==OF_VERIFY)?"OF_VERIFY ":"",
808 ((mode & OF_SEARCH )==OF_SEARCH)?"OF_SEARCH ":"",
809 ((mode & OF_CANCEL )==OF_CANCEL)?"OF_CANCEL ":"",
810 ((mode & OF_CREATE )==OF_CREATE)?"OF_CREATE ":"",
811 ((mode & OF_PROMPT )==OF_PROMPT)?"OF_PROMPT ":"",
812 ((mode & OF_EXIST )==OF_EXIST)?"OF_EXIST ":"",
813 ((mode & OF_REOPEN )==OF_REOPEN)?"OF_REOPEN ":""
817 ofs->cBytes = sizeof(OFSTRUCT);
818 ofs->nErrCode = 0;
819 if (mode & OF_REOPEN) name = ofs->szPathName;
821 if (!name) {
822 ERR("called with `name' set to NULL ! Please debug.\n");
823 return HFILE_ERROR;
826 TRACE("%s %04x\n", name, mode );
828 /* the watcom 10.6 IDE relies on a valid path returned in ofs->szPathName
829 Are there any cases where getting the path here is wrong?
830 Uwe Bonnes 1997 Apr 2 */
831 if (!GetFullPathNameA( name, sizeof(ofs->szPathName),
832 ofs->szPathName, NULL )) goto error;
833 FILE_ConvertOFMode( mode, &access, &sharing );
835 /* OF_PARSE simply fills the structure */
837 if (mode & OF_PARSE)
839 ofs->fFixedDisk = (GetDriveType16( ofs->szPathName[0]-'A' )
840 != DRIVE_REMOVABLE);
841 TRACE("(%s): OF_PARSE, res = '%s'\n",
842 name, ofs->szPathName );
843 return 0;
846 /* OF_CREATE is completely different from all other options, so
847 handle it first */
849 if (mode & OF_CREATE)
851 if ((hFileRet = CreateFileA( name, GENERIC_READ | GENERIC_WRITE,
852 sharing, NULL, CREATE_ALWAYS,
853 FILE_ATTRIBUTE_NORMAL, -1 ))== INVALID_HANDLE_VALUE)
854 goto error;
855 goto success;
858 /* If OF_SEARCH is set, ignore the given path */
860 if ((mode & OF_SEARCH) && !(mode & OF_REOPEN))
862 /* First try the file name as is */
863 if (DOSFS_GetFullName( name, TRUE, &full_name )) goto found;
864 /* Now remove the path */
865 if (name[0] && (name[1] == ':')) name += 2;
866 if ((p = strrchr( name, '\\' ))) name = p + 1;
867 if ((p = strrchr( name, '/' ))) name = p + 1;
868 if (!name[0]) goto not_found;
871 /* Now look for the file */
873 if (!DIR_SearchPath( NULL, name, NULL, &full_name, win32 )) goto not_found;
875 found:
876 TRACE("found %s = %s\n",
877 full_name.long_name, full_name.short_name );
878 lstrcpynA( ofs->szPathName, full_name.short_name,
879 sizeof(ofs->szPathName) );
881 if (mode & OF_SHARE_EXCLUSIVE)
882 /* Some InstallShield version uses OF_SHARE_EXCLUSIVE
883 on the file <tempdir>/_ins0432._mp to determine how
884 far installation has proceeded.
885 _ins0432._mp is an executable and while running the
886 application expects the open with OF_SHARE_ to fail*/
887 /* Probable FIXME:
888 As our loader closes the files after loading the executable,
889 we can't find the running executable with FILE_InUse.
890 Perhaps the loader should keep the file open.
891 Recheck against how Win handles that case */
893 char *last = strrchr(full_name.long_name,'/');
894 if (!last)
895 last = full_name.long_name - 1;
896 if (GetModuleHandle16(last+1))
898 TRACE("Denying shared open for %s\n",full_name.long_name);
899 return HFILE_ERROR;
903 if (mode & OF_DELETE)
905 if (unlink( full_name.long_name ) == -1) goto not_found;
906 TRACE("(%s): OF_DELETE return = OK\n", name);
907 return 1;
910 hFileRet = FILE_CreateFile( full_name.long_name, access, sharing,
911 NULL, OPEN_EXISTING, 0, -1 );
912 if (hFileRet == HFILE_ERROR) goto not_found;
914 GetFileTime( hFileRet, NULL, NULL, &filetime );
915 FileTimeToDosDateTime( &filetime, &filedatetime[0], &filedatetime[1] );
916 if ((mode & OF_VERIFY) && (mode & OF_REOPEN))
918 if (memcmp( ofs->reserved, filedatetime, sizeof(ofs->reserved) ))
920 CloseHandle( hFileRet );
921 WARN("(%s): OF_VERIFY failed\n", name );
922 /* FIXME: what error here? */
923 SetLastError( ERROR_FILE_NOT_FOUND );
924 goto error;
927 memcpy( ofs->reserved, filedatetime, sizeof(ofs->reserved) );
929 success: /* We get here if the open was successful */
930 TRACE("(%s): OK, return = %d\n", name, hFileRet );
931 if (win32)
933 if (mode & OF_EXIST) /* Return the handle, but close it first */
934 CloseHandle( hFileRet );
936 else
938 hFileRet = FILE_AllocDosHandle( hFileRet );
939 if (hFileRet == HFILE_ERROR16) goto error;
940 if (mode & OF_EXIST) /* Return the handle, but close it first */
941 _lclose16( hFileRet );
943 return hFileRet;
945 not_found: /* We get here if the file does not exist */
946 WARN("'%s' not found\n", name );
947 SetLastError( ERROR_FILE_NOT_FOUND );
948 /* fall through */
950 error: /* We get here if there was an error opening the file */
951 ofs->nErrCode = GetLastError();
952 WARN("(%s): return = HFILE_ERROR error= %d\n",
953 name,ofs->nErrCode );
954 return HFILE_ERROR;
958 /***********************************************************************
959 * OpenFile16 (KERNEL.74)
961 HFILE16 WINAPI OpenFile16( LPCSTR name, OFSTRUCT *ofs, UINT16 mode )
963 return FILE_DoOpenFile( name, ofs, mode, FALSE );
967 /***********************************************************************
968 * OpenFile32 (KERNEL32.396)
970 HFILE WINAPI OpenFile( LPCSTR name, OFSTRUCT *ofs, UINT mode )
972 return FILE_DoOpenFile( name, ofs, mode, TRUE );
976 /***********************************************************************
977 * FILE_InitProcessDosHandles
979 * Allocates the default DOS handles for a process. Called either by
980 * AllocDosHandle below or by the DOSVM stuff.
982 BOOL FILE_InitProcessDosHandles( void ) {
983 HANDLE *ptr;
985 if (!(ptr = HeapAlloc( SystemHeap, HEAP_ZERO_MEMORY,
986 sizeof(*ptr) * DOS_TABLE_SIZE )))
987 return FALSE;
988 PROCESS_Current()->dos_handles = ptr;
989 ptr[0] = GetStdHandle(STD_INPUT_HANDLE);
990 ptr[1] = GetStdHandle(STD_OUTPUT_HANDLE);
991 ptr[2] = GetStdHandle(STD_ERROR_HANDLE);
992 ptr[3] = GetStdHandle(STD_ERROR_HANDLE);
993 ptr[4] = GetStdHandle(STD_ERROR_HANDLE);
994 return TRUE;
997 /***********************************************************************
998 * FILE_AllocDosHandle
1000 * Allocate a DOS handle for a Win32 handle. The Win32 handle is no
1001 * longer valid after this function (even on failure).
1003 HFILE16 FILE_AllocDosHandle( HANDLE handle )
1005 int i;
1006 HANDLE *ptr = PROCESS_Current()->dos_handles;
1008 if (!handle || (handle == INVALID_HANDLE_VALUE))
1009 return INVALID_HANDLE_VALUE16;
1011 if (!ptr) {
1012 if (!FILE_InitProcessDosHandles())
1013 goto error;
1014 ptr = PROCESS_Current()->dos_handles;
1017 for (i = 0; i < DOS_TABLE_SIZE; i++, ptr++)
1018 if (!*ptr)
1020 *ptr = handle;
1021 TRACE("Got %d for h32 %d\n", i, handle );
1022 return i;
1024 error:
1025 CloseHandle( handle );
1026 SetLastError( ERROR_TOO_MANY_OPEN_FILES );
1027 return INVALID_HANDLE_VALUE16;
1031 /***********************************************************************
1032 * FILE_GetHandle32
1034 * Return the Win32 handle for a DOS handle.
1036 HANDLE FILE_GetHandle( HFILE16 hfile )
1038 HANDLE *table = PROCESS_Current()->dos_handles;
1039 if ((hfile >= DOS_TABLE_SIZE) || !table || !table[hfile])
1041 SetLastError( ERROR_INVALID_HANDLE );
1042 return INVALID_HANDLE_VALUE;
1044 return table[hfile];
1048 /***********************************************************************
1049 * FILE_Dup2
1051 * dup2() function for DOS handles.
1053 HFILE16 FILE_Dup2( HFILE16 hFile1, HFILE16 hFile2 )
1055 HANDLE *table = PROCESS_Current()->dos_handles;
1056 HANDLE new_handle;
1058 if ((hFile1 >= DOS_TABLE_SIZE) || (hFile2 >= DOS_TABLE_SIZE) ||
1059 !table || !table[hFile1])
1061 SetLastError( ERROR_INVALID_HANDLE );
1062 return HFILE_ERROR16;
1064 if (hFile2 < 5)
1066 FIXME("stdio handle closed, need proper conversion\n" );
1067 SetLastError( ERROR_INVALID_HANDLE );
1068 return HFILE_ERROR16;
1070 if (!DuplicateHandle( GetCurrentProcess(), table[hFile1],
1071 GetCurrentProcess(), &new_handle,
1072 0, FALSE, DUPLICATE_SAME_ACCESS ))
1073 return HFILE_ERROR16;
1074 if (table[hFile2]) CloseHandle( table[hFile2] );
1075 table[hFile2] = new_handle;
1076 return hFile2;
1080 /***********************************************************************
1081 * _lclose16 (KERNEL.81)
1083 HFILE16 WINAPI _lclose16( HFILE16 hFile )
1085 HANDLE *table = PROCESS_Current()->dos_handles;
1087 if (hFile < 5)
1089 FIXME("stdio handle closed, need proper conversion\n" );
1090 SetLastError( ERROR_INVALID_HANDLE );
1091 return HFILE_ERROR16;
1093 if ((hFile >= DOS_TABLE_SIZE) || !table || !table[hFile])
1095 SetLastError( ERROR_INVALID_HANDLE );
1096 return HFILE_ERROR16;
1098 TRACE("%d (handle32=%d)\n", hFile, table[hFile] );
1099 CloseHandle( table[hFile] );
1100 table[hFile] = 0;
1101 return 0;
1105 /***********************************************************************
1106 * _lclose32 (KERNEL32.592)
1108 HFILE WINAPI _lclose( HFILE hFile )
1110 TRACE("handle %d\n", hFile );
1111 return CloseHandle( hFile ) ? 0 : HFILE_ERROR;
1114 /***********************************************************************
1115 * GetOverlappedResult (KERNEL32.360)
1117 BOOL WINAPI GetOverlappedResult(HANDLE hFile,LPOVERLAPPED lpOverlapped,
1118 LPDWORD lpNumberOfBytesTransferred,
1119 BOOL bWait)
1121 /* Since all i/o is currently synchronuos,
1122 * return true, assuming ReadFile/WriteFile
1123 * have completed the operation */
1124 FIXME("NO Asynch I/O, assuming Read/Write succeeded\n" );
1125 return TRUE;
1128 /***********************************************************************
1129 * ReadFile (KERNEL32.428)
1131 BOOL WINAPI ReadFile( HANDLE hFile, LPVOID buffer, DWORD bytesToRead,
1132 LPDWORD bytesRead, LPOVERLAPPED overlapped )
1134 struct get_read_fd_request *req = get_req_buffer();
1135 int unix_handle, result;
1137 TRACE("%d %p %ld\n", hFile, buffer, bytesToRead );
1139 if (bytesRead) *bytesRead = 0; /* Do this before anything else */
1140 if (!bytesToRead) return TRUE;
1142 if ( overlapped ) {
1143 SetLastError ( ERROR_INVALID_PARAMETER );
1144 return FALSE;
1147 req->handle = hFile;
1148 server_call_fd( REQ_GET_READ_FD, -1, &unix_handle );
1149 if (unix_handle == -1) return FALSE;
1150 while ((result = read( unix_handle, buffer, bytesToRead )) == -1)
1152 if ((errno == EAGAIN) || (errno == EINTR)) continue;
1153 if ((errno == EFAULT) && VIRTUAL_HandleFault( buffer )) continue;
1154 FILE_SetDosError();
1155 break;
1157 close( unix_handle );
1158 if (result == -1) return FALSE;
1159 if (bytesRead) *bytesRead = result;
1160 return TRUE;
1164 /***********************************************************************
1165 * WriteFile (KERNEL32.578)
1167 BOOL WINAPI WriteFile( HANDLE hFile, LPCVOID buffer, DWORD bytesToWrite,
1168 LPDWORD bytesWritten, LPOVERLAPPED overlapped )
1170 struct get_write_fd_request *req = get_req_buffer();
1171 int unix_handle, result;
1173 TRACE("%d %p %ld\n", hFile, buffer, bytesToWrite );
1175 if (bytesWritten) *bytesWritten = 0; /* Do this before anything else */
1176 if (!bytesToWrite) return TRUE;
1178 if ( overlapped ) {
1179 SetLastError ( ERROR_INVALID_PARAMETER );
1180 return FALSE;
1183 req->handle = hFile;
1184 server_call_fd( REQ_GET_WRITE_FD, -1, &unix_handle );
1185 if (unix_handle == -1) return FALSE;
1186 while ((result = write( unix_handle, buffer, bytesToWrite )) == -1)
1188 if ((errno == EAGAIN) || (errno == EINTR)) continue;
1189 if ((errno == EFAULT) && VIRTUAL_HandleFault( buffer )) continue;
1190 if (errno == ENOSPC)
1191 SetLastError( ERROR_DISK_FULL );
1192 else
1193 FILE_SetDosError();
1194 break;
1196 close( unix_handle );
1197 if (result == -1) return FALSE;
1198 if (bytesWritten) *bytesWritten = result;
1199 return TRUE;
1203 /***********************************************************************
1204 * WIN16_hread
1206 LONG WINAPI WIN16_hread( HFILE16 hFile, SEGPTR buffer, LONG count )
1208 LONG maxlen;
1210 TRACE("%d %08lx %ld\n",
1211 hFile, (DWORD)buffer, count );
1213 /* Some programs pass a count larger than the allocated buffer */
1214 maxlen = GetSelectorLimit16( SELECTOROF(buffer) ) - OFFSETOF(buffer) + 1;
1215 if (count > maxlen) count = maxlen;
1216 return _lread(FILE_GetHandle(hFile), PTR_SEG_TO_LIN(buffer), count );
1220 /***********************************************************************
1221 * WIN16_lread
1223 UINT16 WINAPI WIN16_lread( HFILE16 hFile, SEGPTR buffer, UINT16 count )
1225 return (UINT16)WIN16_hread( hFile, buffer, (LONG)count );
1229 /***********************************************************************
1230 * _lread32 (KERNEL32.596)
1232 UINT WINAPI _lread( HFILE handle, LPVOID buffer, UINT count )
1234 DWORD result;
1235 if (!ReadFile( handle, buffer, count, &result, NULL )) return -1;
1236 return result;
1240 /***********************************************************************
1241 * _lread16 (KERNEL.82)
1243 UINT16 WINAPI _lread16( HFILE16 hFile, LPVOID buffer, UINT16 count )
1245 return (UINT16)_lread(FILE_GetHandle(hFile), buffer, (LONG)count );
1249 /***********************************************************************
1250 * _lcreat16 (KERNEL.83)
1252 HFILE16 WINAPI _lcreat16( LPCSTR path, INT16 attr )
1254 return FILE_AllocDosHandle( _lcreat( path, attr ) );
1258 /***********************************************************************
1259 * _lcreat (KERNEL32.593)
1261 HFILE WINAPI _lcreat( LPCSTR path, INT attr )
1263 /* Mask off all flags not explicitly allowed by the doc */
1264 attr &= FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM;
1265 TRACE("%s %02x\n", path, attr );
1266 return CreateFileA( path, GENERIC_READ | GENERIC_WRITE,
1267 FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
1268 CREATE_ALWAYS, attr, -1 );
1272 /***********************************************************************
1273 * SetFilePointer (KERNEL32.492)
1275 DWORD WINAPI SetFilePointer( HANDLE hFile, LONG distance, LONG *highword,
1276 DWORD method )
1278 struct set_file_pointer_request *req = get_req_buffer();
1280 if (highword && *highword)
1282 FIXME("64-bit offsets not supported yet\n");
1283 SetLastError( ERROR_INVALID_PARAMETER );
1284 return 0xffffffff;
1286 TRACE("handle %d offset %ld origin %ld\n",
1287 hFile, distance, method );
1289 req->handle = hFile;
1290 req->low = distance;
1291 req->high = highword ? *highword : 0;
1292 /* FIXME: assumes 1:1 mapping between Windows and Unix seek constants */
1293 req->whence = method;
1294 SetLastError( 0 );
1295 if (server_call( REQ_SET_FILE_POINTER )) return 0xffffffff;
1296 if (highword) *highword = req->new_high;
1297 return req->new_low;
1301 /***********************************************************************
1302 * _llseek16 (KERNEL.84)
1304 * FIXME:
1305 * Seeking before the start of the file should be allowed for _llseek16,
1306 * but cause subsequent I/O operations to fail (cf. interrupt list)
1309 LONG WINAPI _llseek16( HFILE16 hFile, LONG lOffset, INT16 nOrigin )
1311 return SetFilePointer( FILE_GetHandle(hFile), lOffset, NULL, nOrigin );
1315 /***********************************************************************
1316 * _llseek32 (KERNEL32.594)
1318 LONG WINAPI _llseek( HFILE hFile, LONG lOffset, INT nOrigin )
1320 return SetFilePointer( hFile, lOffset, NULL, nOrigin );
1324 /***********************************************************************
1325 * _lopen16 (KERNEL.85)
1327 HFILE16 WINAPI _lopen16( LPCSTR path, INT16 mode )
1329 return FILE_AllocDosHandle( _lopen( path, mode ) );
1333 /***********************************************************************
1334 * _lopen32 (KERNEL32.595)
1336 HFILE WINAPI _lopen( LPCSTR path, INT mode )
1338 DWORD access, sharing;
1340 TRACE("('%s',%04x)\n", path, mode );
1341 FILE_ConvertOFMode( mode, &access, &sharing );
1342 return CreateFileA( path, access, sharing, NULL, OPEN_EXISTING, 0, -1 );
1346 /***********************************************************************
1347 * _lwrite16 (KERNEL.86)
1349 UINT16 WINAPI _lwrite16( HFILE16 hFile, LPCSTR buffer, UINT16 count )
1351 return (UINT16)_hwrite( FILE_GetHandle(hFile), buffer, (LONG)count );
1354 /***********************************************************************
1355 * _lwrite32 (KERNEL32.761)
1357 UINT WINAPI _lwrite( HFILE hFile, LPCSTR buffer, UINT count )
1359 return (UINT)_hwrite( hFile, buffer, (LONG)count );
1363 /***********************************************************************
1364 * _hread16 (KERNEL.349)
1366 LONG WINAPI _hread16( HFILE16 hFile, LPVOID buffer, LONG count)
1368 return _lread( FILE_GetHandle(hFile), buffer, count );
1372 /***********************************************************************
1373 * _hread32 (KERNEL32.590)
1375 LONG WINAPI _hread( HFILE hFile, LPVOID buffer, LONG count)
1377 return _lread( hFile, buffer, count );
1381 /***********************************************************************
1382 * _hwrite16 (KERNEL.350)
1384 LONG WINAPI _hwrite16( HFILE16 hFile, LPCSTR buffer, LONG count )
1386 return _hwrite( FILE_GetHandle(hFile), buffer, count );
1390 /***********************************************************************
1391 * _hwrite32 (KERNEL32.591)
1393 * experimentation yields that _lwrite:
1394 * o truncates the file at the current position with
1395 * a 0 len write
1396 * o returns 0 on a 0 length write
1397 * o works with console handles
1400 LONG WINAPI _hwrite( HFILE handle, LPCSTR buffer, LONG count )
1402 DWORD result;
1404 TRACE("%d %p %ld\n", handle, buffer, count );
1406 if (!count)
1408 /* Expand or truncate at current position */
1409 if (!SetEndOfFile( handle )) return HFILE_ERROR;
1410 return 0;
1412 if (!WriteFile( handle, buffer, count, &result, NULL ))
1413 return HFILE_ERROR;
1414 return result;
1418 /***********************************************************************
1419 * SetHandleCount16 (KERNEL.199)
1421 UINT16 WINAPI SetHandleCount16( UINT16 count )
1423 HGLOBAL16 hPDB = GetCurrentPDB16();
1424 PDB16 *pdb = (PDB16 *)GlobalLock16( hPDB );
1425 BYTE *files = PTR_SEG_TO_LIN( pdb->fileHandlesPtr );
1427 TRACE("(%d)\n", count );
1429 if (count < 20) count = 20; /* No point in going below 20 */
1430 else if (count > 254) count = 254;
1432 if (count == 20)
1434 if (pdb->nbFiles > 20)
1436 memcpy( pdb->fileHandles, files, 20 );
1437 GlobalFree16( pdb->hFileHandles );
1438 pdb->fileHandlesPtr = (SEGPTR)MAKELONG( 0x18,
1439 GlobalHandleToSel16( hPDB ) );
1440 pdb->hFileHandles = 0;
1441 pdb->nbFiles = 20;
1444 else /* More than 20, need a new file handles table */
1446 BYTE *newfiles;
1447 HGLOBAL16 newhandle = GlobalAlloc16( GMEM_MOVEABLE, count );
1448 if (!newhandle)
1450 SetLastError( ERROR_NOT_ENOUGH_MEMORY );
1451 return pdb->nbFiles;
1453 newfiles = (BYTE *)GlobalLock16( newhandle );
1455 if (count > pdb->nbFiles)
1457 memcpy( newfiles, files, pdb->nbFiles );
1458 memset( newfiles + pdb->nbFiles, 0xff, count - pdb->nbFiles );
1460 else memcpy( newfiles, files, count );
1461 if (pdb->nbFiles > 20) GlobalFree16( pdb->hFileHandles );
1462 pdb->fileHandlesPtr = WIN16_GlobalLock16( newhandle );
1463 pdb->hFileHandles = newhandle;
1464 pdb->nbFiles = count;
1466 return pdb->nbFiles;
1470 /*************************************************************************
1471 * SetHandleCount32 (KERNEL32.494)
1473 UINT WINAPI SetHandleCount( UINT count )
1475 return MIN( 256, count );
1479 /***********************************************************************
1480 * FlushFileBuffers (KERNEL32.133)
1482 BOOL WINAPI FlushFileBuffers( HANDLE hFile )
1484 struct flush_file_request *req = get_req_buffer();
1485 req->handle = hFile;
1486 return !server_call( REQ_FLUSH_FILE );
1490 /**************************************************************************
1491 * SetEndOfFile (KERNEL32.483)
1493 BOOL WINAPI SetEndOfFile( HANDLE hFile )
1495 struct truncate_file_request *req = get_req_buffer();
1496 req->handle = hFile;
1497 return !server_call( REQ_TRUNCATE_FILE );
1501 /***********************************************************************
1502 * DeleteFile16 (KERNEL.146)
1504 BOOL16 WINAPI DeleteFile16( LPCSTR path )
1506 return DeleteFileA( path );
1510 /***********************************************************************
1511 * DeleteFile32A (KERNEL32.71)
1513 BOOL WINAPI DeleteFileA( LPCSTR path )
1515 DOS_FULL_NAME full_name;
1517 TRACE("'%s'\n", path );
1519 if (!*path)
1521 ERR("Empty path passed\n");
1522 return FALSE;
1524 if (DOSFS_GetDevice( path ))
1526 WARN("cannot remove DOS device '%s'!\n", path);
1527 SetLastError( ERROR_FILE_NOT_FOUND );
1528 return FALSE;
1531 if (!DOSFS_GetFullName( path, TRUE, &full_name )) return FALSE;
1532 if (unlink( full_name.long_name ) == -1)
1534 FILE_SetDosError();
1535 return FALSE;
1537 return TRUE;
1541 /***********************************************************************
1542 * DeleteFile32W (KERNEL32.72)
1544 BOOL WINAPI DeleteFileW( LPCWSTR path )
1546 LPSTR xpath = HEAP_strdupWtoA( GetProcessHeap(), 0, path );
1547 BOOL ret = DeleteFileA( xpath );
1548 HeapFree( GetProcessHeap(), 0, xpath );
1549 return ret;
1553 /***********************************************************************
1554 * FILE_dommap
1556 LPVOID FILE_dommap( int unix_handle, LPVOID start,
1557 DWORD size_high, DWORD size_low,
1558 DWORD offset_high, DWORD offset_low,
1559 int prot, int flags )
1561 int fd = -1;
1562 int pos;
1563 LPVOID ret;
1565 if (size_high || offset_high)
1566 FIXME("offsets larger than 4Gb not supported\n");
1568 if (unix_handle == -1)
1570 #ifdef MAP_ANON
1571 flags |= MAP_ANON;
1572 #else
1573 static int fdzero = -1;
1575 if (fdzero == -1)
1577 if ((fdzero = open( "/dev/zero", O_RDONLY )) == -1)
1579 perror( "/dev/zero: open" );
1580 exit(1);
1583 fd = fdzero;
1584 #endif /* MAP_ANON */
1585 /* Linux EINVAL's on us if we don't pass MAP_PRIVATE to an anon mmap */
1586 #ifdef MAP_SHARED
1587 flags &= ~MAP_SHARED;
1588 #endif
1589 #ifdef MAP_PRIVATE
1590 flags |= MAP_PRIVATE;
1591 #endif
1593 else fd = unix_handle;
1595 if ((ret = mmap( start, size_low, prot,
1596 flags, fd, offset_low )) != (LPVOID)-1)
1597 return ret;
1599 /* mmap() failed; if this is because the file offset is not */
1600 /* page-aligned (EINVAL), or because the underlying filesystem */
1601 /* does not support mmap() (ENOEXEC), we do it by hand. */
1603 if (unix_handle == -1) return ret;
1604 if ((errno != ENOEXEC) && (errno != EINVAL)) return ret;
1605 if (prot & PROT_WRITE)
1607 /* We cannot fake shared write mappings */
1608 #ifdef MAP_SHARED
1609 if (flags & MAP_SHARED) return ret;
1610 #endif
1611 #ifdef MAP_PRIVATE
1612 if (!(flags & MAP_PRIVATE)) return ret;
1613 #endif
1615 /* printf( "FILE_mmap: mmap failed (%d), faking it\n", errno );*/
1616 /* Reserve the memory with an anonymous mmap */
1617 ret = FILE_dommap( -1, start, size_high, size_low, 0, 0,
1618 PROT_READ | PROT_WRITE, flags );
1619 if (ret == (LPVOID)-1) return ret;
1620 /* Now read in the file */
1621 if ((pos = lseek( fd, offset_low, SEEK_SET )) == -1)
1623 FILE_munmap( ret, size_high, size_low );
1624 return (LPVOID)-1;
1626 read( fd, ret, size_low );
1627 lseek( fd, pos, SEEK_SET ); /* Restore the file pointer */
1628 mprotect( ret, size_low, prot ); /* Set the right protection */
1629 return ret;
1633 /***********************************************************************
1634 * FILE_munmap
1636 int FILE_munmap( LPVOID start, DWORD size_high, DWORD size_low )
1638 if (size_high)
1639 FIXME("offsets larger than 4Gb not supported\n");
1640 return munmap( start, size_low );
1644 /***********************************************************************
1645 * GetFileType (KERNEL32.222)
1647 DWORD WINAPI GetFileType( HANDLE hFile )
1649 struct get_file_info_request *req = get_req_buffer();
1650 req->handle = hFile;
1651 if (server_call( REQ_GET_FILE_INFO )) return FILE_TYPE_UNKNOWN;
1652 return req->type;
1656 /**************************************************************************
1657 * MoveFileExA (KERNEL32.???)
1659 BOOL WINAPI MoveFileExA( LPCSTR fn1, LPCSTR fn2, DWORD flag )
1661 DOS_FULL_NAME full_name1, full_name2;
1663 TRACE("(%s,%s,%04lx)\n", fn1, fn2, flag);
1665 if (!DOSFS_GetFullName( fn1, TRUE, &full_name1 )) return FALSE;
1667 if (fn2) /* !fn2 means delete fn1 */
1669 if (DOSFS_GetFullName( fn2, TRUE, &full_name2 ))
1671 /* target exists, check if we may overwrite */
1672 if (!(flag & MOVEFILE_REPLACE_EXISTING))
1674 /* FIXME: Use right error code */
1675 SetLastError( ERROR_ACCESS_DENIED );
1676 return FALSE;
1679 else if (!DOSFS_GetFullName( fn2, FALSE, &full_name2 )) return FALSE;
1681 /* Source name and target path are valid */
1683 if (flag & MOVEFILE_DELAY_UNTIL_REBOOT)
1685 /* FIXME: (bon@elektron.ikp.physik.th-darmstadt.de 970706)
1686 Perhaps we should queue these command and execute it
1687 when exiting... What about using on_exit(2)
1689 FIXME("Please move existing file '%s' to file '%s' when Wine has finished\n",
1690 full_name1.long_name, full_name2.long_name);
1691 return TRUE;
1694 if (full_name1.drive != full_name2.drive)
1696 /* use copy, if allowed */
1697 if (!(flag & MOVEFILE_COPY_ALLOWED))
1699 /* FIXME: Use right error code */
1700 SetLastError( ERROR_FILE_EXISTS );
1701 return FALSE;
1703 return CopyFileA( fn1, fn2, !(flag & MOVEFILE_REPLACE_EXISTING) );
1705 if (rename( full_name1.long_name, full_name2.long_name ) == -1)
1707 FILE_SetDosError();
1708 return FALSE;
1710 return TRUE;
1712 else /* fn2 == NULL means delete source */
1714 if (flag & MOVEFILE_DELAY_UNTIL_REBOOT)
1716 if (flag & MOVEFILE_COPY_ALLOWED) {
1717 WARN("Illegal flag\n");
1718 SetLastError( ERROR_GEN_FAILURE );
1719 return FALSE;
1721 /* FIXME: (bon@elektron.ikp.physik.th-darmstadt.de 970706)
1722 Perhaps we should queue these command and execute it
1723 when exiting... What about using on_exit(2)
1725 FIXME("Please delete file '%s' when Wine has finished\n",
1726 full_name1.long_name);
1727 return TRUE;
1730 if (unlink( full_name1.long_name ) == -1)
1732 FILE_SetDosError();
1733 return FALSE;
1735 return TRUE; /* successfully deleted */
1739 /**************************************************************************
1740 * MoveFileEx32W (KERNEL32.???)
1742 BOOL WINAPI MoveFileExW( LPCWSTR fn1, LPCWSTR fn2, DWORD flag )
1744 LPSTR afn1 = HEAP_strdupWtoA( GetProcessHeap(), 0, fn1 );
1745 LPSTR afn2 = HEAP_strdupWtoA( GetProcessHeap(), 0, fn2 );
1746 BOOL res = MoveFileExA( afn1, afn2, flag );
1747 HeapFree( GetProcessHeap(), 0, afn1 );
1748 HeapFree( GetProcessHeap(), 0, afn2 );
1749 return res;
1753 /**************************************************************************
1754 * MoveFile32A (KERNEL32.387)
1756 * Move file or directory
1758 BOOL WINAPI MoveFileA( LPCSTR fn1, LPCSTR fn2 )
1760 DOS_FULL_NAME full_name1, full_name2;
1761 struct stat fstat;
1763 TRACE("(%s,%s)\n", fn1, fn2 );
1765 if (!DOSFS_GetFullName( fn1, TRUE, &full_name1 )) return FALSE;
1766 if (DOSFS_GetFullName( fn2, TRUE, &full_name2 ))
1767 /* The new name must not already exist */
1768 return FALSE;
1769 if (!DOSFS_GetFullName( fn2, FALSE, &full_name2 )) return FALSE;
1771 if (full_name1.drive == full_name2.drive) /* move */
1772 if (rename( full_name1.long_name, full_name2.long_name ) == -1)
1774 FILE_SetDosError();
1775 return FALSE;
1777 else return TRUE;
1778 else /*copy */ {
1779 if (stat( full_name1.long_name, &fstat ))
1781 WARN("Invalid source file %s\n",
1782 full_name1.long_name);
1783 FILE_SetDosError();
1784 return FALSE;
1786 if (S_ISDIR(fstat.st_mode)) {
1787 /* No Move for directories across file systems */
1788 /* FIXME: Use right error code */
1789 SetLastError( ERROR_GEN_FAILURE );
1790 return FALSE;
1792 else
1793 return CopyFileA(fn1, fn2, TRUE); /*fail, if exist */
1798 /**************************************************************************
1799 * MoveFile32W (KERNEL32.390)
1801 BOOL WINAPI MoveFileW( LPCWSTR fn1, LPCWSTR fn2 )
1803 LPSTR afn1 = HEAP_strdupWtoA( GetProcessHeap(), 0, fn1 );
1804 LPSTR afn2 = HEAP_strdupWtoA( GetProcessHeap(), 0, fn2 );
1805 BOOL res = MoveFileA( afn1, afn2 );
1806 HeapFree( GetProcessHeap(), 0, afn1 );
1807 HeapFree( GetProcessHeap(), 0, afn2 );
1808 return res;
1812 /**************************************************************************
1813 * CopyFile32A (KERNEL32.36)
1815 BOOL WINAPI CopyFileA( LPCSTR source, LPCSTR dest, BOOL fail_if_exists )
1817 HFILE h1, h2;
1818 BY_HANDLE_FILE_INFORMATION info;
1819 UINT count;
1820 BOOL ret = FALSE;
1821 int mode;
1822 char buffer[2048];
1824 if ((h1 = _lopen( source, OF_READ )) == HFILE_ERROR) return FALSE;
1825 if (!GetFileInformationByHandle( h1, &info ))
1827 CloseHandle( h1 );
1828 return FALSE;
1830 mode = (info.dwFileAttributes & FILE_ATTRIBUTE_READONLY) ? 0444 : 0666;
1831 if ((h2 = CreateFileA( dest, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
1832 fail_if_exists ? CREATE_NEW : CREATE_ALWAYS,
1833 info.dwFileAttributes, h1 )) == HFILE_ERROR)
1835 CloseHandle( h1 );
1836 return FALSE;
1838 while ((count = _lread( h1, buffer, sizeof(buffer) )) > 0)
1840 char *p = buffer;
1841 while (count > 0)
1843 INT res = _lwrite( h2, p, count );
1844 if (res <= 0) goto done;
1845 p += res;
1846 count -= res;
1849 ret = TRUE;
1850 done:
1851 CloseHandle( h1 );
1852 CloseHandle( h2 );
1853 return ret;
1857 /**************************************************************************
1858 * CopyFile32W (KERNEL32.37)
1860 BOOL WINAPI CopyFileW( LPCWSTR source, LPCWSTR dest, BOOL fail_if_exists)
1862 LPSTR sourceA = HEAP_strdupWtoA( GetProcessHeap(), 0, source );
1863 LPSTR destA = HEAP_strdupWtoA( GetProcessHeap(), 0, dest );
1864 BOOL ret = CopyFileA( sourceA, destA, fail_if_exists );
1865 HeapFree( GetProcessHeap(), 0, sourceA );
1866 HeapFree( GetProcessHeap(), 0, destA );
1867 return ret;
1871 /**************************************************************************
1872 * CopyFileEx32A (KERNEL32.858)
1874 * This implementation ignores most of the extra parameters passed-in into
1875 * the "ex" version of the method and calls the CopyFile method.
1876 * It will have to be fixed eventually.
1878 BOOL WINAPI CopyFileExA(LPCSTR sourceFilename,
1879 LPCSTR destFilename,
1880 LPPROGRESS_ROUTINE progressRoutine,
1881 LPVOID appData,
1882 LPBOOL cancelFlagPointer,
1883 DWORD copyFlags)
1885 BOOL failIfExists = FALSE;
1888 * Interpret the only flag that CopyFile can interpret.
1890 if ( (copyFlags & COPY_FILE_FAIL_IF_EXISTS) != 0)
1892 failIfExists = TRUE;
1895 return CopyFileA(sourceFilename, destFilename, failIfExists);
1898 /**************************************************************************
1899 * CopyFileEx32W (KERNEL32.859)
1901 BOOL WINAPI CopyFileExW(LPCWSTR sourceFilename,
1902 LPCWSTR destFilename,
1903 LPPROGRESS_ROUTINE progressRoutine,
1904 LPVOID appData,
1905 LPBOOL cancelFlagPointer,
1906 DWORD copyFlags)
1908 LPSTR sourceA = HEAP_strdupWtoA( GetProcessHeap(), 0, sourceFilename );
1909 LPSTR destA = HEAP_strdupWtoA( GetProcessHeap(), 0, destFilename );
1911 BOOL ret = CopyFileExA(sourceA,
1912 destA,
1913 progressRoutine,
1914 appData,
1915 cancelFlagPointer,
1916 copyFlags);
1918 HeapFree( GetProcessHeap(), 0, sourceA );
1919 HeapFree( GetProcessHeap(), 0, destA );
1921 return ret;
1925 /***********************************************************************
1926 * SetFileTime (KERNEL32.650)
1928 BOOL WINAPI SetFileTime( HANDLE hFile,
1929 const FILETIME *lpCreationTime,
1930 const FILETIME *lpLastAccessTime,
1931 const FILETIME *lpLastWriteTime )
1933 struct set_file_time_request *req = get_req_buffer();
1935 req->handle = hFile;
1936 if (lpLastAccessTime)
1937 req->access_time = DOSFS_FileTimeToUnixTime(lpLastAccessTime, NULL);
1938 else
1939 req->access_time = 0; /* FIXME */
1940 if (lpLastWriteTime)
1941 req->write_time = DOSFS_FileTimeToUnixTime(lpLastWriteTime, NULL);
1942 else
1943 req->write_time = 0; /* FIXME */
1944 return !server_call( REQ_SET_FILE_TIME );
1948 /**************************************************************************
1949 * LockFile (KERNEL32.511)
1951 BOOL WINAPI LockFile( HANDLE hFile, DWORD dwFileOffsetLow, DWORD dwFileOffsetHigh,
1952 DWORD nNumberOfBytesToLockLow, DWORD nNumberOfBytesToLockHigh )
1954 struct lock_file_request *req = get_req_buffer();
1956 req->handle = hFile;
1957 req->offset_low = dwFileOffsetLow;
1958 req->offset_high = dwFileOffsetHigh;
1959 req->count_low = nNumberOfBytesToLockLow;
1960 req->count_high = nNumberOfBytesToLockHigh;
1961 return !server_call( REQ_LOCK_FILE );
1964 /**************************************************************************
1965 * LockFileEx [KERNEL32.512]
1967 * Locks a byte range within an open file for shared or exclusive access.
1969 * RETURNS
1970 * success: TRUE
1971 * failure: FALSE
1972 * NOTES
1974 * Per Microsoft docs, the third parameter (reserved) must be set to 0.
1976 BOOL WINAPI LockFileEx( HANDLE hFile, DWORD flags, DWORD reserved,
1977 DWORD nNumberOfBytesToLockLow, DWORD nNumberOfBytesToLockHigh,
1978 LPOVERLAPPED pOverlapped )
1980 FIXME("hFile=%d,flags=%ld,reserved=%ld,lowbytes=%ld,highbytes=%ld,overlapped=%p: stub.\n",
1981 hFile, flags, reserved, nNumberOfBytesToLockLow, nNumberOfBytesToLockHigh,
1982 pOverlapped);
1983 if (reserved == 0)
1984 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1985 else
1987 ERR("reserved == %ld: Supposed to be 0??\n", reserved);
1988 SetLastError(ERROR_INVALID_PARAMETER);
1991 return FALSE;
1995 /**************************************************************************
1996 * UnlockFile (KERNEL32.703)
1998 BOOL WINAPI UnlockFile( HANDLE hFile, DWORD dwFileOffsetLow, DWORD dwFileOffsetHigh,
1999 DWORD nNumberOfBytesToUnlockLow, DWORD nNumberOfBytesToUnlockHigh )
2001 struct unlock_file_request *req = get_req_buffer();
2003 req->handle = hFile;
2004 req->offset_low = dwFileOffsetLow;
2005 req->offset_high = dwFileOffsetHigh;
2006 req->count_low = nNumberOfBytesToUnlockLow;
2007 req->count_high = nNumberOfBytesToUnlockHigh;
2008 return !server_call( REQ_UNLOCK_FILE );
2012 /**************************************************************************
2013 * UnlockFileEx (KERNEL32.705)
2015 BOOL WINAPI UnlockFileEx(
2016 HFILE hFile,
2017 DWORD dwReserved,
2018 DWORD nNumberOfBytesToUnlockLow,
2019 DWORD nNumberOfBytesToUnlockHigh,
2020 LPOVERLAPPED lpOverlapped
2023 FIXME("hFile=%d,reserved=%ld,lowbytes=%ld,highbytes=%ld,overlapped=%p: stub.\n",
2024 hFile, dwReserved, nNumberOfBytesToUnlockLow, nNumberOfBytesToUnlockHigh,
2025 lpOverlapped);
2026 if (dwReserved == 0)
2027 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
2028 else
2030 ERR("reserved == %ld: Supposed to be 0??\n", dwReserved);
2031 SetLastError(ERROR_INVALID_PARAMETER);
2034 return FALSE;
2038 #if 0
2040 struct DOS_FILE_LOCK {
2041 struct DOS_FILE_LOCK * next;
2042 DWORD base;
2043 DWORD len;
2044 DWORD processId;
2045 FILE_OBJECT * dos_file;
2046 /* char * unix_name;*/
2049 typedef struct DOS_FILE_LOCK DOS_FILE_LOCK;
2051 static DOS_FILE_LOCK *locks = NULL;
2052 static void DOS_RemoveFileLocks(FILE_OBJECT *file);
2055 /* Locks need to be mirrored because unix file locking is based
2056 * on the pid. Inside of wine there can be multiple WINE processes
2057 * that share the same unix pid.
2058 * Read's and writes should check these locks also - not sure
2059 * how critical that is at this point (FIXME).
2062 static BOOL DOS_AddLock(FILE_OBJECT *file, struct flock *f)
2064 DOS_FILE_LOCK *curr;
2065 DWORD processId;
2067 processId = GetCurrentProcessId();
2069 /* check if lock overlaps a current lock for the same file */
2070 #if 0
2071 for (curr = locks; curr; curr = curr->next) {
2072 if (strcmp(curr->unix_name, file->unix_name) == 0) {
2073 if ((f->l_start == curr->base) && (f->l_len == curr->len))
2074 return TRUE;/* region is identic */
2075 if ((f->l_start < (curr->base + curr->len)) &&
2076 ((f->l_start + f->l_len) > curr->base)) {
2077 /* region overlaps */
2078 return FALSE;
2082 #endif
2084 curr = HeapAlloc( SystemHeap, 0, sizeof(DOS_FILE_LOCK) );
2085 curr->processId = GetCurrentProcessId();
2086 curr->base = f->l_start;
2087 curr->len = f->l_len;
2088 /* curr->unix_name = HEAP_strdupA( SystemHeap, 0, file->unix_name);*/
2089 curr->next = locks;
2090 curr->dos_file = file;
2091 locks = curr;
2092 return TRUE;
2095 static void DOS_RemoveFileLocks(FILE_OBJECT *file)
2097 DWORD processId;
2098 DOS_FILE_LOCK **curr;
2099 DOS_FILE_LOCK *rem;
2101 processId = GetCurrentProcessId();
2102 curr = &locks;
2103 while (*curr) {
2104 if ((*curr)->dos_file == file) {
2105 rem = *curr;
2106 *curr = (*curr)->next;
2107 /* HeapFree( SystemHeap, 0, rem->unix_name );*/
2108 HeapFree( SystemHeap, 0, rem );
2110 else
2111 curr = &(*curr)->next;
2115 static BOOL DOS_RemoveLock(FILE_OBJECT *file, struct flock *f)
2117 DWORD processId;
2118 DOS_FILE_LOCK **curr;
2119 DOS_FILE_LOCK *rem;
2121 processId = GetCurrentProcessId();
2122 for (curr = &locks; *curr; curr = &(*curr)->next) {
2123 if ((*curr)->processId == processId &&
2124 (*curr)->dos_file == file &&
2125 (*curr)->base == f->l_start &&
2126 (*curr)->len == f->l_len) {
2127 /* this is the same lock */
2128 rem = *curr;
2129 *curr = (*curr)->next;
2130 /* HeapFree( SystemHeap, 0, rem->unix_name );*/
2131 HeapFree( SystemHeap, 0, rem );
2132 return TRUE;
2135 /* no matching lock found */
2136 return FALSE;
2140 /**************************************************************************
2141 * LockFile (KERNEL32.511)
2143 BOOL WINAPI LockFile(
2144 HFILE hFile,DWORD dwFileOffsetLow,DWORD dwFileOffsetHigh,
2145 DWORD nNumberOfBytesToLockLow,DWORD nNumberOfBytesToLockHigh )
2147 struct flock f;
2148 FILE_OBJECT *file;
2150 TRACE("handle %d offsetlow=%ld offsethigh=%ld nbyteslow=%ld nbyteshigh=%ld\n",
2151 hFile, dwFileOffsetLow, dwFileOffsetHigh,
2152 nNumberOfBytesToLockLow, nNumberOfBytesToLockHigh);
2154 if (dwFileOffsetHigh || nNumberOfBytesToLockHigh) {
2155 FIXME("Unimplemented bytes > 32bits\n");
2156 return FALSE;
2159 f.l_start = dwFileOffsetLow;
2160 f.l_len = nNumberOfBytesToLockLow;
2161 f.l_whence = SEEK_SET;
2162 f.l_pid = 0;
2163 f.l_type = F_WRLCK;
2165 if (!(file = FILE_GetFile(hFile,0,NULL))) return FALSE;
2167 /* shadow locks internally */
2168 if (!DOS_AddLock(file, &f)) {
2169 SetLastError( ERROR_LOCK_VIOLATION );
2170 return FALSE;
2173 /* FIXME: Unix locking commented out for now, doesn't work with Excel */
2174 #ifdef USE_UNIX_LOCKS
2175 if (fcntl(file->unix_handle, F_SETLK, &f) == -1) {
2176 if (errno == EACCES || errno == EAGAIN) {
2177 SetLastError( ERROR_LOCK_VIOLATION );
2179 else {
2180 FILE_SetDosError();
2182 /* remove our internal copy of the lock */
2183 DOS_RemoveLock(file, &f);
2184 return FALSE;
2186 #endif
2187 return TRUE;
2191 /**************************************************************************
2192 * UnlockFile (KERNEL32.703)
2194 BOOL WINAPI UnlockFile(
2195 HFILE hFile,DWORD dwFileOffsetLow,DWORD dwFileOffsetHigh,
2196 DWORD nNumberOfBytesToUnlockLow,DWORD nNumberOfBytesToUnlockHigh )
2198 FILE_OBJECT *file;
2199 struct flock f;
2201 TRACE("handle %d offsetlow=%ld offsethigh=%ld nbyteslow=%ld nbyteshigh=%ld\n",
2202 hFile, dwFileOffsetLow, dwFileOffsetHigh,
2203 nNumberOfBytesToUnlockLow, nNumberOfBytesToUnlockHigh);
2205 if (dwFileOffsetHigh || nNumberOfBytesToUnlockHigh) {
2206 WARN("Unimplemented bytes > 32bits\n");
2207 return FALSE;
2210 f.l_start = dwFileOffsetLow;
2211 f.l_len = nNumberOfBytesToUnlockLow;
2212 f.l_whence = SEEK_SET;
2213 f.l_pid = 0;
2214 f.l_type = F_UNLCK;
2216 if (!(file = FILE_GetFile(hFile,0,NULL))) return FALSE;
2218 DOS_RemoveLock(file, &f); /* ok if fails - may be another wine */
2220 /* FIXME: Unix locking commented out for now, doesn't work with Excel */
2221 #ifdef USE_UNIX_LOCKS
2222 if (fcntl(file->unix_handle, F_SETLK, &f) == -1) {
2223 FILE_SetDosError();
2224 return FALSE;
2226 #endif
2227 return TRUE;
2229 #endif
2231 /**************************************************************************
2232 * GetFileAttributesEx32A [KERNEL32.874]
2234 BOOL WINAPI GetFileAttributesExA(
2235 LPCSTR lpFileName, GET_FILEEX_INFO_LEVELS fInfoLevelId,
2236 LPVOID lpFileInformation)
2238 DOS_FULL_NAME full_name;
2239 BY_HANDLE_FILE_INFORMATION info;
2241 if (lpFileName == NULL) return FALSE;
2242 if (lpFileInformation == NULL) return FALSE;
2244 if (fInfoLevelId == GetFileExInfoStandard) {
2245 LPWIN32_FILE_ATTRIBUTE_DATA lpFad =
2246 (LPWIN32_FILE_ATTRIBUTE_DATA) lpFileInformation;
2247 if (!DOSFS_GetFullName( lpFileName, TRUE, &full_name )) return FALSE;
2248 if (!FILE_Stat( full_name.long_name, &info )) return FALSE;
2250 lpFad->dwFileAttributes = info.dwFileAttributes;
2251 lpFad->ftCreationTime = info.ftCreationTime;
2252 lpFad->ftLastAccessTime = info.ftLastAccessTime;
2253 lpFad->ftLastWriteTime = info.ftLastWriteTime;
2254 lpFad->nFileSizeHigh = info.nFileSizeHigh;
2255 lpFad->nFileSizeLow = info.nFileSizeLow;
2257 else {
2258 FIXME("invalid info level %d!\n", fInfoLevelId);
2259 return FALSE;
2262 return TRUE;
2266 /**************************************************************************
2267 * GetFileAttributesEx32W [KERNEL32.875]
2269 BOOL WINAPI GetFileAttributesExW(
2270 LPCWSTR lpFileName, GET_FILEEX_INFO_LEVELS fInfoLevelId,
2271 LPVOID lpFileInformation)
2273 LPSTR nameA = HEAP_strdupWtoA( GetProcessHeap(), 0, lpFileName );
2274 BOOL res =
2275 GetFileAttributesExA( nameA, fInfoLevelId, lpFileInformation);
2276 HeapFree( GetProcessHeap(), 0, nameA );
2277 return res;