Remove old link before creating the new one.
[wine.git] / files / file.c
blob5259bc8170b86bad080d1977186c91a02bf29b0b
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 "extended" 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 <stdio.h>
20 #include <string.h>
21 #ifdef HAVE_SYS_ERRNO_H
22 #include <sys/errno.h>
23 #endif
24 #include <sys/types.h>
25 #include <sys/stat.h>
26 #ifdef HAVE_SYS_MMAN_H
27 #include <sys/mman.h>
28 #endif
29 #include <sys/time.h>
30 #include <time.h>
31 #include <unistd.h>
32 #include <utime.h>
34 #include "winerror.h"
35 #include "windef.h"
36 #include "winbase.h"
37 #include "wine/winbase16.h"
38 #include "wine/port.h"
39 #include "drive.h"
40 #include "file.h"
41 #include "global.h"
42 #include "heap.h"
43 #include "msdos.h"
44 #include "ldt.h"
45 #include "task.h"
46 #include "wincon.h"
47 #include "debugtools.h"
49 #include "server.h"
51 DEFAULT_DEBUG_CHANNEL(file);
53 #if defined(MAP_ANONYMOUS) && !defined(MAP_ANON)
54 #define MAP_ANON MAP_ANONYMOUS
55 #endif
57 /* Size of per-process table of DOS handles */
58 #define DOS_TABLE_SIZE 256
60 static HANDLE dos_handles[DOS_TABLE_SIZE];
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 /***********************************************************************
90 * FILE_strcasecmp
92 * locale-independent case conversion for file I/O
94 int FILE_strcasecmp( const char *str1, const char *str2 )
96 for (;;)
98 int ret = FILE_toupper(*str1) - FILE_toupper(*str2);
99 if (ret || !*str1) return ret;
100 str1++;
101 str2++;
106 /***********************************************************************
107 * FILE_strncasecmp
109 * locale-independent case conversion for file I/O
111 int FILE_strncasecmp( const char *str1, const char *str2, int len )
113 int ret = 0;
114 for ( ; len > 0; len--, str1++, str2++)
115 if ((ret = FILE_toupper(*str1) - FILE_toupper(*str2)) || !*str1) break;
116 return ret;
120 /***********************************************************************
121 * FILE_SetDosError
123 * Set the DOS error code from errno.
125 void FILE_SetDosError(void)
127 int save_errno = errno; /* errno gets overwritten by printf */
129 TRACE("errno = %d %s\n", errno, strerror(errno));
130 switch (save_errno)
132 case EAGAIN:
133 SetLastError( ERROR_SHARING_VIOLATION );
134 break;
135 case EBADF:
136 SetLastError( ERROR_INVALID_HANDLE );
137 break;
138 case ENOSPC:
139 SetLastError( ERROR_HANDLE_DISK_FULL );
140 break;
141 case EACCES:
142 case EPERM:
143 case EROFS:
144 SetLastError( ERROR_ACCESS_DENIED );
145 break;
146 case EBUSY:
147 SetLastError( ERROR_LOCK_VIOLATION );
148 break;
149 case ENOENT:
150 SetLastError( ERROR_FILE_NOT_FOUND );
151 break;
152 case EISDIR:
153 SetLastError( ERROR_CANNOT_MAKE );
154 break;
155 case ENFILE:
156 case EMFILE:
157 SetLastError( ERROR_NO_MORE_FILES );
158 break;
159 case EEXIST:
160 SetLastError( ERROR_FILE_EXISTS );
161 break;
162 case EINVAL:
163 case ESPIPE:
164 SetLastError( ERROR_SEEK );
165 break;
166 case ENOTEMPTY:
167 SetLastError( ERROR_DIR_NOT_EMPTY );
168 break;
169 case ENOEXEC:
170 SetLastError( ERROR_BAD_FORMAT );
171 break;
172 default:
173 WARN( "unknown file error: %s", strerror(save_errno) );
174 SetLastError( ERROR_GEN_FAILURE );
175 break;
177 errno = save_errno;
181 /***********************************************************************
182 * FILE_DupUnixHandle
184 * Duplicate a Unix handle into a task handle.
186 HFILE FILE_DupUnixHandle( int fd, DWORD access )
188 struct alloc_file_handle_request *req = get_req_buffer();
189 req->access = access;
190 server_call_fd( REQ_ALLOC_FILE_HANDLE, fd, NULL );
191 return req->handle;
195 /***********************************************************************
196 * FILE_GetUnixHandle
198 * Retrieve the Unix handle corresponding to a file handle.
200 int FILE_GetUnixHandle( HANDLE handle, DWORD access )
202 int unix_handle = -1;
203 if (access == GENERIC_READ)
205 struct get_read_fd_request *req = get_req_buffer();
206 req->handle = handle;
207 server_call_fd( REQ_GET_READ_FD, -1, &unix_handle );
209 else if (access == GENERIC_WRITE)
211 struct get_write_fd_request *req = get_req_buffer();
212 req->handle = handle;
213 server_call_fd( REQ_GET_WRITE_FD, -1, &unix_handle );
215 else ERR( "bad access %08lx\n", access );
216 return unix_handle;
220 /*************************************************************************
221 * FILE_OpenConsole
223 * Open a handle to the current process console.
225 static HANDLE FILE_OpenConsole( BOOL output, DWORD access, LPSECURITY_ATTRIBUTES sa )
227 int ret = -1;
229 SERVER_START_REQ
231 struct open_console_request *req = server_alloc_req( sizeof(*req), 0 );
233 req->output = output;
234 req->access = access;
235 req->inherit = (sa && (sa->nLength>=sizeof(*sa)) && sa->bInheritHandle);
236 SetLastError(0);
237 if (!server_call( REQ_OPEN_CONSOLE )) ret = req->handle;
239 SERVER_END_REQ;
240 return ret;
244 /***********************************************************************
245 * FILE_CreateFile
247 * Implementation of CreateFile. Takes a Unix path name.
249 HANDLE FILE_CreateFile( LPCSTR filename, DWORD access, DWORD sharing,
250 LPSECURITY_ATTRIBUTES sa, DWORD creation,
251 DWORD attributes, HANDLE template, BOOL fail_read_only )
253 DWORD err;
254 HANDLE ret;
255 size_t len = strlen(filename);
257 if (len > REQUEST_MAX_VAR_SIZE)
259 FIXME("filename '%s' too long\n", filename );
260 SetLastError( ERROR_INVALID_PARAMETER );
261 return -1;
264 restart:
265 SERVER_START_REQ
267 struct create_file_request *req = server_alloc_req( sizeof(*req), len );
268 req->access = access;
269 req->inherit = (sa && (sa->nLength>=sizeof(*sa)) && sa->bInheritHandle);
270 req->sharing = sharing;
271 req->create = creation;
272 req->attrs = attributes;
273 memcpy( server_data_ptr(req), filename, len );
274 SetLastError(0);
275 err = server_call( REQ_CREATE_FILE );
276 ret = req->handle;
278 SERVER_END_REQ;
280 /* If write access failed, retry without GENERIC_WRITE */
282 if ((ret == -1) && !fail_read_only && (access & GENERIC_WRITE))
284 if ((err == STATUS_MEDIA_WRITE_PROTECTED) || (err == STATUS_ACCESS_DENIED))
286 TRACE("Write access failed for file '%s', trying without "
287 "write access\n", filename);
288 access &= ~GENERIC_WRITE;
289 goto restart;
293 if (ret == -1)
294 WARN("Unable to create file '%s' (GLE %ld)\n", filename,
295 GetLastError());
297 return ret;
301 /***********************************************************************
302 * FILE_CreateDevice
304 * Same as FILE_CreateFile but for a device
306 HFILE FILE_CreateDevice( int client_id, DWORD access, LPSECURITY_ATTRIBUTES sa )
308 HFILE ret;
309 SERVER_START_REQ
311 struct create_device_request *req = server_alloc_req( sizeof(*req), 0 );
313 req->access = access;
314 req->inherit = (sa && (sa->nLength>=sizeof(*sa)) && sa->bInheritHandle);
315 req->id = client_id;
316 SetLastError(0);
317 server_call( REQ_CREATE_DEVICE );
318 ret = req->handle;
320 SERVER_END_REQ;
321 return ret;
325 /*************************************************************************
326 * CreateFileA [KERNEL32.45] Creates or opens a file or other object
328 * Creates or opens an object, and returns a handle that can be used to
329 * access that object.
331 * PARAMS
333 * filename [I] pointer to filename to be accessed
334 * access [I] access mode requested
335 * sharing [I] share mode
336 * sa [I] pointer to security attributes
337 * creation [I] how to create the file
338 * attributes [I] attributes for newly created file
339 * template [I] handle to file with extended attributes to copy
341 * RETURNS
342 * Success: Open handle to specified file
343 * Failure: INVALID_HANDLE_VALUE
345 * NOTES
346 * Should call SetLastError() on failure.
348 * BUGS
350 * Doesn't support character devices, pipes, template files, or a
351 * lot of the 'attributes' flags yet.
353 HANDLE WINAPI CreateFileA( LPCSTR filename, DWORD access, DWORD sharing,
354 LPSECURITY_ATTRIBUTES sa, DWORD creation,
355 DWORD attributes, HANDLE template )
357 DOS_FULL_NAME full_name;
359 if (!filename)
361 SetLastError( ERROR_INVALID_PARAMETER );
362 return HFILE_ERROR;
364 TRACE("%s %s%s%s%s%s%s%s\n",filename,
365 ((access & GENERIC_READ)==GENERIC_READ)?"GENERIC_READ ":"",
366 ((access & GENERIC_WRITE)==GENERIC_WRITE)?"GENERIC_WRITE ":"",
367 (!access)?"QUERY_ACCESS ":"",
368 ((sharing & FILE_SHARE_READ)==FILE_SHARE_READ)?"FILE_SHARE_READ ":"",
369 ((sharing & FILE_SHARE_WRITE)==FILE_SHARE_WRITE)?"FILE_SHARE_WRITE ":"",
370 ((sharing & FILE_SHARE_DELETE)==FILE_SHARE_DELETE)?"FILE_SHARE_DELETE ":"",
371 (creation ==CREATE_NEW)?"CREATE_NEW":
372 (creation ==CREATE_ALWAYS)?"CREATE_ALWAYS ":
373 (creation ==OPEN_EXISTING)?"OPEN_EXISTING ":
374 (creation ==OPEN_ALWAYS)?"OPEN_ALWAYS ":
375 (creation ==TRUNCATE_EXISTING)?"TRUNCATE_EXISTING ":"");
377 /* If the name starts with '\\?\', ignore the first 4 chars. */
378 if (!strncmp(filename, "\\\\?\\", 4))
380 filename += 4;
381 if (!strncmp(filename, "UNC\\", 4))
383 FIXME("UNC name (%s) not supported.\n", filename );
384 SetLastError( ERROR_PATH_NOT_FOUND );
385 return HFILE_ERROR;
389 if (!strncmp(filename, "\\\\.\\", 4)) {
390 if (!DOSFS_GetDevice( filename ))
391 return DEVICE_Open( filename+4, access, sa );
392 else
393 filename+=4; /* fall into DOSFS_Device case below */
396 /* If the name still starts with '\\', it's a UNC name. */
397 if (!strncmp(filename, "\\\\", 2))
399 FIXME("UNC name (%s) not supported.\n", filename );
400 SetLastError( ERROR_PATH_NOT_FOUND );
401 return HFILE_ERROR;
404 /* If the name contains a DOS wild card (* or ?), do no create a file */
405 if(strchr(filename,'*') || strchr(filename,'?'))
406 return HFILE_ERROR;
408 /* Open a console for CONIN$ or CONOUT$ */
409 if (!strcasecmp(filename, "CONIN$")) return FILE_OpenConsole( FALSE, access, sa );
410 if (!strcasecmp(filename, "CONOUT$")) return FILE_OpenConsole( TRUE, access, sa );
412 if (DOSFS_GetDevice( filename ))
414 HFILE ret;
416 TRACE("opening device '%s'\n", filename );
418 if (HFILE_ERROR!=(ret=DOSFS_OpenDevice( filename, access )))
419 return ret;
421 /* Do not silence this please. It is a critical error. -MM */
422 ERR("Couldn't open device '%s'!\n",filename);
423 SetLastError( ERROR_FILE_NOT_FOUND );
424 return HFILE_ERROR;
427 /* check for filename, don't check for last entry if creating */
428 if (!DOSFS_GetFullName( filename,
429 (creation == OPEN_EXISTING) ||
430 (creation == TRUNCATE_EXISTING),
431 &full_name )) {
432 WARN("Unable to get full filename from '%s' (GLE %ld)\n",
433 filename, GetLastError());
434 return HFILE_ERROR;
437 return FILE_CreateFile( full_name.long_name, access, sharing,
438 sa, creation, attributes, template,
439 DRIVE_GetFlags(full_name.drive) & DRIVE_FAIL_READ_ONLY );
444 /*************************************************************************
445 * CreateFileW (KERNEL32.48)
447 HANDLE WINAPI CreateFileW( LPCWSTR filename, DWORD access, DWORD sharing,
448 LPSECURITY_ATTRIBUTES sa, DWORD creation,
449 DWORD attributes, HANDLE template)
451 LPSTR afn = HEAP_strdupWtoA( GetProcessHeap(), 0, filename );
452 HANDLE res = CreateFileA( afn, access, sharing, sa, creation, attributes, template );
453 HeapFree( GetProcessHeap(), 0, afn );
454 return res;
458 /***********************************************************************
459 * FILE_FillInfo
461 * Fill a file information from a struct stat.
463 static void FILE_FillInfo( struct stat *st, BY_HANDLE_FILE_INFORMATION *info )
465 if (S_ISDIR(st->st_mode))
466 info->dwFileAttributes = FILE_ATTRIBUTE_DIRECTORY;
467 else
468 info->dwFileAttributes = FILE_ATTRIBUTE_ARCHIVE;
469 if (!(st->st_mode & S_IWUSR))
470 info->dwFileAttributes |= FILE_ATTRIBUTE_READONLY;
472 RtlSecondsSince1970ToTime( st->st_mtime, &info->ftCreationTime );
473 RtlSecondsSince1970ToTime( st->st_mtime, &info->ftLastWriteTime );
474 RtlSecondsSince1970ToTime( st->st_atime, &info->ftLastAccessTime );
476 info->dwVolumeSerialNumber = 0; /* FIXME */
477 info->nFileSizeHigh = 0;
478 info->nFileSizeLow = S_ISDIR(st->st_mode) ? 0 : st->st_size;
479 info->nNumberOfLinks = st->st_nlink;
480 info->nFileIndexHigh = 0;
481 info->nFileIndexLow = st->st_ino;
485 /***********************************************************************
486 * FILE_Stat
488 * Stat a Unix path name. Return TRUE if OK.
490 BOOL FILE_Stat( LPCSTR unixName, BY_HANDLE_FILE_INFORMATION *info )
492 struct stat st;
494 if (lstat( unixName, &st ) == -1)
496 FILE_SetDosError();
497 return FALSE;
499 if (!S_ISLNK(st.st_mode)) FILE_FillInfo( &st, info );
500 else
502 /* do a "real" stat to find out
503 about the type of the symlink destination */
504 if (stat( unixName, &st ) == -1)
506 FILE_SetDosError();
507 return FALSE;
509 FILE_FillInfo( &st, info );
510 info->dwFileAttributes |= FILE_ATTRIBUTE_SYMLINK;
512 return TRUE;
516 /***********************************************************************
517 * GetFileInformationByHandle (KERNEL32.219)
519 DWORD WINAPI GetFileInformationByHandle( HANDLE hFile,
520 BY_HANDLE_FILE_INFORMATION *info )
522 DWORD ret;
523 if (!info) return 0;
525 SERVER_START_REQ
527 struct get_file_info_request *req = server_alloc_req( sizeof(*req), 0 );
528 req->handle = hFile;
529 if ((ret = !server_call( REQ_GET_FILE_INFO )))
531 RtlSecondsSince1970ToTime( req->write_time, &info->ftCreationTime );
532 RtlSecondsSince1970ToTime( req->write_time, &info->ftLastWriteTime );
533 RtlSecondsSince1970ToTime( req->access_time, &info->ftLastAccessTime );
534 info->dwFileAttributes = req->attr;
535 info->dwVolumeSerialNumber = req->serial;
536 info->nFileSizeHigh = req->size_high;
537 info->nFileSizeLow = req->size_low;
538 info->nNumberOfLinks = req->links;
539 info->nFileIndexHigh = req->index_high;
540 info->nFileIndexLow = req->index_low;
543 SERVER_END_REQ;
544 return ret;
548 /**************************************************************************
549 * GetFileAttributes16 (KERNEL.420)
551 DWORD WINAPI GetFileAttributes16( LPCSTR name )
553 return GetFileAttributesA( name );
557 /**************************************************************************
558 * GetFileAttributesA (KERNEL32.217)
560 DWORD WINAPI GetFileAttributesA( LPCSTR name )
562 DOS_FULL_NAME full_name;
563 BY_HANDLE_FILE_INFORMATION info;
565 if (name == NULL || *name=='\0') return -1;
567 if (!DOSFS_GetFullName( name, TRUE, &full_name )) return -1;
568 if (!FILE_Stat( full_name.long_name, &info )) return -1;
569 return info.dwFileAttributes;
573 /**************************************************************************
574 * GetFileAttributesW (KERNEL32.218)
576 DWORD WINAPI GetFileAttributesW( LPCWSTR name )
578 LPSTR nameA = HEAP_strdupWtoA( GetProcessHeap(), 0, name );
579 DWORD res = GetFileAttributesA( nameA );
580 HeapFree( GetProcessHeap(), 0, nameA );
581 return res;
585 /***********************************************************************
586 * GetFileSize (KERNEL32.220)
588 DWORD WINAPI GetFileSize( HANDLE hFile, LPDWORD filesizehigh )
590 BY_HANDLE_FILE_INFORMATION info;
591 if (!GetFileInformationByHandle( hFile, &info )) return 0;
592 if (filesizehigh) *filesizehigh = info.nFileSizeHigh;
593 return info.nFileSizeLow;
597 /***********************************************************************
598 * GetFileTime (KERNEL32.221)
600 BOOL WINAPI GetFileTime( HANDLE hFile, FILETIME *lpCreationTime,
601 FILETIME *lpLastAccessTime,
602 FILETIME *lpLastWriteTime )
604 BY_HANDLE_FILE_INFORMATION info;
605 if (!GetFileInformationByHandle( hFile, &info )) return FALSE;
606 if (lpCreationTime) *lpCreationTime = info.ftCreationTime;
607 if (lpLastAccessTime) *lpLastAccessTime = info.ftLastAccessTime;
608 if (lpLastWriteTime) *lpLastWriteTime = info.ftLastWriteTime;
609 return TRUE;
612 /***********************************************************************
613 * CompareFileTime (KERNEL32.28)
615 INT WINAPI CompareFileTime( LPFILETIME x, LPFILETIME y )
617 if (!x || !y) return -1;
619 if (x->dwHighDateTime > y->dwHighDateTime)
620 return 1;
621 if (x->dwHighDateTime < y->dwHighDateTime)
622 return -1;
623 if (x->dwLowDateTime > y->dwLowDateTime)
624 return 1;
625 if (x->dwLowDateTime < y->dwLowDateTime)
626 return -1;
627 return 0;
630 /***********************************************************************
631 * FILE_GetTempFileName : utility for GetTempFileName
633 static UINT FILE_GetTempFileName( LPCSTR path, LPCSTR prefix, UINT unique,
634 LPSTR buffer, BOOL isWin16 )
636 static UINT unique_temp;
637 DOS_FULL_NAME full_name;
638 int i;
639 LPSTR p;
640 UINT num;
642 if ( !path || !prefix || !buffer ) return 0;
644 if (!unique_temp) unique_temp = time(NULL) & 0xffff;
645 num = unique ? (unique & 0xffff) : (unique_temp++ & 0xffff);
647 strcpy( buffer, path );
648 p = buffer + strlen(buffer);
650 /* add a \, if there isn't one and path is more than just the drive letter ... */
651 if ( !((strlen(buffer) == 2) && (buffer[1] == ':'))
652 && ((p == buffer) || (p[-1] != '\\'))) *p++ = '\\';
654 if (isWin16) *p++ = '~';
655 for (i = 3; (i > 0) && (*prefix); i--) *p++ = *prefix++;
656 sprintf( p, "%04x.tmp", num );
658 /* Now try to create it */
660 if (!unique)
664 HFILE handle = CreateFileA( buffer, GENERIC_WRITE, 0, NULL,
665 CREATE_NEW, FILE_ATTRIBUTE_NORMAL, -1 );
666 if (handle != INVALID_HANDLE_VALUE)
667 { /* We created it */
668 TRACE("created %s\n",
669 buffer);
670 CloseHandle( handle );
671 break;
673 if (GetLastError() != ERROR_FILE_EXISTS)
674 break; /* No need to go on */
675 num++;
676 sprintf( p, "%04x.tmp", num );
677 } while (num != (unique & 0xffff));
680 /* Get the full path name */
682 if (DOSFS_GetFullName( buffer, FALSE, &full_name ))
684 /* Check if we have write access in the directory */
685 if ((p = strrchr( full_name.long_name, '/' ))) *p = '\0';
686 if (access( full_name.long_name, W_OK ) == -1)
687 WARN("returns '%s', which doesn't seem to be writeable.\n",
688 buffer);
690 TRACE("returning %s\n", buffer );
691 return unique ? unique : num;
695 /***********************************************************************
696 * GetTempFileNameA (KERNEL32.290)
698 UINT WINAPI GetTempFileNameA( LPCSTR path, LPCSTR prefix, UINT unique,
699 LPSTR buffer)
701 return FILE_GetTempFileName(path, prefix, unique, buffer, FALSE);
704 /***********************************************************************
705 * GetTempFileNameW (KERNEL32.291)
707 UINT WINAPI GetTempFileNameW( LPCWSTR path, LPCWSTR prefix, UINT unique,
708 LPWSTR buffer )
710 LPSTR patha,prefixa;
711 char buffera[144];
712 UINT ret;
714 if (!path) return 0;
715 patha = HEAP_strdupWtoA( GetProcessHeap(), 0, path );
716 prefixa = HEAP_strdupWtoA( GetProcessHeap(), 0, prefix );
717 ret = FILE_GetTempFileName( patha, prefixa, unique, buffera, FALSE );
718 MultiByteToWideChar( CP_ACP, 0, buffera, -1, buffer, MAX_PATH );
719 HeapFree( GetProcessHeap(), 0, patha );
720 HeapFree( GetProcessHeap(), 0, prefixa );
721 return ret;
725 /***********************************************************************
726 * GetTempFileName16 (KERNEL.97)
728 UINT16 WINAPI GetTempFileName16( BYTE drive, LPCSTR prefix, UINT16 unique,
729 LPSTR buffer )
731 char temppath[144];
733 if (!(drive & ~TF_FORCEDRIVE)) /* drive 0 means current default drive */
734 drive |= DRIVE_GetCurrentDrive() + 'A';
736 if ((drive & TF_FORCEDRIVE) &&
737 !DRIVE_IsValid( toupper(drive & ~TF_FORCEDRIVE) - 'A' ))
739 drive &= ~TF_FORCEDRIVE;
740 WARN("invalid drive %d specified\n", drive );
743 if (drive & TF_FORCEDRIVE)
744 sprintf(temppath,"%c:", drive & ~TF_FORCEDRIVE );
745 else
746 GetTempPathA( 132, temppath );
747 return (UINT16)FILE_GetTempFileName( temppath, prefix, unique, buffer, TRUE );
750 /***********************************************************************
751 * FILE_DoOpenFile
753 * Implementation of OpenFile16() and OpenFile32().
755 static HFILE FILE_DoOpenFile( LPCSTR name, OFSTRUCT *ofs, UINT mode,
756 BOOL win32 )
758 HFILE hFileRet;
759 FILETIME filetime;
760 WORD filedatetime[2];
761 DOS_FULL_NAME full_name;
762 DWORD access, sharing;
763 char *p;
765 if (!ofs) return HFILE_ERROR;
767 TRACE("%s %s %s %s%s%s%s%s%s%s%s%s\n",name,
768 ((mode & 0x3 )==OF_READ)?"OF_READ":
769 ((mode & 0x3 )==OF_WRITE)?"OF_WRITE":
770 ((mode & 0x3 )==OF_READWRITE)?"OF_READWRITE":"unknown",
771 ((mode & 0x70 )==OF_SHARE_COMPAT)?"OF_SHARE_COMPAT":
772 ((mode & 0x70 )==OF_SHARE_DENY_NONE)?"OF_SHARE_DENY_NONE":
773 ((mode & 0x70 )==OF_SHARE_DENY_READ)?"OF_SHARE_DENY_READ":
774 ((mode & 0x70 )==OF_SHARE_DENY_WRITE)?"OF_SHARE_DENY_WRITE":
775 ((mode & 0x70 )==OF_SHARE_EXCLUSIVE)?"OF_SHARE_EXCLUSIVE":"unknown",
776 ((mode & OF_PARSE )==OF_PARSE)?"OF_PARSE ":"",
777 ((mode & OF_DELETE )==OF_DELETE)?"OF_DELETE ":"",
778 ((mode & OF_VERIFY )==OF_VERIFY)?"OF_VERIFY ":"",
779 ((mode & OF_SEARCH )==OF_SEARCH)?"OF_SEARCH ":"",
780 ((mode & OF_CANCEL )==OF_CANCEL)?"OF_CANCEL ":"",
781 ((mode & OF_CREATE )==OF_CREATE)?"OF_CREATE ":"",
782 ((mode & OF_PROMPT )==OF_PROMPT)?"OF_PROMPT ":"",
783 ((mode & OF_EXIST )==OF_EXIST)?"OF_EXIST ":"",
784 ((mode & OF_REOPEN )==OF_REOPEN)?"OF_REOPEN ":""
788 ofs->cBytes = sizeof(OFSTRUCT);
789 ofs->nErrCode = 0;
790 if (mode & OF_REOPEN) name = ofs->szPathName;
792 if (!name) {
793 ERR("called with `name' set to NULL ! Please debug.\n");
794 return HFILE_ERROR;
797 TRACE("%s %04x\n", name, mode );
799 /* the watcom 10.6 IDE relies on a valid path returned in ofs->szPathName
800 Are there any cases where getting the path here is wrong?
801 Uwe Bonnes 1997 Apr 2 */
802 if (!GetFullPathNameA( name, sizeof(ofs->szPathName),
803 ofs->szPathName, NULL )) goto error;
804 FILE_ConvertOFMode( mode, &access, &sharing );
806 /* OF_PARSE simply fills the structure */
808 if (mode & OF_PARSE)
810 ofs->fFixedDisk = (GetDriveType16( ofs->szPathName[0]-'A' )
811 != DRIVE_REMOVABLE);
812 TRACE("(%s): OF_PARSE, res = '%s'\n",
813 name, ofs->szPathName );
814 return 0;
817 /* OF_CREATE is completely different from all other options, so
818 handle it first */
820 if (mode & OF_CREATE)
822 if ((hFileRet = CreateFileA( name, GENERIC_READ | GENERIC_WRITE,
823 sharing, NULL, CREATE_ALWAYS,
824 FILE_ATTRIBUTE_NORMAL, -1 ))== INVALID_HANDLE_VALUE)
825 goto error;
826 goto success;
829 /* If OF_SEARCH is set, ignore the given path */
831 if ((mode & OF_SEARCH) && !(mode & OF_REOPEN))
833 /* First try the file name as is */
834 if (DOSFS_GetFullName( name, TRUE, &full_name )) goto found;
835 /* Now remove the path */
836 if (name[0] && (name[1] == ':')) name += 2;
837 if ((p = strrchr( name, '\\' ))) name = p + 1;
838 if ((p = strrchr( name, '/' ))) name = p + 1;
839 if (!name[0]) goto not_found;
842 /* Now look for the file */
844 if (!DIR_SearchPath( NULL, name, NULL, &full_name, win32 )) goto not_found;
846 found:
847 TRACE("found %s = %s\n",
848 full_name.long_name, full_name.short_name );
849 lstrcpynA( ofs->szPathName, full_name.short_name,
850 sizeof(ofs->szPathName) );
852 if (mode & OF_SHARE_EXCLUSIVE)
853 /* Some InstallShield version uses OF_SHARE_EXCLUSIVE
854 on the file <tempdir>/_ins0432._mp to determine how
855 far installation has proceeded.
856 _ins0432._mp is an executable and while running the
857 application expects the open with OF_SHARE_ to fail*/
858 /* Probable FIXME:
859 As our loader closes the files after loading the executable,
860 we can't find the running executable with FILE_InUse.
861 Perhaps the loader should keep the file open.
862 Recheck against how Win handles that case */
864 char *last = strrchr(full_name.long_name,'/');
865 if (!last)
866 last = full_name.long_name - 1;
867 if (GetModuleHandle16(last+1))
869 TRACE("Denying shared open for %s\n",full_name.long_name);
870 return HFILE_ERROR;
874 if (mode & OF_DELETE)
876 if (unlink( full_name.long_name ) == -1) goto not_found;
877 TRACE("(%s): OF_DELETE return = OK\n", name);
878 return 1;
881 hFileRet = FILE_CreateFile( full_name.long_name, access, sharing,
882 NULL, OPEN_EXISTING, 0, -1,
883 DRIVE_GetFlags(full_name.drive) & DRIVE_FAIL_READ_ONLY );
884 if (hFileRet == HFILE_ERROR) goto not_found;
886 GetFileTime( hFileRet, NULL, NULL, &filetime );
887 FileTimeToDosDateTime( &filetime, &filedatetime[0], &filedatetime[1] );
888 if ((mode & OF_VERIFY) && (mode & OF_REOPEN))
890 if (memcmp( ofs->reserved, filedatetime, sizeof(ofs->reserved) ))
892 CloseHandle( hFileRet );
893 WARN("(%s): OF_VERIFY failed\n", name );
894 /* FIXME: what error here? */
895 SetLastError( ERROR_FILE_NOT_FOUND );
896 goto error;
899 memcpy( ofs->reserved, filedatetime, sizeof(ofs->reserved) );
901 success: /* We get here if the open was successful */
902 TRACE("(%s): OK, return = %d\n", name, hFileRet );
903 if (win32)
905 if (mode & OF_EXIST) /* Return the handle, but close it first */
906 CloseHandle( hFileRet );
908 else
910 hFileRet = Win32HandleToDosFileHandle( hFileRet );
911 if (hFileRet == HFILE_ERROR16) goto error;
912 if (mode & OF_EXIST) /* Return the handle, but close it first */
913 _lclose16( hFileRet );
915 return hFileRet;
917 not_found: /* We get here if the file does not exist */
918 WARN("'%s' not found or sharing violation\n", name );
919 SetLastError( ERROR_FILE_NOT_FOUND );
920 /* fall through */
922 error: /* We get here if there was an error opening the file */
923 ofs->nErrCode = GetLastError();
924 WARN("(%s): return = HFILE_ERROR error= %d\n",
925 name,ofs->nErrCode );
926 return HFILE_ERROR;
930 /***********************************************************************
931 * OpenFile16 (KERNEL.74)
933 HFILE16 WINAPI OpenFile16( LPCSTR name, OFSTRUCT *ofs, UINT16 mode )
935 return FILE_DoOpenFile( name, ofs, mode, FALSE );
939 /***********************************************************************
940 * OpenFile (KERNEL32.396)
942 HFILE WINAPI OpenFile( LPCSTR name, OFSTRUCT *ofs, UINT mode )
944 return FILE_DoOpenFile( name, ofs, mode, TRUE );
948 /***********************************************************************
949 * FILE_InitProcessDosHandles
951 * Allocates the default DOS handles for a process. Called either by
952 * Win32HandleToDosFileHandle below or by the DOSVM stuff.
954 static void FILE_InitProcessDosHandles( void )
956 dos_handles[0] = GetStdHandle(STD_INPUT_HANDLE);
957 dos_handles[1] = GetStdHandle(STD_OUTPUT_HANDLE);
958 dos_handles[2] = GetStdHandle(STD_ERROR_HANDLE);
959 dos_handles[3] = GetStdHandle(STD_ERROR_HANDLE);
960 dos_handles[4] = GetStdHandle(STD_ERROR_HANDLE);
963 /***********************************************************************
964 * Win32HandleToDosFileHandle (KERNEL32.21)
966 * Allocate a DOS handle for a Win32 handle. The Win32 handle is no
967 * longer valid after this function (even on failure).
969 * Note: this is not exactly right, since on Win95 the Win32 handles
970 * are on top of DOS handles and we do it the other way
971 * around. Should be good enough though.
973 HFILE WINAPI Win32HandleToDosFileHandle( HANDLE handle )
975 int i;
977 if (!handle || (handle == INVALID_HANDLE_VALUE))
978 return HFILE_ERROR;
980 for (i = 5; i < DOS_TABLE_SIZE; i++)
981 if (!dos_handles[i])
983 dos_handles[i] = handle;
984 TRACE("Got %d for h32 %d\n", i, handle );
985 return (HFILE)i;
987 CloseHandle( handle );
988 SetLastError( ERROR_TOO_MANY_OPEN_FILES );
989 return HFILE_ERROR;
993 /***********************************************************************
994 * DosFileHandleToWin32Handle (KERNEL32.20)
996 * Return the Win32 handle for a DOS handle.
998 * Note: this is not exactly right, since on Win95 the Win32 handles
999 * are on top of DOS handles and we do it the other way
1000 * around. Should be good enough though.
1002 HANDLE WINAPI DosFileHandleToWin32Handle( HFILE handle )
1004 HFILE16 hfile = (HFILE16)handle;
1005 if (hfile < 5 && !dos_handles[hfile]) FILE_InitProcessDosHandles();
1006 if ((hfile >= DOS_TABLE_SIZE) || !dos_handles[hfile])
1008 SetLastError( ERROR_INVALID_HANDLE );
1009 return INVALID_HANDLE_VALUE;
1011 return dos_handles[hfile];
1015 /***********************************************************************
1016 * DisposeLZ32Handle (KERNEL32.22)
1018 * Note: this is not entirely correct, we should only close the
1019 * 32-bit handle and not the 16-bit one, but we cannot do
1020 * this because of the way our DOS handles are implemented.
1021 * It shouldn't break anything though.
1023 void WINAPI DisposeLZ32Handle( HANDLE handle )
1025 int i;
1027 if (!handle || (handle == INVALID_HANDLE_VALUE)) return;
1029 for (i = 5; i < DOS_TABLE_SIZE; i++)
1030 if (dos_handles[i] == handle)
1032 dos_handles[i] = 0;
1033 CloseHandle( handle );
1034 break;
1039 /***********************************************************************
1040 * FILE_Dup2
1042 * dup2() function for DOS handles.
1044 HFILE16 FILE_Dup2( HFILE16 hFile1, HFILE16 hFile2 )
1046 HANDLE new_handle;
1048 if (hFile1 < 5 && !dos_handles[hFile1]) FILE_InitProcessDosHandles();
1050 if ((hFile1 >= DOS_TABLE_SIZE) || (hFile2 >= DOS_TABLE_SIZE) || !dos_handles[hFile1])
1052 SetLastError( ERROR_INVALID_HANDLE );
1053 return HFILE_ERROR16;
1055 if (hFile2 < 5)
1057 FIXME("stdio handle closed, need proper conversion\n" );
1058 SetLastError( ERROR_INVALID_HANDLE );
1059 return HFILE_ERROR16;
1061 if (!DuplicateHandle( GetCurrentProcess(), dos_handles[hFile1],
1062 GetCurrentProcess(), &new_handle,
1063 0, FALSE, DUPLICATE_SAME_ACCESS ))
1064 return HFILE_ERROR16;
1065 if (dos_handles[hFile2]) CloseHandle( dos_handles[hFile2] );
1066 dos_handles[hFile2] = new_handle;
1067 return hFile2;
1071 /***********************************************************************
1072 * _lclose16 (KERNEL.81)
1074 HFILE16 WINAPI _lclose16( HFILE16 hFile )
1076 if (hFile < 5)
1078 FIXME("stdio handle closed, need proper conversion\n" );
1079 SetLastError( ERROR_INVALID_HANDLE );
1080 return HFILE_ERROR16;
1082 if ((hFile >= DOS_TABLE_SIZE) || !dos_handles[hFile])
1084 SetLastError( ERROR_INVALID_HANDLE );
1085 return HFILE_ERROR16;
1087 TRACE("%d (handle32=%d)\n", hFile, dos_handles[hFile] );
1088 CloseHandle( dos_handles[hFile] );
1089 dos_handles[hFile] = 0;
1090 return 0;
1094 /***********************************************************************
1095 * _lclose (KERNEL32.592)
1097 HFILE WINAPI _lclose( HFILE hFile )
1099 TRACE("handle %d\n", hFile );
1100 return CloseHandle( hFile ) ? 0 : HFILE_ERROR;
1103 /***********************************************************************
1104 * GetOverlappedResult (KERNEL32.360)
1106 BOOL WINAPI GetOverlappedResult(HANDLE hFile,LPOVERLAPPED lpOverlapped,
1107 LPDWORD lpNumberOfBytesTransferred,
1108 BOOL bWait)
1110 /* Since all i/o is currently synchronous,
1111 * return true, assuming ReadFile/WriteFile
1112 * have completed the operation */
1113 FIXME("NO Asynch I/O, assuming Read/Write succeeded\n" );
1114 return TRUE;
1117 /***********************************************************************
1118 * ReadFile (KERNEL32.428)
1120 BOOL WINAPI ReadFile( HANDLE hFile, LPVOID buffer, DWORD bytesToRead,
1121 LPDWORD bytesRead, LPOVERLAPPED overlapped )
1123 int unix_handle, result;
1125 TRACE("%d %p %ld\n", hFile, buffer, bytesToRead );
1127 if (bytesRead) *bytesRead = 0; /* Do this before anything else */
1128 if (!bytesToRead) return TRUE;
1130 if ( overlapped ) {
1131 SetLastError ( ERROR_INVALID_PARAMETER );
1132 return FALSE;
1135 unix_handle = FILE_GetUnixHandle( hFile, GENERIC_READ );
1136 if (unix_handle == -1) return FALSE;
1137 while ((result = read( unix_handle, buffer, bytesToRead )) == -1)
1139 if ((errno == EAGAIN) || (errno == EINTR)) continue;
1140 if ((errno == EFAULT) && !VIRTUAL_HandleFault( buffer )) continue;
1141 FILE_SetDosError();
1142 break;
1144 close( unix_handle );
1145 if (result == -1) return FALSE;
1146 if (bytesRead) *bytesRead = result;
1147 return TRUE;
1151 /***********************************************************************
1152 * WriteFile (KERNEL32.578)
1154 BOOL WINAPI WriteFile( HANDLE hFile, LPCVOID buffer, DWORD bytesToWrite,
1155 LPDWORD bytesWritten, LPOVERLAPPED overlapped )
1157 int unix_handle, result;
1159 TRACE("%d %p %ld\n", hFile, buffer, bytesToWrite );
1161 if (bytesWritten) *bytesWritten = 0; /* Do this before anything else */
1162 if (!bytesToWrite) return TRUE;
1164 if ( overlapped ) {
1165 SetLastError ( ERROR_INVALID_PARAMETER );
1166 return FALSE;
1169 unix_handle = FILE_GetUnixHandle( hFile, GENERIC_WRITE );
1170 if (unix_handle == -1) return FALSE;
1171 while ((result = write( unix_handle, buffer, bytesToWrite )) == -1)
1173 if ((errno == EAGAIN) || (errno == EINTR)) continue;
1174 if ((errno == EFAULT) && !VIRTUAL_HandleFault( buffer )) continue;
1175 if (errno == ENOSPC)
1176 SetLastError( ERROR_DISK_FULL );
1177 else
1178 FILE_SetDosError();
1179 break;
1181 close( unix_handle );
1182 if (result == -1) return FALSE;
1183 if (bytesWritten) *bytesWritten = result;
1184 return TRUE;
1188 /***********************************************************************
1189 * WIN16_hread
1191 LONG WINAPI WIN16_hread( HFILE16 hFile, SEGPTR buffer, LONG count )
1193 LONG maxlen;
1195 TRACE("%d %08lx %ld\n",
1196 hFile, (DWORD)buffer, count );
1198 /* Some programs pass a count larger than the allocated buffer */
1199 maxlen = GetSelectorLimit16( SELECTOROF(buffer) ) - OFFSETOF(buffer) + 1;
1200 if (count > maxlen) count = maxlen;
1201 return _lread(DosFileHandleToWin32Handle(hFile), PTR_SEG_TO_LIN(buffer), count );
1205 /***********************************************************************
1206 * WIN16_lread
1208 UINT16 WINAPI WIN16_lread( HFILE16 hFile, SEGPTR buffer, UINT16 count )
1210 return (UINT16)WIN16_hread( hFile, buffer, (LONG)count );
1214 /***********************************************************************
1215 * _lread (KERNEL32.596)
1217 UINT WINAPI _lread( HFILE handle, LPVOID buffer, UINT count )
1219 DWORD result;
1220 if (!ReadFile( handle, buffer, count, &result, NULL )) return -1;
1221 return result;
1225 /***********************************************************************
1226 * _lread16 (KERNEL.82)
1228 UINT16 WINAPI _lread16( HFILE16 hFile, LPVOID buffer, UINT16 count )
1230 return (UINT16)_lread(DosFileHandleToWin32Handle(hFile), buffer, (LONG)count );
1234 /***********************************************************************
1235 * _lcreat16 (KERNEL.83)
1237 HFILE16 WINAPI _lcreat16( LPCSTR path, INT16 attr )
1239 return Win32HandleToDosFileHandle( _lcreat( path, attr ) );
1243 /***********************************************************************
1244 * _lcreat (KERNEL32.593)
1246 HFILE WINAPI _lcreat( LPCSTR path, INT attr )
1248 /* Mask off all flags not explicitly allowed by the doc */
1249 attr &= FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM;
1250 TRACE("%s %02x\n", path, attr );
1251 return CreateFileA( path, GENERIC_READ | GENERIC_WRITE,
1252 FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
1253 CREATE_ALWAYS, attr, -1 );
1257 /***********************************************************************
1258 * SetFilePointer (KERNEL32.492)
1260 DWORD WINAPI SetFilePointer( HANDLE hFile, LONG distance, LONG *highword,
1261 DWORD method )
1263 DWORD ret = 0xffffffff;
1265 if (highword &&
1266 ((distance >= 0 && *highword != 0) || (distance < 0 && *highword != -1)))
1268 FIXME("64-bit offsets not supported yet\n"
1269 "SetFilePointer(%08x,%08lx,%08lx,%08lx)\n",
1270 hFile,distance,*highword,method);
1271 SetLastError( ERROR_INVALID_PARAMETER );
1272 return ret;
1274 TRACE("handle %d offset %ld origin %ld\n",
1275 hFile, distance, method );
1277 SERVER_START_REQ
1279 struct set_file_pointer_request *req = server_alloc_req( sizeof(*req), 0 );
1280 req->handle = hFile;
1281 req->low = distance;
1282 req->high = highword ? *highword : (distance >= 0) ? 0 : -1;
1283 /* FIXME: assumes 1:1 mapping between Windows and Unix seek constants */
1284 req->whence = method;
1285 SetLastError( 0 );
1286 if (!server_call( REQ_SET_FILE_POINTER ))
1288 ret = req->new_low;
1289 if (highword) *highword = req->new_high;
1292 SERVER_END_REQ;
1293 return ret;
1297 /***********************************************************************
1298 * _llseek16 (KERNEL.84)
1300 * FIXME:
1301 * Seeking before the start of the file should be allowed for _llseek16,
1302 * but cause subsequent I/O operations to fail (cf. interrupt list)
1305 LONG WINAPI _llseek16( HFILE16 hFile, LONG lOffset, INT16 nOrigin )
1307 return SetFilePointer( DosFileHandleToWin32Handle(hFile), lOffset, NULL, nOrigin );
1311 /***********************************************************************
1312 * _llseek (KERNEL32.594)
1314 LONG WINAPI _llseek( HFILE hFile, LONG lOffset, INT nOrigin )
1316 return SetFilePointer( hFile, lOffset, NULL, nOrigin );
1320 /***********************************************************************
1321 * _lopen16 (KERNEL.85)
1323 HFILE16 WINAPI _lopen16( LPCSTR path, INT16 mode )
1325 return Win32HandleToDosFileHandle( _lopen( path, mode ) );
1329 /***********************************************************************
1330 * _lopen (KERNEL32.595)
1332 HFILE WINAPI _lopen( LPCSTR path, INT mode )
1334 DWORD access, sharing;
1336 TRACE("('%s',%04x)\n", path, mode );
1337 FILE_ConvertOFMode( mode, &access, &sharing );
1338 return CreateFileA( path, access, sharing, NULL, OPEN_EXISTING, 0, -1 );
1342 /***********************************************************************
1343 * _lwrite16 (KERNEL.86)
1345 UINT16 WINAPI _lwrite16( HFILE16 hFile, LPCSTR buffer, UINT16 count )
1347 return (UINT16)_hwrite( DosFileHandleToWin32Handle(hFile), buffer, (LONG)count );
1350 /***********************************************************************
1351 * _lwrite (KERNEL32.761)
1353 UINT WINAPI _lwrite( HFILE hFile, LPCSTR buffer, UINT count )
1355 return (UINT)_hwrite( hFile, buffer, (LONG)count );
1359 /***********************************************************************
1360 * _hread16 (KERNEL.349)
1362 LONG WINAPI _hread16( HFILE16 hFile, LPVOID buffer, LONG count)
1364 return _lread( DosFileHandleToWin32Handle(hFile), buffer, count );
1368 /***********************************************************************
1369 * _hread (KERNEL32.590)
1371 LONG WINAPI _hread( HFILE hFile, LPVOID buffer, LONG count)
1373 return _lread( hFile, buffer, count );
1377 /***********************************************************************
1378 * _hwrite16 (KERNEL.350)
1380 LONG WINAPI _hwrite16( HFILE16 hFile, LPCSTR buffer, LONG count )
1382 return _hwrite( DosFileHandleToWin32Handle(hFile), buffer, count );
1386 /***********************************************************************
1387 * _hwrite (KERNEL32.591)
1389 * experimentation yields that _lwrite:
1390 * o truncates the file at the current position with
1391 * a 0 len write
1392 * o returns 0 on a 0 length write
1393 * o works with console handles
1396 LONG WINAPI _hwrite( HFILE handle, LPCSTR buffer, LONG count )
1398 DWORD result;
1400 TRACE("%d %p %ld\n", handle, buffer, count );
1402 if (!count)
1404 /* Expand or truncate at current position */
1405 if (!SetEndOfFile( handle )) return HFILE_ERROR;
1406 return 0;
1408 if (!WriteFile( handle, buffer, count, &result, NULL ))
1409 return HFILE_ERROR;
1410 return result;
1414 /***********************************************************************
1415 * SetHandleCount16 (KERNEL.199)
1417 UINT16 WINAPI SetHandleCount16( UINT16 count )
1419 HGLOBAL16 hPDB = GetCurrentPDB16();
1420 PDB16 *pdb = (PDB16 *)GlobalLock16( hPDB );
1421 BYTE *files = PTR_SEG_TO_LIN( pdb->fileHandlesPtr );
1423 TRACE("(%d)\n", count );
1425 if (count < 20) count = 20; /* No point in going below 20 */
1426 else if (count > 254) count = 254;
1428 if (count == 20)
1430 if (pdb->nbFiles > 20)
1432 memcpy( pdb->fileHandles, files, 20 );
1433 GlobalFree16( pdb->hFileHandles );
1434 pdb->fileHandlesPtr = (SEGPTR)MAKELONG( 0x18,
1435 GlobalHandleToSel16( hPDB ) );
1436 pdb->hFileHandles = 0;
1437 pdb->nbFiles = 20;
1440 else /* More than 20, need a new file handles table */
1442 BYTE *newfiles;
1443 HGLOBAL16 newhandle = GlobalAlloc16( GMEM_MOVEABLE, count );
1444 if (!newhandle)
1446 SetLastError( ERROR_NOT_ENOUGH_MEMORY );
1447 return pdb->nbFiles;
1449 newfiles = (BYTE *)GlobalLock16( newhandle );
1451 if (count > pdb->nbFiles)
1453 memcpy( newfiles, files, pdb->nbFiles );
1454 memset( newfiles + pdb->nbFiles, 0xff, count - pdb->nbFiles );
1456 else memcpy( newfiles, files, count );
1457 if (pdb->nbFiles > 20) GlobalFree16( pdb->hFileHandles );
1458 pdb->fileHandlesPtr = WIN16_GlobalLock16( newhandle );
1459 pdb->hFileHandles = newhandle;
1460 pdb->nbFiles = count;
1462 return pdb->nbFiles;
1466 /*************************************************************************
1467 * SetHandleCount (KERNEL32.494)
1469 UINT WINAPI SetHandleCount( UINT count )
1471 return min( 256, count );
1475 /***********************************************************************
1476 * FlushFileBuffers (KERNEL32.133)
1478 BOOL WINAPI FlushFileBuffers( HANDLE hFile )
1480 BOOL ret;
1481 SERVER_START_REQ
1483 struct flush_file_request *req = server_alloc_req( sizeof(*req), 0 );
1484 req->handle = hFile;
1485 ret = !server_call( REQ_FLUSH_FILE );
1487 SERVER_END_REQ;
1488 return ret;
1492 /**************************************************************************
1493 * SetEndOfFile (KERNEL32.483)
1495 BOOL WINAPI SetEndOfFile( HANDLE hFile )
1497 BOOL ret;
1498 SERVER_START_REQ
1500 struct truncate_file_request *req = server_alloc_req( sizeof(*req), 0 );
1501 req->handle = hFile;
1502 ret = !server_call( REQ_TRUNCATE_FILE );
1504 SERVER_END_REQ;
1505 return ret;
1509 /***********************************************************************
1510 * DeleteFile16 (KERNEL.146)
1512 BOOL16 WINAPI DeleteFile16( LPCSTR path )
1514 return DeleteFileA( path );
1518 /***********************************************************************
1519 * DeleteFileA (KERNEL32.71)
1521 BOOL WINAPI DeleteFileA( LPCSTR path )
1523 DOS_FULL_NAME full_name;
1525 TRACE("'%s'\n", path );
1527 if (!*path)
1529 ERR("Empty path passed\n");
1530 return FALSE;
1532 if (DOSFS_GetDevice( path ))
1534 WARN("cannot remove DOS device '%s'!\n", path);
1535 SetLastError( ERROR_FILE_NOT_FOUND );
1536 return FALSE;
1539 if (!DOSFS_GetFullName( path, TRUE, &full_name )) return FALSE;
1540 if (unlink( full_name.long_name ) == -1)
1542 FILE_SetDosError();
1543 return FALSE;
1545 return TRUE;
1549 /***********************************************************************
1550 * DeleteFileW (KERNEL32.72)
1552 BOOL WINAPI DeleteFileW( LPCWSTR path )
1554 LPSTR xpath = HEAP_strdupWtoA( GetProcessHeap(), 0, path );
1555 BOOL ret = DeleteFileA( xpath );
1556 HeapFree( GetProcessHeap(), 0, xpath );
1557 return ret;
1561 /***********************************************************************
1562 * GetFileType (KERNEL32.222)
1564 DWORD WINAPI GetFileType( HANDLE hFile )
1566 DWORD ret = FILE_TYPE_UNKNOWN;
1567 SERVER_START_REQ
1569 struct get_file_info_request *req = server_alloc_req( sizeof(*req), 0 );
1570 req->handle = hFile;
1571 if (!server_call( REQ_GET_FILE_INFO )) ret = req->type;
1573 SERVER_END_REQ;
1574 return ret;
1578 /**************************************************************************
1579 * MoveFileExA (KERNEL32.???)
1581 BOOL WINAPI MoveFileExA( LPCSTR fn1, LPCSTR fn2, DWORD flag )
1583 DOS_FULL_NAME full_name1, full_name2;
1585 TRACE("(%s,%s,%04lx)\n", fn1, fn2, flag);
1587 if (!DOSFS_GetFullName( fn1, TRUE, &full_name1 )) return FALSE;
1589 if (fn2) /* !fn2 means delete fn1 */
1591 if (DOSFS_GetFullName( fn2, TRUE, &full_name2 ))
1593 /* target exists, check if we may overwrite */
1594 if (!(flag & MOVEFILE_REPLACE_EXISTING))
1596 /* FIXME: Use right error code */
1597 SetLastError( ERROR_ACCESS_DENIED );
1598 return FALSE;
1601 else if (!DOSFS_GetFullName( fn2, FALSE, &full_name2 )) return FALSE;
1603 /* Source name and target path are valid */
1605 if (flag & MOVEFILE_DELAY_UNTIL_REBOOT)
1607 /* FIXME: (bon@elektron.ikp.physik.th-darmstadt.de 970706)
1608 Perhaps we should queue these command and execute it
1609 when exiting... What about using on_exit(2)
1611 FIXME("Please move existing file '%s' to file '%s' when Wine has finished\n",
1612 full_name1.long_name, full_name2.long_name);
1613 return TRUE;
1616 if (full_name1.drive != full_name2.drive)
1618 /* use copy, if allowed */
1619 if (!(flag & MOVEFILE_COPY_ALLOWED))
1621 /* FIXME: Use right error code */
1622 SetLastError( ERROR_FILE_EXISTS );
1623 return FALSE;
1625 return CopyFileA( fn1, fn2, !(flag & MOVEFILE_REPLACE_EXISTING) );
1627 if (rename( full_name1.long_name, full_name2.long_name ) == -1)
1629 FILE_SetDosError();
1630 return FALSE;
1632 return TRUE;
1634 else /* fn2 == NULL means delete source */
1636 if (flag & MOVEFILE_DELAY_UNTIL_REBOOT)
1638 if (flag & MOVEFILE_COPY_ALLOWED) {
1639 WARN("Illegal flag\n");
1640 SetLastError( ERROR_GEN_FAILURE );
1641 return FALSE;
1643 /* FIXME: (bon@elektron.ikp.physik.th-darmstadt.de 970706)
1644 Perhaps we should queue these command and execute it
1645 when exiting... What about using on_exit(2)
1647 FIXME("Please delete file '%s' when Wine has finished\n",
1648 full_name1.long_name);
1649 return TRUE;
1652 if (unlink( full_name1.long_name ) == -1)
1654 FILE_SetDosError();
1655 return FALSE;
1657 return TRUE; /* successfully deleted */
1661 /**************************************************************************
1662 * MoveFileExW (KERNEL32.???)
1664 BOOL WINAPI MoveFileExW( LPCWSTR fn1, LPCWSTR fn2, DWORD flag )
1666 LPSTR afn1 = HEAP_strdupWtoA( GetProcessHeap(), 0, fn1 );
1667 LPSTR afn2 = HEAP_strdupWtoA( GetProcessHeap(), 0, fn2 );
1668 BOOL res = MoveFileExA( afn1, afn2, flag );
1669 HeapFree( GetProcessHeap(), 0, afn1 );
1670 HeapFree( GetProcessHeap(), 0, afn2 );
1671 return res;
1675 /**************************************************************************
1676 * MoveFileA (KERNEL32.387)
1678 * Move file or directory
1680 BOOL WINAPI MoveFileA( LPCSTR fn1, LPCSTR fn2 )
1682 DOS_FULL_NAME full_name1, full_name2;
1683 struct stat fstat;
1685 TRACE("(%s,%s)\n", fn1, fn2 );
1687 if (!DOSFS_GetFullName( fn1, TRUE, &full_name1 )) return FALSE;
1688 if (DOSFS_GetFullName( fn2, TRUE, &full_name2 )) {
1689 /* The new name must not already exist */
1690 SetLastError(ERROR_ALREADY_EXISTS);
1691 return FALSE;
1693 if (!DOSFS_GetFullName( fn2, FALSE, &full_name2 )) return FALSE;
1695 if (full_name1.drive == full_name2.drive) /* move */
1696 if (rename( full_name1.long_name, full_name2.long_name ) == -1)
1698 FILE_SetDosError();
1699 return FALSE;
1701 else return TRUE;
1702 else /*copy */ {
1703 if (stat( full_name1.long_name, &fstat ))
1705 WARN("Invalid source file %s\n",
1706 full_name1.long_name);
1707 FILE_SetDosError();
1708 return FALSE;
1710 if (S_ISDIR(fstat.st_mode)) {
1711 /* No Move for directories across file systems */
1712 /* FIXME: Use right error code */
1713 SetLastError( ERROR_GEN_FAILURE );
1714 return FALSE;
1716 else
1717 return CopyFileA(fn1, fn2, TRUE); /*fail, if exist */
1722 /**************************************************************************
1723 * MoveFileW (KERNEL32.390)
1725 BOOL WINAPI MoveFileW( LPCWSTR fn1, LPCWSTR fn2 )
1727 LPSTR afn1 = HEAP_strdupWtoA( GetProcessHeap(), 0, fn1 );
1728 LPSTR afn2 = HEAP_strdupWtoA( GetProcessHeap(), 0, fn2 );
1729 BOOL res = MoveFileA( afn1, afn2 );
1730 HeapFree( GetProcessHeap(), 0, afn1 );
1731 HeapFree( GetProcessHeap(), 0, afn2 );
1732 return res;
1736 /**************************************************************************
1737 * CopyFileA (KERNEL32.36)
1739 BOOL WINAPI CopyFileA( LPCSTR source, LPCSTR dest, BOOL fail_if_exists )
1741 HFILE h1, h2;
1742 BY_HANDLE_FILE_INFORMATION info;
1743 UINT count;
1744 BOOL ret = FALSE;
1745 int mode;
1746 char buffer[2048];
1748 if ((h1 = _lopen( source, OF_READ )) == HFILE_ERROR) return FALSE;
1749 if (!GetFileInformationByHandle( h1, &info ))
1751 CloseHandle( h1 );
1752 return FALSE;
1754 mode = (info.dwFileAttributes & FILE_ATTRIBUTE_READONLY) ? 0444 : 0666;
1755 if ((h2 = CreateFileA( dest, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
1756 fail_if_exists ? CREATE_NEW : CREATE_ALWAYS,
1757 info.dwFileAttributes, h1 )) == HFILE_ERROR)
1759 CloseHandle( h1 );
1760 return FALSE;
1762 while ((count = _lread( h1, buffer, sizeof(buffer) )) > 0)
1764 char *p = buffer;
1765 while (count > 0)
1767 INT res = _lwrite( h2, p, count );
1768 if (res <= 0) goto done;
1769 p += res;
1770 count -= res;
1773 ret = TRUE;
1774 done:
1775 CloseHandle( h1 );
1776 CloseHandle( h2 );
1777 return ret;
1781 /**************************************************************************
1782 * CopyFileW (KERNEL32.37)
1784 BOOL WINAPI CopyFileW( LPCWSTR source, LPCWSTR dest, BOOL fail_if_exists)
1786 LPSTR sourceA = HEAP_strdupWtoA( GetProcessHeap(), 0, source );
1787 LPSTR destA = HEAP_strdupWtoA( GetProcessHeap(), 0, dest );
1788 BOOL ret = CopyFileA( sourceA, destA, fail_if_exists );
1789 HeapFree( GetProcessHeap(), 0, sourceA );
1790 HeapFree( GetProcessHeap(), 0, destA );
1791 return ret;
1795 /**************************************************************************
1796 * CopyFileExA (KERNEL32.858)
1798 * This implementation ignores most of the extra parameters passed-in into
1799 * the "ex" version of the method and calls the CopyFile method.
1800 * It will have to be fixed eventually.
1802 BOOL WINAPI CopyFileExA(LPCSTR sourceFilename,
1803 LPCSTR destFilename,
1804 LPPROGRESS_ROUTINE progressRoutine,
1805 LPVOID appData,
1806 LPBOOL cancelFlagPointer,
1807 DWORD copyFlags)
1809 BOOL failIfExists = FALSE;
1812 * Interpret the only flag that CopyFile can interpret.
1814 if ( (copyFlags & COPY_FILE_FAIL_IF_EXISTS) != 0)
1816 failIfExists = TRUE;
1819 return CopyFileA(sourceFilename, destFilename, failIfExists);
1822 /**************************************************************************
1823 * CopyFileExW (KERNEL32.859)
1825 BOOL WINAPI CopyFileExW(LPCWSTR sourceFilename,
1826 LPCWSTR destFilename,
1827 LPPROGRESS_ROUTINE progressRoutine,
1828 LPVOID appData,
1829 LPBOOL cancelFlagPointer,
1830 DWORD copyFlags)
1832 LPSTR sourceA = HEAP_strdupWtoA( GetProcessHeap(), 0, sourceFilename );
1833 LPSTR destA = HEAP_strdupWtoA( GetProcessHeap(), 0, destFilename );
1835 BOOL ret = CopyFileExA(sourceA,
1836 destA,
1837 progressRoutine,
1838 appData,
1839 cancelFlagPointer,
1840 copyFlags);
1842 HeapFree( GetProcessHeap(), 0, sourceA );
1843 HeapFree( GetProcessHeap(), 0, destA );
1845 return ret;
1849 /***********************************************************************
1850 * SetFileTime (KERNEL32.650)
1852 BOOL WINAPI SetFileTime( HANDLE hFile,
1853 const FILETIME *lpCreationTime,
1854 const FILETIME *lpLastAccessTime,
1855 const FILETIME *lpLastWriteTime )
1857 BOOL ret;
1858 SERVER_START_REQ
1860 struct set_file_time_request *req = server_alloc_req( sizeof(*req), 0 );
1861 req->handle = hFile;
1862 if (lpLastAccessTime)
1863 RtlTimeToSecondsSince1970( lpLastAccessTime, (DWORD *)&req->access_time );
1864 else
1865 req->access_time = 0; /* FIXME */
1866 if (lpLastWriteTime)
1867 RtlTimeToSecondsSince1970( lpLastWriteTime, (DWORD *)&req->write_time );
1868 else
1869 req->write_time = 0; /* FIXME */
1870 ret = !server_call( REQ_SET_FILE_TIME );
1872 SERVER_END_REQ;
1873 return ret;
1877 /**************************************************************************
1878 * LockFile (KERNEL32.511)
1880 BOOL WINAPI LockFile( HANDLE hFile, DWORD dwFileOffsetLow, DWORD dwFileOffsetHigh,
1881 DWORD nNumberOfBytesToLockLow, DWORD nNumberOfBytesToLockHigh )
1883 BOOL ret;
1884 SERVER_START_REQ
1886 struct lock_file_request *req = server_alloc_req( sizeof(*req), 0 );
1888 req->handle = hFile;
1889 req->offset_low = dwFileOffsetLow;
1890 req->offset_high = dwFileOffsetHigh;
1891 req->count_low = nNumberOfBytesToLockLow;
1892 req->count_high = nNumberOfBytesToLockHigh;
1893 ret = !server_call( REQ_LOCK_FILE );
1895 SERVER_END_REQ;
1896 return ret;
1899 /**************************************************************************
1900 * LockFileEx [KERNEL32.512]
1902 * Locks a byte range within an open file for shared or exclusive access.
1904 * RETURNS
1905 * success: TRUE
1906 * failure: FALSE
1907 * NOTES
1909 * Per Microsoft docs, the third parameter (reserved) must be set to 0.
1911 BOOL WINAPI LockFileEx( HANDLE hFile, DWORD flags, DWORD reserved,
1912 DWORD nNumberOfBytesToLockLow, DWORD nNumberOfBytesToLockHigh,
1913 LPOVERLAPPED pOverlapped )
1915 FIXME("hFile=%d,flags=%ld,reserved=%ld,lowbytes=%ld,highbytes=%ld,overlapped=%p: stub.\n",
1916 hFile, flags, reserved, nNumberOfBytesToLockLow, nNumberOfBytesToLockHigh,
1917 pOverlapped);
1918 if (reserved == 0)
1919 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1920 else
1922 ERR("reserved == %ld: Supposed to be 0??\n", reserved);
1923 SetLastError(ERROR_INVALID_PARAMETER);
1926 return FALSE;
1930 /**************************************************************************
1931 * UnlockFile (KERNEL32.703)
1933 BOOL WINAPI UnlockFile( HANDLE hFile, DWORD dwFileOffsetLow, DWORD dwFileOffsetHigh,
1934 DWORD nNumberOfBytesToUnlockLow, DWORD nNumberOfBytesToUnlockHigh )
1936 BOOL ret;
1937 SERVER_START_REQ
1939 struct unlock_file_request *req = server_alloc_req( sizeof(*req), 0 );
1941 req->handle = hFile;
1942 req->offset_low = dwFileOffsetLow;
1943 req->offset_high = dwFileOffsetHigh;
1944 req->count_low = nNumberOfBytesToUnlockLow;
1945 req->count_high = nNumberOfBytesToUnlockHigh;
1946 ret = !server_call( REQ_UNLOCK_FILE );
1948 SERVER_END_REQ;
1949 return ret;
1953 /**************************************************************************
1954 * UnlockFileEx (KERNEL32.705)
1956 BOOL WINAPI UnlockFileEx(
1957 HFILE hFile,
1958 DWORD dwReserved,
1959 DWORD nNumberOfBytesToUnlockLow,
1960 DWORD nNumberOfBytesToUnlockHigh,
1961 LPOVERLAPPED lpOverlapped
1964 FIXME("hFile=%d,reserved=%ld,lowbytes=%ld,highbytes=%ld,overlapped=%p: stub.\n",
1965 hFile, dwReserved, nNumberOfBytesToUnlockLow, nNumberOfBytesToUnlockHigh,
1966 lpOverlapped);
1967 if (dwReserved == 0)
1968 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1969 else
1971 ERR("reserved == %ld: Supposed to be 0??\n", dwReserved);
1972 SetLastError(ERROR_INVALID_PARAMETER);
1975 return FALSE;
1979 #if 0
1981 struct DOS_FILE_LOCK {
1982 struct DOS_FILE_LOCK * next;
1983 DWORD base;
1984 DWORD len;
1985 DWORD processId;
1986 FILE_OBJECT * dos_file;
1987 /* char * unix_name;*/
1990 typedef struct DOS_FILE_LOCK DOS_FILE_LOCK;
1992 static DOS_FILE_LOCK *locks = NULL;
1993 static void DOS_RemoveFileLocks(FILE_OBJECT *file);
1996 /* Locks need to be mirrored because unix file locking is based
1997 * on the pid. Inside of wine there can be multiple WINE processes
1998 * that share the same unix pid.
1999 * Read's and writes should check these locks also - not sure
2000 * how critical that is at this point (FIXME).
2003 static BOOL DOS_AddLock(FILE_OBJECT *file, struct flock *f)
2005 DOS_FILE_LOCK *curr;
2006 DWORD processId;
2008 processId = GetCurrentProcessId();
2010 /* check if lock overlaps a current lock for the same file */
2011 #if 0
2012 for (curr = locks; curr; curr = curr->next) {
2013 if (strcmp(curr->unix_name, file->unix_name) == 0) {
2014 if ((f->l_start == curr->base) && (f->l_len == curr->len))
2015 return TRUE;/* region is identic */
2016 if ((f->l_start < (curr->base + curr->len)) &&
2017 ((f->l_start + f->l_len) > curr->base)) {
2018 /* region overlaps */
2019 return FALSE;
2023 #endif
2025 curr = HeapAlloc( GetProcessHeap(), 0, sizeof(DOS_FILE_LOCK) );
2026 curr->processId = GetCurrentProcessId();
2027 curr->base = f->l_start;
2028 curr->len = f->l_len;
2029 /* curr->unix_name = HEAP_strdupA( GetProcessHeap(), 0, file->unix_name);*/
2030 curr->next = locks;
2031 curr->dos_file = file;
2032 locks = curr;
2033 return TRUE;
2036 static void DOS_RemoveFileLocks(FILE_OBJECT *file)
2038 DWORD processId;
2039 DOS_FILE_LOCK **curr;
2040 DOS_FILE_LOCK *rem;
2042 processId = GetCurrentProcessId();
2043 curr = &locks;
2044 while (*curr) {
2045 if ((*curr)->dos_file == file) {
2046 rem = *curr;
2047 *curr = (*curr)->next;
2048 /* HeapFree( GetProcessHeap(), 0, rem->unix_name );*/
2049 HeapFree( GetProcessHeap(), 0, rem );
2051 else
2052 curr = &(*curr)->next;
2056 static BOOL DOS_RemoveLock(FILE_OBJECT *file, struct flock *f)
2058 DWORD processId;
2059 DOS_FILE_LOCK **curr;
2060 DOS_FILE_LOCK *rem;
2062 processId = GetCurrentProcessId();
2063 for (curr = &locks; *curr; curr = &(*curr)->next) {
2064 if ((*curr)->processId == processId &&
2065 (*curr)->dos_file == file &&
2066 (*curr)->base == f->l_start &&
2067 (*curr)->len == f->l_len) {
2068 /* this is the same lock */
2069 rem = *curr;
2070 *curr = (*curr)->next;
2071 /* HeapFree( GetProcessHeap(), 0, rem->unix_name );*/
2072 HeapFree( GetProcessHeap(), 0, rem );
2073 return TRUE;
2076 /* no matching lock found */
2077 return FALSE;
2081 /**************************************************************************
2082 * LockFile (KERNEL32.511)
2084 BOOL WINAPI LockFile(
2085 HFILE hFile,DWORD dwFileOffsetLow,DWORD dwFileOffsetHigh,
2086 DWORD nNumberOfBytesToLockLow,DWORD nNumberOfBytesToLockHigh )
2088 struct flock f;
2089 FILE_OBJECT *file;
2091 TRACE("handle %d offsetlow=%ld offsethigh=%ld nbyteslow=%ld nbyteshigh=%ld\n",
2092 hFile, dwFileOffsetLow, dwFileOffsetHigh,
2093 nNumberOfBytesToLockLow, nNumberOfBytesToLockHigh);
2095 if (dwFileOffsetHigh || nNumberOfBytesToLockHigh) {
2096 FIXME("Unimplemented bytes > 32bits\n");
2097 return FALSE;
2100 f.l_start = dwFileOffsetLow;
2101 f.l_len = nNumberOfBytesToLockLow;
2102 f.l_whence = SEEK_SET;
2103 f.l_pid = 0;
2104 f.l_type = F_WRLCK;
2106 if (!(file = FILE_GetFile(hFile,0,NULL))) return FALSE;
2108 /* shadow locks internally */
2109 if (!DOS_AddLock(file, &f)) {
2110 SetLastError( ERROR_LOCK_VIOLATION );
2111 return FALSE;
2114 /* FIXME: Unix locking commented out for now, doesn't work with Excel */
2115 #ifdef USE_UNIX_LOCKS
2116 if (fcntl(file->unix_handle, F_SETLK, &f) == -1) {
2117 if (errno == EACCES || errno == EAGAIN) {
2118 SetLastError( ERROR_LOCK_VIOLATION );
2120 else {
2121 FILE_SetDosError();
2123 /* remove our internal copy of the lock */
2124 DOS_RemoveLock(file, &f);
2125 return FALSE;
2127 #endif
2128 return TRUE;
2132 /**************************************************************************
2133 * UnlockFile (KERNEL32.703)
2135 BOOL WINAPI UnlockFile(
2136 HFILE hFile,DWORD dwFileOffsetLow,DWORD dwFileOffsetHigh,
2137 DWORD nNumberOfBytesToUnlockLow,DWORD nNumberOfBytesToUnlockHigh )
2139 FILE_OBJECT *file;
2140 struct flock f;
2142 TRACE("handle %d offsetlow=%ld offsethigh=%ld nbyteslow=%ld nbyteshigh=%ld\n",
2143 hFile, dwFileOffsetLow, dwFileOffsetHigh,
2144 nNumberOfBytesToUnlockLow, nNumberOfBytesToUnlockHigh);
2146 if (dwFileOffsetHigh || nNumberOfBytesToUnlockHigh) {
2147 WARN("Unimplemented bytes > 32bits\n");
2148 return FALSE;
2151 f.l_start = dwFileOffsetLow;
2152 f.l_len = nNumberOfBytesToUnlockLow;
2153 f.l_whence = SEEK_SET;
2154 f.l_pid = 0;
2155 f.l_type = F_UNLCK;
2157 if (!(file = FILE_GetFile(hFile,0,NULL))) return FALSE;
2159 DOS_RemoveLock(file, &f); /* ok if fails - may be another wine */
2161 /* FIXME: Unix locking commented out for now, doesn't work with Excel */
2162 #ifdef USE_UNIX_LOCKS
2163 if (fcntl(file->unix_handle, F_SETLK, &f) == -1) {
2164 FILE_SetDosError();
2165 return FALSE;
2167 #endif
2168 return TRUE;
2170 #endif
2172 /**************************************************************************
2173 * GetFileAttributesExA [KERNEL32.874]
2175 BOOL WINAPI GetFileAttributesExA(
2176 LPCSTR lpFileName, GET_FILEEX_INFO_LEVELS fInfoLevelId,
2177 LPVOID lpFileInformation)
2179 DOS_FULL_NAME full_name;
2180 BY_HANDLE_FILE_INFORMATION info;
2182 if (lpFileName == NULL) return FALSE;
2183 if (lpFileInformation == NULL) return FALSE;
2185 if (fInfoLevelId == GetFileExInfoStandard) {
2186 LPWIN32_FILE_ATTRIBUTE_DATA lpFad =
2187 (LPWIN32_FILE_ATTRIBUTE_DATA) lpFileInformation;
2188 if (!DOSFS_GetFullName( lpFileName, TRUE, &full_name )) return FALSE;
2189 if (!FILE_Stat( full_name.long_name, &info )) return FALSE;
2191 lpFad->dwFileAttributes = info.dwFileAttributes;
2192 lpFad->ftCreationTime = info.ftCreationTime;
2193 lpFad->ftLastAccessTime = info.ftLastAccessTime;
2194 lpFad->ftLastWriteTime = info.ftLastWriteTime;
2195 lpFad->nFileSizeHigh = info.nFileSizeHigh;
2196 lpFad->nFileSizeLow = info.nFileSizeLow;
2198 else {
2199 FIXME("invalid info level %d!\n", fInfoLevelId);
2200 return FALSE;
2203 return TRUE;
2207 /**************************************************************************
2208 * GetFileAttributesExW [KERNEL32.875]
2210 BOOL WINAPI GetFileAttributesExW(
2211 LPCWSTR lpFileName, GET_FILEEX_INFO_LEVELS fInfoLevelId,
2212 LPVOID lpFileInformation)
2214 LPSTR nameA = HEAP_strdupWtoA( GetProcessHeap(), 0, lpFileName );
2215 BOOL res =
2216 GetFileAttributesExA( nameA, fInfoLevelId, lpFileInformation);
2217 HeapFree( GetProcessHeap(), 0, nameA );
2218 return res;