Small fixes.
[wine/multimedia.git] / files / file.c
blob6a5cac09813eea028fa689eecba3b7f70c74fef4
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 <assert.h>
13 #include <ctype.h>
14 #include <errno.h>
15 #include <fcntl.h>
16 #include <stdlib.h>
17 #include <string.h>
18 #include <sys/errno.h>
19 #include <sys/types.h>
20 #include <sys/stat.h>
21 #include <sys/mman.h>
22 #include <sys/time.h>
23 #include <time.h>
24 #include <unistd.h>
25 #include <utime.h>
27 #include "windows.h"
28 #include "winerror.h"
29 #include "drive.h"
30 #include "file.h"
31 #include "global.h"
32 #include "heap.h"
33 #include "msdos.h"
34 #include "options.h"
35 #include "ldt.h"
36 #include "process.h"
37 #include "task.h"
38 #include "async.h"
39 #include "debug.h"
41 #if defined(MAP_ANONYMOUS) && !defined(MAP_ANON)
42 #define MAP_ANON MAP_ANONYMOUS
43 #endif
45 static BOOL32 FILE_Signaled(K32OBJ *ptr, DWORD tid);
46 static BOOL32 FILE_Satisfied(K32OBJ *ptr, DWORD thread_id);
47 static void FILE_AddWait(K32OBJ *ptr, DWORD tid);
48 static void FILE_RemoveWait(K32OBJ *ptr, DWORD thread_id);
49 static BOOL32 FILE_Read(K32OBJ *ptr, LPVOID lpBuffer, DWORD nNumberOfChars,
50 LPDWORD lpNumberOfChars, LPOVERLAPPED lpOverlapped);
51 static BOOL32 FILE_Write(K32OBJ *ptr, LPCVOID lpBuffer, DWORD nNumberOfChars,
52 LPDWORD lpNumberOfChars, LPOVERLAPPED lpOverlapped);
53 static void FILE_Destroy( K32OBJ *obj );
55 const K32OBJ_OPS FILE_Ops =
57 FILE_Signaled, /* signaled */
58 FILE_Satisfied, /* satisfied */
59 FILE_AddWait, /* add_wait */
60 FILE_RemoveWait, /* remove_wait */
61 FILE_Read, /* read */
62 FILE_Write, /* write */
63 FILE_Destroy /* destroy */
66 struct DOS_FILE_LOCK {
67 struct DOS_FILE_LOCK * next;
68 DWORD base;
69 DWORD len;
70 DWORD processId;
71 FILE_OBJECT * dos_file;
72 char * unix_name;
75 typedef struct DOS_FILE_LOCK DOS_FILE_LOCK;
77 static DOS_FILE_LOCK *locks = NULL;
78 static void DOS_RemoveFileLocks(FILE_OBJECT *file);
80 /***********************************************************************
81 * FILE_Alloc
83 * Allocate a file.
85 HFILE32 FILE_Alloc( FILE_OBJECT **file )
87 HFILE32 handle;
88 *file = HeapAlloc( SystemHeap, 0, sizeof(FILE_OBJECT) );
89 if (!*file)
91 DOS_ERROR( ER_TooManyOpenFiles, EC_ProgramError, SA_Abort, EL_Disk );
92 return (HFILE32)NULL;
94 (*file)->header.type = K32OBJ_FILE;
95 (*file)->header.refcount = 0;
96 (*file)->unix_handle = -1;
97 (*file)->unix_name = NULL;
98 (*file)->type = FILE_TYPE_DISK;
99 (*file)->pos = 0;
100 (*file)->mode = 0;
101 (*file)->wait_queue = NULL;
103 handle = HANDLE_Alloc( PROCESS_Current(), &(*file)->header,
104 FILE_ALL_ACCESS | GENERIC_READ |
105 GENERIC_WRITE | GENERIC_EXECUTE /*FIXME*/, TRUE, -1 );
106 /* If the allocation failed, the object is already destroyed */
107 if (handle == INVALID_HANDLE_VALUE32) *file = NULL;
108 return handle;
111 /***********************************************************************
112 * FILE_async_handler [internal]
114 static void
115 FILE_async_handler(int unixfd,void *private) {
116 FILE_OBJECT *file = (FILE_OBJECT*)private;
118 SYNC_WakeUp(&file->wait_queue,INFINITE32);
121 static BOOL32 FILE_Signaled(K32OBJ *ptr, DWORD thread_id)
123 fd_set fds,*readfds = NULL,*writefds = NULL;
124 struct timeval tv;
125 FILE_OBJECT *file = (FILE_OBJECT *)ptr;
127 FD_ZERO(&fds);
128 FD_SET(file->unix_handle,&fds);
129 if (file->mode == OF_READ) readfds = &fds;
130 if (file->mode == OF_WRITE) writefds = &fds;
131 if (file->mode == OF_READWRITE) {writefds = &fds; readfds = &fds;}
132 tv.tv_sec = 0;
133 tv.tv_usec = 0;
134 assert(readfds || writefds);
135 if (select(file->unix_handle+1,readfds,writefds,NULL,&tv)>0)
136 return TRUE; /* we triggered one fd. Whereever. */
137 return FALSE;
140 static void FILE_AddWait(K32OBJ *ptr, DWORD thread_id)
142 FILE_OBJECT *file = (FILE_OBJECT*)ptr;
143 if (!file->wait_queue)
144 ASYNC_RegisterFD(file->unix_handle,FILE_async_handler,file);
145 THREAD_AddQueue(&file->wait_queue,thread_id);
148 static void FILE_RemoveWait(K32OBJ *ptr, DWORD thread_id)
150 FILE_OBJECT *file = (FILE_OBJECT*)ptr;
151 THREAD_RemoveQueue(&file->wait_queue,thread_id);
152 if (!file->wait_queue)
153 ASYNC_UnregisterFD(file->unix_handle,FILE_async_handler);
156 static BOOL32 FILE_Satisfied(K32OBJ *ptr, DWORD thread_id)
158 return FALSE; /* not abandoned. Hmm? */
161 /* FIXME: lpOverlapped is ignored */
162 static BOOL32 FILE_Read(K32OBJ *ptr, LPVOID lpBuffer, DWORD nNumberOfChars,
163 LPDWORD lpNumberOfChars, LPOVERLAPPED lpOverlapped)
165 FILE_OBJECT *file = (FILE_OBJECT *)ptr;
166 int result;
168 TRACE(file, "%p %p %ld\n", ptr, lpBuffer,
169 nNumberOfChars);
171 if (nNumberOfChars == 0) {
172 *lpNumberOfChars = 0; /* FIXME: does this change */
173 return TRUE;
176 if ( (file->pos < 0) || /* workaround, see SetFilePointer */
177 ((result = read(file->unix_handle, lpBuffer, nNumberOfChars)) == -1) )
179 FILE_SetDosError();
180 return FALSE;
182 file->pos += result;
183 *lpNumberOfChars = result;
184 return TRUE;
188 * experimentation yields that WriteFile:
189 * o does not truncate on write of 0
190 * o always changes the *lpNumberOfChars to actual number of
191 * characters written
192 * o write of 0 nNumberOfChars returns TRUE
194 static BOOL32 FILE_Write(K32OBJ *ptr, LPCVOID lpBuffer, DWORD nNumberOfChars,
195 LPDWORD lpNumberOfChars, LPOVERLAPPED lpOverlapped)
197 FILE_OBJECT *file = (FILE_OBJECT *)ptr;
198 int result;
200 TRACE(file, "%p %p %ld\n", ptr, lpBuffer,
201 nNumberOfChars);
203 *lpNumberOfChars = 0;
206 * I assume this loop around EAGAIN is here because
207 * win32 doesn't have interrupted system calls
210 if (file->pos < 0) { /* workaround, see SetFilePointer */
211 FILE_SetDosError();
212 return FALSE;
215 for (;;)
217 result = write(file->unix_handle, lpBuffer, nNumberOfChars);
218 if (result != -1) {
219 *lpNumberOfChars = result;
220 file->pos += result;
221 return TRUE;
223 if (errno != EINTR) {
224 FILE_SetDosError();
225 return FALSE;
232 /***********************************************************************
233 * FILE_Destroy
235 * Destroy a DOS file.
237 static void FILE_Destroy( K32OBJ *ptr )
239 FILE_OBJECT *file = (FILE_OBJECT *)ptr;
240 assert( ptr->type == K32OBJ_FILE );
242 DOS_RemoveFileLocks(file);
244 if (file->unix_handle != -1) close( file->unix_handle );
245 if (file->unix_name) HeapFree( SystemHeap, 0, file->unix_name );
246 ptr->type = K32OBJ_UNKNOWN;
247 HeapFree( SystemHeap, 0, file );
251 /***********************************************************************
252 * FILE_GetFile
254 * Return the DOS file associated to a task file handle. FILE_ReleaseFile must
255 * be called to release the file.
257 FILE_OBJECT *FILE_GetFile( HFILE32 handle )
259 return (FILE_OBJECT *)HANDLE_GetObjPtr( PROCESS_Current(), handle,
260 K32OBJ_FILE, 0 /*FIXME*/, NULL );
264 /***********************************************************************
265 * FILE_ReleaseFile
267 * Release a DOS file obtained with FILE_GetFile.
269 void FILE_ReleaseFile( FILE_OBJECT *file )
271 K32OBJ_DecCount( &file->header );
275 /***********************************************************************
276 * FILE_GetUnixHandle
278 * Return the Unix handle associated to a file handle.
280 int FILE_GetUnixHandle( HFILE32 hFile )
282 FILE_OBJECT *file;
283 int ret;
285 if (!(file = FILE_GetFile( hFile ))) return -1;
286 ret = file->unix_handle;
287 FILE_ReleaseFile( file );
288 return ret;
291 /***********************************************************************
292 * FILE_UnixToDosMode
294 * PARAMS
295 * unixmode[I]
296 * RETURNS
297 * dosmode
299 static int FILE_UnixToDosMode(int unixMode)
301 int dosMode;
302 switch(unixMode & 3)
304 case O_WRONLY:
305 dosMode = OF_WRITE;
306 break;
307 case O_RDWR:
308 dosMode =OF_READWRITE;
309 break;
310 case O_RDONLY:
311 default:
312 dosMode = OF_READ;
313 break;
315 return dosMode;
318 /***********************************************************************
319 * FILE_DOSToUnixMode
321 * PARAMS
322 * dosMode[I]
323 * RETURNS
324 * unixmode
326 static int FILE_DOSToUnixMode(int dosMode)
328 int unixMode;
329 switch(dosMode & 3)
331 case OF_WRITE:
332 unixMode = O_WRONLY; break;
333 case OF_READWRITE:
334 unixMode = O_RDWR; break;
335 case OF_READ:
336 default:
337 unixMode = O_RDONLY; break;
339 return unixMode;
342 /***********************************************************************
343 * FILE_ShareDeny
345 * PARAMS
346 * oldmode[I] mode how file was first opened
347 * mode[I] mode how the file should get opened
348 * RETURNS
349 * TRUE: deny open
350 * FALSE: allow open
352 * Look what we have to do with the given SHARE modes
354 * Ralph Brown's interrupt list gives following explication, I guess
355 * the same holds for Windows, DENY ALL should be OF_SHARE_COMPAT
357 * FIXME: Validate this function
358 ========from Ralph Brown's list =========
359 (Table 0750)
360 Values of DOS file sharing behavior:
361 | Second and subsequent Opens
362 First |Compat Deny Deny Deny Deny
363 Open | All Write Read None
364 |R W RW R W RW R W RW R W RW R W RW
365 - - - - -| - - - - - - - - - - - - - - - - -
366 Compat R |Y Y Y N N N 1 N N N N N 1 N N
367 W |Y Y Y N N N N N N N N N N N N
368 RW|Y Y Y N N N N N N N N N N N N
369 - - - - -|
370 Deny R |C C C N N N N N N N N N N N N
371 All W |C C C N N N N N N N N N N N N
372 RW|C C C N N N N N N N N N N N N
373 - - - - -|
374 Deny R |2 C C N N N Y N N N N N Y N N
375 Write W |C C C N N N N N N Y N N Y N N
376 RW|C C C N N N N N N N N N Y N N
377 - - - - -|
378 Deny R |C C C N N N N Y N N N N N Y N
379 Read W |C C C N N N N N N N Y N N Y N
380 RW|C C C N N N N N N N N N N Y N
381 - - - - -|
382 Deny R |2 C C N N N Y Y Y N N N Y Y Y
383 None W |C C C N N N N N N Y Y Y Y Y Y
384 RW|C C C N N N N N N N N N Y Y Y
385 Legend: Y = open succeeds, N = open fails with error code 05h
386 C = open fails, INT 24 generated
387 1 = open succeeds if file read-only, else fails with error code
388 2 = open succeeds if file read-only, else fails with INT 24
389 ========end of description from Ralph Brown's List =====
390 For every "Y" in the table we return FALSE
391 For every "N" we set the DOS_ERROR and return TRUE
392 For all other cases we barf,set the DOS_ERROR and return TRUE
395 static BOOL32 FILE_ShareDeny( int mode, int oldmode)
397 int oldsharemode = oldmode & 0x70;
398 int sharemode = mode & 0x70;
399 int oldopenmode = oldmode & 3;
400 int openmode = mode & 3;
402 switch (oldsharemode)
404 case OF_SHARE_COMPAT:
405 if (sharemode == OF_SHARE_COMPAT) return FALSE;
406 if (openmode == OF_READ) goto test_ro_err05 ;
407 goto fail_error05;
408 case OF_SHARE_EXCLUSIVE:
409 if (sharemode == OF_SHARE_COMPAT) goto fail_int24;
410 goto fail_error05;
411 case OF_SHARE_DENY_WRITE:
412 if (openmode != OF_READ)
414 if (sharemode == OF_SHARE_COMPAT) goto fail_int24;
415 goto fail_error05;
417 switch (sharemode)
419 case OF_SHARE_COMPAT:
420 if (oldopenmode == OF_READ) goto test_ro_int24 ;
421 goto fail_int24;
422 case OF_SHARE_DENY_NONE :
423 return FALSE;
424 case OF_SHARE_DENY_WRITE :
425 if (oldopenmode == OF_READ) return FALSE;
426 case OF_SHARE_DENY_READ :
427 if (oldopenmode == OF_WRITE) return FALSE;
428 case OF_SHARE_EXCLUSIVE:
429 default:
430 goto fail_error05;
432 break;
433 case OF_SHARE_DENY_READ:
434 if (openmode != OF_WRITE)
436 if (sharemode == OF_SHARE_COMPAT) goto fail_int24;
437 goto fail_error05;
439 switch (sharemode)
441 case OF_SHARE_COMPAT:
442 goto fail_int24;
443 case OF_SHARE_DENY_NONE :
444 return FALSE;
445 case OF_SHARE_DENY_WRITE :
446 if (oldopenmode == OF_READ) return FALSE;
447 case OF_SHARE_DENY_READ :
448 if (oldopenmode == OF_WRITE) return FALSE;
449 case OF_SHARE_EXCLUSIVE:
450 default:
451 goto fail_error05;
453 break;
454 case OF_SHARE_DENY_NONE:
455 switch (sharemode)
457 case OF_SHARE_COMPAT:
458 goto fail_int24;
459 case OF_SHARE_DENY_NONE :
460 return FALSE;
461 case OF_SHARE_DENY_WRITE :
462 if (oldopenmode == OF_READ) return FALSE;
463 case OF_SHARE_DENY_READ :
464 if (oldopenmode == OF_WRITE) return FALSE;
465 case OF_SHARE_EXCLUSIVE:
466 default:
467 goto fail_error05;
469 default:
470 ERR(file,"unknown mode\n");
472 ERR(file,"shouldn't happen\n");
473 ERR(file,"Please report to bon@elektron.ikp.physik.tu-darmstadt.de\n");
474 return TRUE;
476 test_ro_int24:
477 if (oldmode == OF_READ)
478 return FALSE;
479 /* Fall through */
480 fail_int24:
481 FIXME(file,"generate INT24 missing\n");
482 /* Is this the right error? */
483 DOS_ERROR( ER_AccessDenied, EC_AccessDenied, SA_Abort, EL_Disk );
484 return TRUE;
486 test_ro_err05:
487 if (oldmode == OF_READ)
488 return FALSE;
489 /* fall through */
490 fail_error05:
491 TRACE(file,"Access Denied, oldmode 0x%02x mode 0x%02x\n",oldmode,mode);
492 DOS_ERROR( ER_AccessDenied, EC_AccessDenied, SA_Abort, EL_Disk );
493 return TRUE;
498 /***********************************************************************
501 * Look if the File is in Use For the OF_SHARE_XXX options
503 * PARAMS
504 * name [I]: full unix name of the file that should be opened
505 * mode [O]: mode how the file was first opened
506 * RETURNS
507 * TRUE if the file was opened before
508 * FALSE if we open the file exclusive for this process
510 * Scope of the files we look for is only the current pdb
511 * Could we use /proc/self/? on Linux for this?
512 * Should we use flock? Should we create another structure?
513 * Searching through all files seem quite expensive for me, but
514 * I don't see any other way.
516 * FIXME: Extend scope to the whole Wine process
519 static BOOL32 FILE_InUse(char * name, int * mode)
521 FILE_OBJECT *file;
522 int i;
523 HGLOBAL16 hPDB = GetCurrentPDB();
524 PDB *pdb = (PDB *)GlobalLock16( hPDB );
526 if (!pdb) return 0;
527 for (i=0;i<pdb->nbFiles;i++)
529 file =FILE_GetFile( (HFILE32) i);
530 if(file)
532 if(file->unix_name)
534 TRACE(file,"got %s at %d\n",file->unix_name,i);
535 if(!lstrcmp32A(file->unix_name,name))
537 *mode = file->mode;
538 FILE_ReleaseFile(file);
539 return TRUE;
542 FILE_ReleaseFile(file);
545 return FALSE;
548 /***********************************************************************
549 * FILE_SetDosError
551 * Set the DOS error code from errno.
553 void FILE_SetDosError(void)
555 int save_errno = errno; /* errno gets overwritten by printf */
557 TRACE(file, "errno = %d %s\n", errno, strerror(errno));
558 switch (save_errno)
560 case EAGAIN:
561 DOS_ERROR( ER_ShareViolation, EC_Temporary, SA_Retry, EL_Disk );
562 break;
563 case EBADF:
564 DOS_ERROR( ER_InvalidHandle, EC_ProgramError, SA_Abort, EL_Disk );
565 break;
566 case ENOSPC:
567 DOS_ERROR( ER_DiskFull, EC_MediaError, SA_Abort, EL_Disk );
568 break;
569 case EACCES:
570 case EPERM:
571 case EROFS:
572 DOS_ERROR( ER_AccessDenied, EC_AccessDenied, SA_Abort, EL_Disk );
573 break;
574 case EBUSY:
575 DOS_ERROR( ER_LockViolation, EC_AccessDenied, SA_Abort, EL_Disk );
576 break;
577 case ENOENT:
578 DOS_ERROR( ER_FileNotFound, EC_NotFound, SA_Abort, EL_Disk );
579 break;
580 case EISDIR:
581 DOS_ERROR( ER_CanNotMakeDir, EC_AccessDenied, SA_Abort, EL_Unknown );
582 break;
583 case ENFILE:
584 case EMFILE:
585 DOS_ERROR( ER_NoMoreFiles, EC_MediaError, SA_Abort, EL_Unknown );
586 break;
587 case EEXIST:
588 DOS_ERROR( ER_FileExists, EC_Exists, SA_Abort, EL_Disk );
589 break;
590 case EINVAL:
591 case ESPIPE:
592 DOS_ERROR( ER_SeekError, EC_NotFound, SA_Ignore, EL_Disk );
593 break;
594 case ENOTEMPTY:
595 DOS_ERROR( ERROR_DIR_NOT_EMPTY, EC_Exists, SA_Ignore, EL_Disk );
596 break;
597 default:
598 perror( "int21: unknown errno" );
599 DOS_ERROR( ER_GeneralFailure, EC_SystemFailure, SA_Abort, EL_Unknown );
600 break;
602 errno = save_errno;
606 /***********************************************************************
607 * FILE_DupUnixHandle
609 * Duplicate a Unix handle into a task handle.
611 HFILE32 FILE_DupUnixHandle( int fd )
613 HFILE32 handle;
614 FILE_OBJECT *file;
616 if ((handle = FILE_Alloc( &file )) != INVALID_HANDLE_VALUE32)
618 if ((file->unix_handle = dup(fd)) == -1)
620 FILE_SetDosError();
621 CloseHandle( handle );
622 return INVALID_HANDLE_VALUE32;
625 return handle;
629 /***********************************************************************
630 * FILE_OpenUnixFile
632 HFILE32 FILE_OpenUnixFile( const char *name, int mode )
634 HFILE32 handle;
635 FILE_OBJECT *file;
636 struct stat st;
638 if ((handle = FILE_Alloc( &file )) == INVALID_HANDLE_VALUE32)
639 return INVALID_HANDLE_VALUE32;
641 if ((file->unix_handle = open( name, mode, 0666 )) == -1)
643 if (!Options.failReadOnly && (mode == O_RDWR))
644 file->unix_handle = open( name, O_RDONLY );
646 if ((file->unix_handle == -1) || (fstat( file->unix_handle, &st ) == -1))
648 FILE_SetDosError();
649 CloseHandle( handle );
650 return INVALID_HANDLE_VALUE32;
652 if (S_ISDIR(st.st_mode))
654 DOS_ERROR( ER_AccessDenied, EC_AccessDenied, SA_Abort, EL_Disk );
655 CloseHandle( handle );
656 return INVALID_HANDLE_VALUE32;
659 /* File opened OK, now fill the FILE_OBJECT */
661 file->unix_name = HEAP_strdupA( SystemHeap, 0, name );
662 return handle;
666 /***********************************************************************
667 * FILE_Open
669 * path[I] name of file to open
670 * mode[I] mode how to open, in unix notation
671 * shareMode[I] the sharing mode in the win OpenFile notation
674 HFILE32 FILE_Open( LPCSTR path, INT32 mode, INT32 shareMode )
676 DOS_FULL_NAME full_name;
677 const char *unixName;
678 int oldMode, dosMode; /* FIXME: Do we really need unixmode as argument for
679 FILE_Open */
680 FILE_OBJECT *file;
681 HFILE32 hFileRet;
682 BOOL32 fileInUse = FALSE;
684 TRACE(file, "'%s' %04x\n", path, mode );
686 if (!path) return HFILE_ERROR32;
688 if (DOSFS_GetDevice( path ))
690 HFILE32 ret;
692 TRACE(file, "opening device '%s'\n", path );
694 if (HFILE_ERROR32!=(ret=DOSFS_OpenDevice( path, mode )))
695 return ret;
697 /* Do not silence this please. It is a critical error. -MM */
698 ERR(file, "Couldn't open device '%s'!\n",path);
699 DOS_ERROR( ER_FileNotFound, EC_NotFound, SA_Abort, EL_Disk );
700 return HFILE_ERROR32;
703 else /* check for filename, don't check for last entry if creating */
705 if (!DOSFS_GetFullName( path, !(mode & O_CREAT), &full_name ))
706 return HFILE_ERROR32;
707 unixName = full_name.long_name;
710 dosMode = FILE_UnixToDosMode(mode)| shareMode;
711 fileInUse = FILE_InUse(full_name.long_name,&oldMode);
712 if(fileInUse)
714 TRACE(file, "found another instance with mode 0x%02x\n",oldMode&0x70);
715 if (FILE_ShareDeny(dosMode,oldMode)) return HFILE_ERROR32;
717 hFileRet = FILE_OpenUnixFile( unixName, mode );
718 /* we need to save the mode, but only if it is not in use yet*/
719 if ((hFileRet) && (!fileInUse) && ((file =FILE_GetFile(hFileRet))))
721 file->mode=dosMode;
722 FILE_ReleaseFile(file);
724 return hFileRet;
729 /***********************************************************************
730 * FILE_Create
732 static HFILE32 FILE_Create( LPCSTR path, int mode, int unique )
734 HFILE32 handle;
735 FILE_OBJECT *file;
736 DOS_FULL_NAME full_name;
737 BOOL32 fileInUse = FALSE;
738 int oldMode,dosMode; /* FIXME: Do we really need unixmode as argument for
739 FILE_Create */;
741 TRACE(file, "'%s' %04x %d\n", path, mode, unique );
743 if (!path) return INVALID_HANDLE_VALUE32;
745 if (DOSFS_GetDevice( path ))
747 WARN(file, "cannot create DOS device '%s'!\n", path);
748 DOS_ERROR( ER_AccessDenied, EC_NotFound, SA_Abort, EL_Disk );
749 return INVALID_HANDLE_VALUE32;
752 if ((handle = FILE_Alloc( &file )) == INVALID_HANDLE_VALUE32)
753 return INVALID_HANDLE_VALUE32;
755 if (!DOSFS_GetFullName( path, FALSE, &full_name ))
757 CloseHandle( handle );
758 return INVALID_HANDLE_VALUE32;
761 dosMode = FILE_UnixToDosMode(mode);
762 fileInUse = FILE_InUse(full_name.long_name,&oldMode);
763 if(fileInUse)
765 TRACE(file, "found another instance with mode 0x%02x\n",oldMode&0x70);
766 if (FILE_ShareDeny(dosMode,oldMode)) return INVALID_HANDLE_VALUE32;
769 if ((file->unix_handle = open( full_name.long_name,
770 O_CREAT | O_TRUNC | O_RDWR | (unique ? O_EXCL : 0),
771 mode )) == -1)
773 FILE_SetDosError();
774 CloseHandle( handle );
775 return INVALID_HANDLE_VALUE32;
778 /* File created OK, now fill the FILE_OBJECT */
780 file->unix_name = HEAP_strdupA( SystemHeap, 0, full_name.long_name );
781 file->mode = dosMode;
782 return handle;
786 /***********************************************************************
787 * FILE_FillInfo
789 * Fill a file information from a struct stat.
791 static void FILE_FillInfo( struct stat *st, BY_HANDLE_FILE_INFORMATION *info )
793 if (S_ISDIR(st->st_mode))
794 info->dwFileAttributes = FILE_ATTRIBUTE_DIRECTORY;
795 else
796 info->dwFileAttributes = FILE_ATTRIBUTE_ARCHIVE;
797 if (!(st->st_mode & S_IWUSR))
798 info->dwFileAttributes |= FILE_ATTRIBUTE_READONLY;
800 DOSFS_UnixTimeToFileTime( st->st_mtime, &info->ftCreationTime, 0 );
801 DOSFS_UnixTimeToFileTime( st->st_mtime, &info->ftLastWriteTime, 0 );
802 DOSFS_UnixTimeToFileTime( st->st_atime, &info->ftLastAccessTime, 0 );
804 info->dwVolumeSerialNumber = 0; /* FIXME */
805 info->nFileSizeHigh = 0;
806 info->nFileSizeLow = S_ISDIR(st->st_mode) ? 0 : st->st_size;
807 info->nNumberOfLinks = st->st_nlink;
808 info->nFileIndexHigh = 0;
809 info->nFileIndexLow = st->st_ino;
813 /***********************************************************************
814 * FILE_Stat
816 * Stat a Unix path name. Return TRUE if OK.
818 BOOL32 FILE_Stat( LPCSTR unixName, BY_HANDLE_FILE_INFORMATION *info )
820 struct stat st;
822 if (!unixName || !info) return FALSE;
824 if (stat( unixName, &st ) == -1)
826 FILE_SetDosError();
827 return FALSE;
829 FILE_FillInfo( &st, info );
830 return TRUE;
834 /***********************************************************************
835 * GetFileInformationByHandle (KERNEL32.219)
837 DWORD WINAPI GetFileInformationByHandle( HFILE32 hFile,
838 BY_HANDLE_FILE_INFORMATION *info )
840 FILE_OBJECT *file;
841 DWORD ret = 0;
842 struct stat st;
844 if (!info) return 0;
846 if (!(file = FILE_GetFile( hFile ))) return 0;
847 if (fstat( file->unix_handle, &st ) == -1) FILE_SetDosError();
848 else
850 FILE_FillInfo( &st, info );
851 ret = 1;
853 FILE_ReleaseFile( file );
854 return ret;
858 /**************************************************************************
859 * GetFileAttributes16 (KERNEL.420)
861 DWORD WINAPI GetFileAttributes16( LPCSTR name )
863 return GetFileAttributes32A( name );
867 /**************************************************************************
868 * GetFileAttributes32A (KERNEL32.217)
870 DWORD WINAPI GetFileAttributes32A( LPCSTR name )
872 DOS_FULL_NAME full_name;
873 BY_HANDLE_FILE_INFORMATION info;
875 if (name == NULL || *name=='\0') return -1;
877 if (!DOSFS_GetFullName( name, TRUE, &full_name )) return -1;
878 if (!FILE_Stat( full_name.long_name, &info )) return -1;
879 return info.dwFileAttributes;
883 /**************************************************************************
884 * GetFileAttributes32W (KERNEL32.218)
886 DWORD WINAPI GetFileAttributes32W( LPCWSTR name )
888 LPSTR nameA = HEAP_strdupWtoA( GetProcessHeap(), 0, name );
889 DWORD res = GetFileAttributes32A( nameA );
890 HeapFree( GetProcessHeap(), 0, nameA );
891 return res;
895 /***********************************************************************
896 * GetFileSize (KERNEL32.220)
898 DWORD WINAPI GetFileSize( HFILE32 hFile, LPDWORD filesizehigh )
900 BY_HANDLE_FILE_INFORMATION info;
901 if (!GetFileInformationByHandle( hFile, &info )) return 0;
902 if (filesizehigh) *filesizehigh = info.nFileSizeHigh;
903 return info.nFileSizeLow;
907 /***********************************************************************
908 * GetFileTime (KERNEL32.221)
910 BOOL32 WINAPI GetFileTime( HFILE32 hFile, FILETIME *lpCreationTime,
911 FILETIME *lpLastAccessTime,
912 FILETIME *lpLastWriteTime )
914 BY_HANDLE_FILE_INFORMATION info;
915 if (!GetFileInformationByHandle( hFile, &info )) return FALSE;
916 if (lpCreationTime) *lpCreationTime = info.ftCreationTime;
917 if (lpLastAccessTime) *lpLastAccessTime = info.ftLastAccessTime;
918 if (lpLastWriteTime) *lpLastWriteTime = info.ftLastWriteTime;
919 return TRUE;
922 /***********************************************************************
923 * CompareFileTime (KERNEL32.28)
925 INT32 WINAPI CompareFileTime( LPFILETIME x, LPFILETIME y )
927 if (!x || !y) return -1;
929 if (x->dwHighDateTime > y->dwHighDateTime)
930 return 1;
931 if (x->dwHighDateTime < y->dwHighDateTime)
932 return -1;
933 if (x->dwLowDateTime > y->dwLowDateTime)
934 return 1;
935 if (x->dwLowDateTime < y->dwLowDateTime)
936 return -1;
937 return 0;
940 /***********************************************************************
941 * FILE_Dup
943 * dup() function for DOS handles.
945 HFILE32 FILE_Dup( HFILE32 hFile )
947 HFILE32 handle;
949 TRACE(file, "FILE_Dup for handle %d\n", hFile );
950 if (!DuplicateHandle( GetCurrentProcess(), hFile, GetCurrentProcess(),
951 &handle, FILE_ALL_ACCESS /* FIXME */, FALSE, 0 ))
952 handle = HFILE_ERROR32;
953 TRACE(file, "FILE_Dup return handle %d\n", handle );
954 return handle;
958 /***********************************************************************
959 * FILE_Dup2
961 * dup2() function for DOS handles.
963 HFILE32 FILE_Dup2( HFILE32 hFile1, HFILE32 hFile2 )
965 FILE_OBJECT *file;
967 TRACE(file, "FILE_Dup2 for handle %d\n", hFile1 );
968 /* FIXME: should use DuplicateHandle */
969 if (!(file = FILE_GetFile( hFile1 ))) return HFILE_ERROR32;
970 if (!HANDLE_SetObjPtr( PROCESS_Current(), hFile2, &file->header, 0 ))
971 hFile2 = HFILE_ERROR32;
972 FILE_ReleaseFile( file );
973 return hFile2;
977 /***********************************************************************
978 * GetTempFileName16 (KERNEL.97)
980 UINT16 WINAPI GetTempFileName16( BYTE drive, LPCSTR prefix, UINT16 unique,
981 LPSTR buffer )
983 char temppath[144];
985 if (!(drive & ~TF_FORCEDRIVE)) /* drive 0 means current default drive */
986 drive |= DRIVE_GetCurrentDrive() + 'A';
988 if ((drive & TF_FORCEDRIVE) &&
989 !DRIVE_IsValid( toupper(drive & ~TF_FORCEDRIVE) - 'A' ))
991 drive &= ~TF_FORCEDRIVE;
992 WARN(file, "invalid drive %d specified\n", drive );
995 if (drive & TF_FORCEDRIVE)
996 sprintf(temppath,"%c:", drive & ~TF_FORCEDRIVE );
997 else
998 GetTempPath32A( 132, temppath );
999 return (UINT16)GetTempFileName32A( temppath, prefix, unique, buffer );
1003 /***********************************************************************
1004 * GetTempFileName32A (KERNEL32.290)
1006 UINT32 WINAPI GetTempFileName32A( LPCSTR path, LPCSTR prefix, UINT32 unique,
1007 LPSTR buffer)
1009 static UINT32 unique_temp;
1010 DOS_FULL_NAME full_name;
1011 int i;
1012 LPSTR p;
1013 UINT32 num;
1015 if ( !path || !prefix || !buffer ) return 0;
1017 if (!unique_temp) unique_temp = time(NULL) & 0xffff;
1018 num = unique ? (unique & 0xffff) : (unique_temp++ & 0xffff);
1020 strcpy( buffer, path );
1021 p = buffer + strlen(buffer);
1023 /* add a \, if there isn't one and path is more than just the drive letter ... */
1024 if ( !((strlen(buffer) == 2) && (buffer[1] == ':'))
1025 && ((p == buffer) || (p[-1] != '\\'))) *p++ = '\\';
1027 *p++ = '~';
1028 for (i = 3; (i > 0) && (*prefix); i--) *p++ = *prefix++;
1029 sprintf( p, "%04x.tmp", num );
1031 /* Now try to create it */
1033 if (!unique)
1037 HFILE32 handle = FILE_Create( buffer, 0666, TRUE );
1038 if (handle != INVALID_HANDLE_VALUE32)
1039 { /* We created it */
1040 TRACE(file, "created %s\n",
1041 buffer);
1042 CloseHandle( handle );
1043 break;
1045 if (DOS_ExtendedError != ER_FileExists)
1046 break; /* No need to go on */
1047 num++;
1048 sprintf( p, "%04x.tmp", num );
1049 } while (num != (unique & 0xffff));
1052 /* Get the full path name */
1054 if (DOSFS_GetFullName( buffer, FALSE, &full_name ))
1056 /* Check if we have write access in the directory */
1057 if ((p = strrchr( full_name.long_name, '/' ))) *p = '\0';
1058 if (access( full_name.long_name, W_OK ) == -1)
1059 WARN(file, "returns '%s', which doesn't seem to be writeable.\n",
1060 buffer);
1062 TRACE(file, "returning %s\n", buffer );
1063 return unique ? unique : num;
1067 /***********************************************************************
1068 * GetTempFileName32W (KERNEL32.291)
1070 UINT32 WINAPI GetTempFileName32W( LPCWSTR path, LPCWSTR prefix, UINT32 unique,
1071 LPWSTR buffer )
1073 LPSTR patha,prefixa;
1074 char buffera[144];
1075 UINT32 ret;
1077 if (!path) return 0;
1078 patha = HEAP_strdupWtoA( GetProcessHeap(), 0, path );
1079 prefixa = HEAP_strdupWtoA( GetProcessHeap(), 0, prefix );
1080 ret = GetTempFileName32A( patha, prefixa, unique, buffera );
1081 lstrcpyAtoW( buffer, buffera );
1082 HeapFree( GetProcessHeap(), 0, patha );
1083 HeapFree( GetProcessHeap(), 0, prefixa );
1084 return ret;
1088 /***********************************************************************
1089 * FILE_DoOpenFile
1091 * Implementation of OpenFile16() and OpenFile32().
1093 static HFILE32 FILE_DoOpenFile( LPCSTR name, OFSTRUCT *ofs, UINT32 mode,
1094 BOOL32 win32 )
1096 HFILE32 hFileRet;
1097 FILETIME filetime;
1098 WORD filedatetime[2];
1099 DOS_FULL_NAME full_name;
1100 char *p;
1101 int unixMode, oldMode;
1102 FILE_OBJECT *file;
1103 BOOL32 fileInUse = FALSE;
1105 if (!ofs) return HFILE_ERROR32;
1108 ofs->cBytes = sizeof(OFSTRUCT);
1109 ofs->nErrCode = 0;
1110 if (mode & OF_REOPEN) name = ofs->szPathName;
1112 if (!name) {
1113 ERR(file, "called with `name' set to NULL ! Please debug.\n");
1114 return HFILE_ERROR32;
1117 TRACE(file, "%s %04x\n", name, mode );
1119 /* the watcom 10.6 IDE relies on a valid path returned in ofs->szPathName
1120 Are there any cases where getting the path here is wrong?
1121 Uwe Bonnes 1997 Apr 2 */
1122 if (!GetFullPathName32A( name, sizeof(ofs->szPathName),
1123 ofs->szPathName, NULL )) goto error;
1125 /* OF_PARSE simply fills the structure */
1127 if (mode & OF_PARSE)
1129 ofs->fFixedDisk = (GetDriveType16( ofs->szPathName[0]-'A' )
1130 != DRIVE_REMOVABLE);
1131 TRACE(file, "(%s): OF_PARSE, res = '%s'\n",
1132 name, ofs->szPathName );
1133 return 0;
1136 /* OF_CREATE is completely different from all other options, so
1137 handle it first */
1139 if (mode & OF_CREATE)
1141 if ((hFileRet = FILE_Create(name,0666,FALSE))== INVALID_HANDLE_VALUE32)
1142 goto error;
1143 goto success;
1146 /* If OF_SEARCH is set, ignore the given path */
1148 if ((mode & OF_SEARCH) && !(mode & OF_REOPEN))
1150 /* First try the file name as is */
1151 if (DOSFS_GetFullName( name, TRUE, &full_name )) goto found;
1152 /* Now remove the path */
1153 if (name[0] && (name[1] == ':')) name += 2;
1154 if ((p = strrchr( name, '\\' ))) name = p + 1;
1155 if ((p = strrchr( name, '/' ))) name = p + 1;
1156 if (!name[0]) goto not_found;
1159 /* Now look for the file */
1161 if (!DIR_SearchPath( NULL, name, NULL, &full_name, win32 )) goto not_found;
1163 found:
1164 TRACE(file, "found %s = %s\n",
1165 full_name.long_name, full_name.short_name );
1166 lstrcpyn32A( ofs->szPathName, full_name.short_name,
1167 sizeof(ofs->szPathName) );
1169 fileInUse = FILE_InUse(full_name.long_name,&oldMode);
1170 if(fileInUse)
1172 TRACE(file, "found another instance with mode 0x%02x\n",oldMode&0x70);
1173 if (FILE_ShareDeny(mode,oldMode)) return HFILE_ERROR32;
1176 if (mode & OF_SHARE_EXCLUSIVE)
1177 /* Some InstallShield version uses OF_SHARE_EXCLUSIVE
1178 on the file <tempdir>/_ins0432._mp to determine how
1179 far installation has proceeded.
1180 _ins0432._mp is an executable and while running the
1181 application expects the open with OF_SHARE_ to fail*/
1182 /* Probable FIXME:
1183 As our loader closes the files after loading the executable,
1184 we can't find the running executable with FILE_InUse.
1185 Perhaps the loader should keep the file open.
1186 Recheck against how Win handles that case */
1188 char *last = strrchr(full_name.long_name,'/');
1189 if (!last)
1190 last = full_name.long_name - 1;
1191 if (GetModuleHandle16(last+1))
1193 TRACE(file,"Denying shared open for %s\n",full_name.long_name);
1194 return HFILE_ERROR32;
1198 if (mode & OF_DELETE)
1200 if (unlink( full_name.long_name ) == -1) goto not_found;
1201 TRACE(file, "(%s): OF_DELETE return = OK\n", name);
1202 return 1;
1205 unixMode=FILE_DOSToUnixMode(mode);
1207 hFileRet = FILE_OpenUnixFile( full_name.long_name, unixMode );
1208 if (hFileRet == HFILE_ERROR32) goto not_found;
1209 /* we need to save the mode, but only if it is not in use yet*/
1210 if( (!fileInUse) &&(file =FILE_GetFile(hFileRet)))
1212 file->mode=mode;
1213 FILE_ReleaseFile(file);
1216 GetFileTime( hFileRet, NULL, NULL, &filetime );
1217 FileTimeToDosDateTime( &filetime, &filedatetime[0], &filedatetime[1] );
1218 if ((mode & OF_VERIFY) && (mode & OF_REOPEN))
1220 if (memcmp( ofs->reserved, filedatetime, sizeof(ofs->reserved) ))
1222 CloseHandle( hFileRet );
1223 WARN(file, "(%s): OF_VERIFY failed\n", name );
1224 /* FIXME: what error here? */
1225 DOS_ERROR( ER_FileNotFound, EC_NotFound, SA_Abort, EL_Disk );
1226 goto error;
1229 memcpy( ofs->reserved, filedatetime, sizeof(ofs->reserved) );
1231 success: /* We get here if the open was successful */
1232 TRACE(file, "(%s): OK, return = %d\n", name, hFileRet );
1233 if (mode & OF_EXIST) /* Return the handle, but close it first */
1234 CloseHandle( hFileRet );
1235 return hFileRet;
1237 not_found: /* We get here if the file does not exist */
1238 WARN(file, "'%s' not found\n", name );
1239 DOS_ERROR( ER_FileNotFound, EC_NotFound, SA_Abort, EL_Disk );
1240 /* fall through */
1242 error: /* We get here if there was an error opening the file */
1243 ofs->nErrCode = DOS_ExtendedError;
1244 WARN(file, "(%s): return = HFILE_ERROR error= %d\n",
1245 name,ofs->nErrCode );
1246 return HFILE_ERROR32;
1250 /***********************************************************************
1251 * OpenFile16 (KERNEL.74)
1253 HFILE16 WINAPI OpenFile16( LPCSTR name, OFSTRUCT *ofs, UINT16 mode )
1255 TRACE(file,"OpenFile16(%s,%i)\n", name, mode);
1256 return HFILE32_TO_HFILE16(FILE_DoOpenFile( name, ofs, mode, FALSE ));
1260 /***********************************************************************
1261 * OpenFile32 (KERNEL32.396)
1263 HFILE32 WINAPI OpenFile32( LPCSTR name, OFSTRUCT *ofs, UINT32 mode )
1265 return FILE_DoOpenFile( name, ofs, mode, TRUE );
1269 /***********************************************************************
1270 * _lclose16 (KERNEL.81)
1272 HFILE16 WINAPI _lclose16( HFILE16 hFile )
1274 TRACE(file, "handle %d\n", hFile );
1275 return CloseHandle( HFILE16_TO_HFILE32( hFile ) ) ? 0 : HFILE_ERROR16;
1279 /***********************************************************************
1280 * _lclose32 (KERNEL32.592)
1282 HFILE32 WINAPI _lclose32( HFILE32 hFile )
1284 TRACE(file, "handle %d\n", hFile );
1285 return CloseHandle( hFile ) ? 0 : HFILE_ERROR32;
1289 /***********************************************************************
1290 * WIN16_hread
1292 LONG WINAPI WIN16_hread( HFILE16 hFile, SEGPTR buffer, LONG count )
1294 LONG maxlen;
1296 TRACE(file, "%d %08lx %ld\n",
1297 hFile, (DWORD)buffer, count );
1299 /* Some programs pass a count larger than the allocated buffer */
1300 maxlen = GetSelectorLimit( SELECTOROF(buffer) ) - OFFSETOF(buffer) + 1;
1301 if (count > maxlen) count = maxlen;
1302 return _lread32(HFILE16_TO_HFILE32(hFile), PTR_SEG_TO_LIN(buffer), count );
1306 /***********************************************************************
1307 * WIN16_lread
1309 UINT16 WINAPI WIN16_lread( HFILE16 hFile, SEGPTR buffer, UINT16 count )
1311 return (UINT16)WIN16_hread( hFile, buffer, (LONG)count );
1315 /***********************************************************************
1316 * _lread32 (KERNEL32.596)
1318 UINT32 WINAPI _lread32( HFILE32 handle, LPVOID buffer, UINT32 count )
1320 K32OBJ *ptr;
1321 DWORD numWritten;
1322 BOOL32 result = FALSE;
1324 TRACE( file, "%d %p %d\n", handle, buffer, count);
1325 if (!(ptr = HANDLE_GetObjPtr( PROCESS_Current(), handle,
1326 K32OBJ_UNKNOWN, 0, NULL))) return -1;
1327 if (K32OBJ_OPS(ptr)->read)
1328 result = K32OBJ_OPS(ptr)->read(ptr, buffer, count, &numWritten, NULL);
1329 K32OBJ_DecCount( ptr );
1330 if (!result) return -1;
1331 return (UINT32)numWritten;
1335 /***********************************************************************
1336 * _lread16 (KERNEL.82)
1338 UINT16 WINAPI _lread16( HFILE16 hFile, LPVOID buffer, UINT16 count )
1340 return (UINT16)_lread32(HFILE16_TO_HFILE32(hFile), buffer, (LONG)count );
1344 /***********************************************************************
1345 * _lcreat16 (KERNEL.83)
1347 HFILE16 WINAPI _lcreat16( LPCSTR path, INT16 attr )
1349 int mode = (attr & 1) ? 0444 : 0666;
1350 TRACE(file, "%s %02x\n", path, attr );
1351 return (HFILE16) HFILE32_TO_HFILE16(FILE_Create( path, mode, FALSE ));
1355 /***********************************************************************
1356 * _lcreat32 (KERNEL32.593)
1358 HFILE32 WINAPI _lcreat32( LPCSTR path, INT32 attr )
1360 int mode = (attr & 1) ? 0444 : 0666;
1361 TRACE(file, "%s %02x\n", path, attr );
1362 return FILE_Create( path, mode, FALSE );
1366 /***********************************************************************
1367 * _lcreat_uniq (Not a Windows API)
1369 HFILE32 _lcreat_uniq( LPCSTR path, INT32 attr )
1371 int mode = (attr & 1) ? 0444 : 0666;
1372 TRACE(file, "%s %02x\n", path, attr );
1373 return FILE_Create( path, mode, TRUE );
1377 /***********************************************************************
1378 * SetFilePointer (KERNEL32.492)
1380 DWORD WINAPI SetFilePointer( HFILE32 hFile, LONG distance, LONG *highword,
1381 DWORD method )
1383 FILE_OBJECT *file;
1384 DWORD result = 0xffffffff;
1386 if (highword && *highword)
1388 FIXME(file, "64-bit offsets not supported yet\n");
1389 SetLastError( ERROR_INVALID_PARAMETER );
1390 return 0xffffffff;
1392 TRACE(file, "handle %d offset %ld origin %ld\n",
1393 hFile, distance, method );
1395 if (!(file = FILE_GetFile( hFile ))) return 0xffffffff;
1398 /* the pointer may be positioned before the start of the file;
1399 no error is returned in that case,
1400 but subsequent attempts at I/O will produce errors.
1401 This is not allowed with Unix lseek(),
1402 so we'll need some emulation here */
1403 switch(method)
1405 case FILE_CURRENT:
1406 distance += file->pos; /* fall through */
1407 case FILE_BEGIN:
1408 if ((result = lseek(file->unix_handle, distance, SEEK_SET)) == -1)
1410 if ((INT32)distance < 0)
1411 file->pos = result = distance;
1413 else
1414 file->pos = result;
1415 break;
1416 case FILE_END:
1417 if ((result = lseek(file->unix_handle, distance, SEEK_END)) == -1)
1419 if ((INT32)distance < 0)
1421 /* get EOF */
1422 result = lseek(file->unix_handle, 0, SEEK_END);
1424 /* return to the old pos, as the first lseek failed */
1425 lseek(file->unix_handle, file->pos, SEEK_END);
1427 file->pos = (result += distance);
1429 else
1430 ERR(file, "lseek: unknown error. Please report.\n");
1432 else file->pos = result;
1433 break;
1434 default:
1435 ERR(file, "Unknown origin %ld !\n", method);
1438 if (result == -1)
1439 FILE_SetDosError();
1441 FILE_ReleaseFile( file );
1442 return result;
1446 /***********************************************************************
1447 * _llseek16 (KERNEL.84)
1449 LONG WINAPI _llseek16( HFILE16 hFile, LONG lOffset, INT16 nOrigin )
1451 return SetFilePointer( HFILE16_TO_HFILE32(hFile), lOffset, NULL, nOrigin );
1455 /***********************************************************************
1456 * _llseek32 (KERNEL32.594)
1458 LONG WINAPI _llseek32( HFILE32 hFile, LONG lOffset, INT32 nOrigin )
1460 return SetFilePointer( hFile, lOffset, NULL, nOrigin );
1464 /***********************************************************************
1465 * _lopen16 (KERNEL.85)
1467 HFILE16 WINAPI _lopen16( LPCSTR path, INT16 mode )
1469 return HFILE32_TO_HFILE16(_lopen32( path, mode ));
1473 /***********************************************************************
1474 * _lopen32 (KERNEL32.595)
1476 HFILE32 WINAPI _lopen32( LPCSTR path, INT32 mode )
1478 INT32 unixMode;
1480 TRACE(file, "('%s',%04x)\n", path, mode );
1482 unixMode= FILE_DOSToUnixMode(mode);
1483 return FILE_Open( path, unixMode , (mode & 0x70));
1487 /***********************************************************************
1488 * _lwrite16 (KERNEL.86)
1490 UINT16 WINAPI _lwrite16( HFILE16 hFile, LPCSTR buffer, UINT16 count )
1492 return (UINT16)_hwrite32( HFILE16_TO_HFILE32(hFile), buffer, (LONG)count );
1495 /***********************************************************************
1496 * _lwrite32 (KERNEL.86)
1498 UINT32 WINAPI _lwrite32( HFILE32 hFile, LPCSTR buffer, UINT32 count )
1500 return (UINT32)_hwrite32( hFile, buffer, (LONG)count );
1504 /***********************************************************************
1505 * _hread16 (KERNEL.349)
1507 LONG WINAPI _hread16( HFILE16 hFile, LPVOID buffer, LONG count)
1509 return _lread32( HFILE16_TO_HFILE32(hFile), buffer, count );
1513 /***********************************************************************
1514 * _hread32 (KERNEL32.590)
1516 LONG WINAPI _hread32( HFILE32 hFile, LPVOID buffer, LONG count)
1518 return _lread32( hFile, buffer, count );
1522 /***********************************************************************
1523 * _hwrite16 (KERNEL.350)
1525 LONG WINAPI _hwrite16( HFILE16 hFile, LPCSTR buffer, LONG count )
1527 return _hwrite32( HFILE16_TO_HFILE32(hFile), buffer, count );
1531 /***********************************************************************
1532 * _hwrite32 (KERNEL32.591)
1534 * experimenation yields that _lwrite:
1535 * o truncates the file at the current position with
1536 * a 0 len write
1537 * o returns 0 on a 0 length write
1538 * o works with console handles
1541 LONG WINAPI _hwrite32( HFILE32 handle, LPCSTR buffer, LONG count )
1543 K32OBJ *ioptr;
1544 DWORD result;
1545 BOOL32 status = FALSE;
1547 TRACE(file, "%d %p %ld\n", handle, buffer, count );
1549 if (count == 0) { /* Expand or truncate at current position */
1550 FILE_OBJECT *file = FILE_GetFile(handle);
1552 if ( ftruncate(file->unix_handle,
1553 lseek( file->unix_handle, 0, SEEK_CUR)) == 0 ) {
1554 FILE_ReleaseFile(file);
1555 return 0;
1556 } else {
1557 FILE_SetDosError();
1558 FILE_ReleaseFile(file);
1559 return HFILE_ERROR32;
1563 if (!(ioptr = HANDLE_GetObjPtr( PROCESS_Current(), handle,
1564 K32OBJ_UNKNOWN, 0, NULL )))
1565 return HFILE_ERROR32;
1566 if (K32OBJ_OPS(ioptr)->write)
1567 status = K32OBJ_OPS(ioptr)->write(ioptr, buffer, count, &result, NULL);
1568 K32OBJ_DecCount( ioptr );
1569 if (!status) result = HFILE_ERROR32;
1570 return result;
1574 /***********************************************************************
1575 * SetHandleCount16 (KERNEL.199)
1577 UINT16 WINAPI SetHandleCount16( UINT16 count )
1579 HGLOBAL16 hPDB = GetCurrentPDB();
1580 PDB *pdb = (PDB *)GlobalLock16( hPDB );
1581 BYTE *files = PTR_SEG_TO_LIN( pdb->fileHandlesPtr );
1583 TRACE(file, "(%d)\n", count );
1585 if (count < 20) count = 20; /* No point in going below 20 */
1586 else if (count > 254) count = 254;
1588 if (count == 20)
1590 if (pdb->nbFiles > 20)
1592 memcpy( pdb->fileHandles, files, 20 );
1593 GlobalFree16( pdb->hFileHandles );
1594 pdb->fileHandlesPtr = (SEGPTR)MAKELONG( 0x18,
1595 GlobalHandleToSel( hPDB ) );
1596 pdb->hFileHandles = 0;
1597 pdb->nbFiles = 20;
1600 else /* More than 20, need a new file handles table */
1602 BYTE *newfiles;
1603 HGLOBAL16 newhandle = GlobalAlloc16( GMEM_MOVEABLE, count );
1604 if (!newhandle)
1606 DOS_ERROR( ER_OutOfMemory, EC_OutOfResource, SA_Abort, EL_Memory );
1607 return pdb->nbFiles;
1609 newfiles = (BYTE *)GlobalLock16( newhandle );
1611 if (count > pdb->nbFiles)
1613 memcpy( newfiles, files, pdb->nbFiles );
1614 memset( newfiles + pdb->nbFiles, 0xff, count - pdb->nbFiles );
1616 else memcpy( newfiles, files, count );
1617 if (pdb->nbFiles > 20) GlobalFree16( pdb->hFileHandles );
1618 pdb->fileHandlesPtr = WIN16_GlobalLock16( newhandle );
1619 pdb->hFileHandles = newhandle;
1620 pdb->nbFiles = count;
1622 return pdb->nbFiles;
1626 /*************************************************************************
1627 * SetHandleCount32 (KERNEL32.494)
1629 UINT32 WINAPI SetHandleCount32( UINT32 count )
1631 return MIN( 256, count );
1635 /***********************************************************************
1636 * FlushFileBuffers (KERNEL32.133)
1638 BOOL32 WINAPI FlushFileBuffers( HFILE32 hFile )
1640 FILE_OBJECT *file;
1641 BOOL32 ret;
1643 TRACE(file, "(%d)\n", hFile );
1644 if (!(file = FILE_GetFile( hFile ))) return FALSE;
1645 if (fsync( file->unix_handle ) != -1) ret = TRUE;
1646 else
1648 FILE_SetDosError();
1649 ret = FALSE;
1651 FILE_ReleaseFile( file );
1652 return ret;
1656 /**************************************************************************
1657 * SetEndOfFile (KERNEL32.483)
1659 BOOL32 WINAPI SetEndOfFile( HFILE32 hFile )
1661 FILE_OBJECT *file;
1662 BOOL32 ret = TRUE;
1664 TRACE(file, "(%d)\n", hFile );
1665 if (!(file = FILE_GetFile( hFile ))) return FALSE;
1666 if (ftruncate( file->unix_handle,
1667 lseek( file->unix_handle, 0, SEEK_CUR ) ))
1669 FILE_SetDosError();
1670 ret = FALSE;
1672 FILE_ReleaseFile( file );
1673 return ret;
1677 /***********************************************************************
1678 * DeleteFile16 (KERNEL.146)
1680 BOOL16 WINAPI DeleteFile16( LPCSTR path )
1682 return DeleteFile32A( path );
1686 /***********************************************************************
1687 * DeleteFile32A (KERNEL32.71)
1689 BOOL32 WINAPI DeleteFile32A( LPCSTR path )
1691 DOS_FULL_NAME full_name;
1693 TRACE(file, "'%s'\n", path );
1695 if (DOSFS_GetDevice( path ))
1697 WARN(file, "cannot remove DOS device '%s'!\n", path);
1698 DOS_ERROR( ER_FileNotFound, EC_NotFound, SA_Abort, EL_Disk );
1699 return FALSE;
1702 if (!DOSFS_GetFullName( path, TRUE, &full_name )) return FALSE;
1703 if (unlink( full_name.long_name ) == -1)
1705 FILE_SetDosError();
1706 return FALSE;
1708 return TRUE;
1712 /***********************************************************************
1713 * DeleteFile32W (KERNEL32.72)
1715 BOOL32 WINAPI DeleteFile32W( LPCWSTR path )
1717 LPSTR xpath = HEAP_strdupWtoA( GetProcessHeap(), 0, path );
1718 BOOL32 ret = DeleteFile32A( xpath );
1719 HeapFree( GetProcessHeap(), 0, xpath );
1720 return ret;
1724 /***********************************************************************
1725 * FILE_SetFileType
1727 BOOL32 FILE_SetFileType( HFILE32 hFile, DWORD type )
1729 FILE_OBJECT *file = FILE_GetFile( hFile );
1730 if (!file) return FALSE;
1731 file->type = type;
1732 FILE_ReleaseFile( file );
1733 return TRUE;
1737 /***********************************************************************
1738 * FILE_mmap
1740 LPVOID FILE_mmap( HFILE32 hFile, LPVOID start,
1741 DWORD size_high, DWORD size_low,
1742 DWORD offset_high, DWORD offset_low,
1743 int prot, int flags )
1745 LPVOID ret;
1746 FILE_OBJECT *file = FILE_GetFile( hFile );
1747 if (!file) return (LPVOID)-1;
1748 ret = FILE_dommap( file, start, size_high, size_low,
1749 offset_high, offset_low, prot, flags );
1750 FILE_ReleaseFile( file );
1751 return ret;
1755 /***********************************************************************
1756 * FILE_dommap
1758 LPVOID FILE_dommap( FILE_OBJECT *file, LPVOID start,
1759 DWORD size_high, DWORD size_low,
1760 DWORD offset_high, DWORD offset_low,
1761 int prot, int flags )
1763 int fd = -1;
1764 int pos;
1765 LPVOID ret;
1767 if (size_high || offset_high)
1768 FIXME(file, "offsets larger than 4Gb not supported\n");
1770 if (!file)
1772 #ifdef MAP_ANON
1773 flags |= MAP_ANON;
1774 #else
1775 static int fdzero = -1;
1777 if (fdzero == -1)
1779 if ((fdzero = open( "/dev/zero", O_RDONLY )) == -1)
1781 perror( "/dev/zero: open" );
1782 exit(1);
1785 fd = fdzero;
1786 #endif /* MAP_ANON */
1787 /* Linux EINVAL's on us if we don't pass MAP_PRIVATE to an anon mmap */
1788 #ifdef MAP_SHARED
1789 flags &= ~MAP_SHARED;
1790 #endif
1791 #ifdef MAP_PRIVATE
1792 flags |= MAP_PRIVATE;
1793 #endif
1795 else fd = file->unix_handle;
1797 if ((ret = mmap( start, size_low, prot,
1798 flags, fd, offset_low )) != (LPVOID)-1)
1799 return ret;
1801 /* mmap() failed; if this is because the file offset is not */
1802 /* page-aligned (EINVAL), or because the underlying filesystem */
1803 /* does not support mmap() (ENOEXEC), we do it by hand. */
1805 if (!file) return ret;
1806 if ((errno != ENOEXEC) && (errno != EINVAL)) return ret;
1807 if (prot & PROT_WRITE)
1809 /* We cannot fake shared write mappings */
1810 #ifdef MAP_SHARED
1811 if (flags & MAP_SHARED) return ret;
1812 #endif
1813 #ifdef MAP_PRIVATE
1814 if (!(flags & MAP_PRIVATE)) return ret;
1815 #endif
1817 /* printf( "FILE_mmap: mmap failed (%d), faking it\n", errno );*/
1818 /* Reserve the memory with an anonymous mmap */
1819 ret = FILE_dommap( NULL, start, size_high, size_low, 0, 0,
1820 PROT_READ | PROT_WRITE, flags );
1821 if (ret == (LPVOID)-1) return ret;
1822 /* Now read in the file */
1823 if ((pos = lseek( fd, offset_low, SEEK_SET )) == -1)
1825 FILE_munmap( ret, size_high, size_low );
1826 return (LPVOID)-1;
1828 read( fd, ret, size_low );
1829 lseek( fd, pos, SEEK_SET ); /* Restore the file pointer */
1830 mprotect( ret, size_low, prot ); /* Set the right protection */
1831 return ret;
1835 /***********************************************************************
1836 * FILE_munmap
1838 int FILE_munmap( LPVOID start, DWORD size_high, DWORD size_low )
1840 if (size_high)
1841 FIXME(file, "offsets larger than 4Gb not supported\n");
1842 return munmap( start, size_low );
1846 /***********************************************************************
1847 * GetFileType (KERNEL32.222)
1849 DWORD WINAPI GetFileType( HFILE32 hFile )
1851 FILE_OBJECT *file = FILE_GetFile(hFile);
1852 if (!file) return FILE_TYPE_UNKNOWN; /* FIXME: correct? */
1853 FILE_ReleaseFile( file );
1854 return file->type;
1858 /**************************************************************************
1859 * MoveFileEx32A (KERNEL32.???)
1861 BOOL32 WINAPI MoveFileEx32A( LPCSTR fn1, LPCSTR fn2, DWORD flag )
1863 DOS_FULL_NAME full_name1, full_name2;
1864 int mode=0; /* mode == 1: use copy */
1866 TRACE(file, "(%s,%s,%04lx)\n", fn1, fn2, flag);
1868 if (!DOSFS_GetFullName( fn1, TRUE, &full_name1 )) return FALSE;
1869 if (fn2) { /* !fn2 means delete fn1 */
1870 if (!DOSFS_GetFullName( fn2, FALSE, &full_name2 )) return FALSE;
1871 /* Source name and target path are valid */
1872 if ( full_name1.drive != full_name2.drive)
1874 /* use copy, if allowed */
1875 if (!(flag & MOVEFILE_COPY_ALLOWED)) {
1876 /* FIXME: Use right error code */
1877 DOS_ERROR( ER_FileExists, EC_Exists, SA_Abort, EL_Disk );
1878 return FALSE;
1880 else mode =1;
1882 if (DOSFS_GetFullName( fn2, TRUE, &full_name2 ))
1883 /* target exists, check if we may overwrite */
1884 if (!(flag & MOVEFILE_REPLACE_EXISTING)) {
1885 /* FIXME: Use right error code */
1886 DOS_ERROR( ER_AccessDenied, EC_AccessDenied, SA_Abort, EL_Disk );
1887 return FALSE;
1890 else /* fn2 == NULL means delete source */
1891 if (flag & MOVEFILE_DELAY_UNTIL_REBOOT) {
1892 if (flag & MOVEFILE_COPY_ALLOWED) {
1893 WARN(file, "Illegal flag\n");
1894 DOS_ERROR( ER_GeneralFailure, EC_SystemFailure, SA_Abort,
1895 EL_Unknown );
1896 return FALSE;
1898 /* FIXME: (bon@elektron.ikp.physik.th-darmstadt.de 970706)
1899 Perhaps we should queue these command and execute it
1900 when exiting... What about using on_exit(2)
1902 FIXME(file, "Please delete file '%s' when Wine has finished\n",
1903 full_name1.long_name);
1904 return TRUE;
1906 else if (unlink( full_name1.long_name ) == -1)
1908 FILE_SetDosError();
1909 return FALSE;
1911 else return TRUE; /* successfully deleted */
1913 if (flag & MOVEFILE_DELAY_UNTIL_REBOOT) {
1914 /* FIXME: (bon@elektron.ikp.physik.th-darmstadt.de 970706)
1915 Perhaps we should queue these command and execute it
1916 when exiting... What about using on_exit(2)
1918 FIXME(file,"Please move existing file '%s' to file '%s'"
1919 "when Wine has finished\n",
1920 full_name1.long_name, full_name2.long_name);
1921 return TRUE;
1924 if (!mode) /* move the file */
1925 if (rename( full_name1.long_name, full_name2.long_name ) == -1)
1927 FILE_SetDosError();
1928 return FALSE;
1930 else return TRUE;
1931 else /* copy File */
1932 return CopyFile32A(fn1, fn2, (!(flag & MOVEFILE_REPLACE_EXISTING)));
1936 /**************************************************************************
1937 * MoveFileEx32W (KERNEL32.???)
1939 BOOL32 WINAPI MoveFileEx32W( LPCWSTR fn1, LPCWSTR fn2, DWORD flag )
1941 LPSTR afn1 = HEAP_strdupWtoA( GetProcessHeap(), 0, fn1 );
1942 LPSTR afn2 = HEAP_strdupWtoA( GetProcessHeap(), 0, fn2 );
1943 BOOL32 res = MoveFileEx32A( afn1, afn2, flag );
1944 HeapFree( GetProcessHeap(), 0, afn1 );
1945 HeapFree( GetProcessHeap(), 0, afn2 );
1946 return res;
1950 /**************************************************************************
1951 * MoveFile32A (KERNEL32.387)
1953 * Move file or directory
1955 BOOL32 WINAPI MoveFile32A( LPCSTR fn1, LPCSTR fn2 )
1957 DOS_FULL_NAME full_name1, full_name2;
1958 struct stat fstat;
1960 TRACE(file, "(%s,%s)\n", fn1, fn2 );
1962 if (!DOSFS_GetFullName( fn1, TRUE, &full_name1 )) return FALSE;
1963 if (DOSFS_GetFullName( fn2, TRUE, &full_name2 ))
1964 /* The new name must not already exist */
1965 return FALSE;
1966 if (!DOSFS_GetFullName( fn2, FALSE, &full_name2 )) return FALSE;
1968 if (full_name1.drive == full_name2.drive) /* move */
1969 if (rename( full_name1.long_name, full_name2.long_name ) == -1)
1971 FILE_SetDosError();
1972 return FALSE;
1974 else return TRUE;
1975 else /*copy */ {
1976 if (stat( full_name1.long_name, &fstat ))
1978 WARN(file, "Invalid source file %s\n",
1979 full_name1.long_name);
1980 FILE_SetDosError();
1981 return FALSE;
1983 if (S_ISDIR(fstat.st_mode)) {
1984 /* No Move for directories across file systems */
1985 /* FIXME: Use right error code */
1986 DOS_ERROR( ER_GeneralFailure, EC_SystemFailure, SA_Abort,
1987 EL_Unknown );
1988 return FALSE;
1990 else
1991 return CopyFile32A(fn1, fn2, TRUE); /*fail, if exist */
1996 /**************************************************************************
1997 * MoveFile32W (KERNEL32.390)
1999 BOOL32 WINAPI MoveFile32W( LPCWSTR fn1, LPCWSTR fn2 )
2001 LPSTR afn1 = HEAP_strdupWtoA( GetProcessHeap(), 0, fn1 );
2002 LPSTR afn2 = HEAP_strdupWtoA( GetProcessHeap(), 0, fn2 );
2003 BOOL32 res = MoveFile32A( afn1, afn2 );
2004 HeapFree( GetProcessHeap(), 0, afn1 );
2005 HeapFree( GetProcessHeap(), 0, afn2 );
2006 return res;
2010 /**************************************************************************
2011 * CopyFile32A (KERNEL32.36)
2013 BOOL32 WINAPI CopyFile32A( LPCSTR source, LPCSTR dest, BOOL32 fail_if_exists )
2015 HFILE32 h1, h2;
2016 BY_HANDLE_FILE_INFORMATION info;
2017 UINT32 count;
2018 BOOL32 ret = FALSE;
2019 int mode;
2020 char buffer[2048];
2022 if ((h1 = _lopen32( source, OF_READ )) == HFILE_ERROR32) return FALSE;
2023 if (!GetFileInformationByHandle( h1, &info ))
2025 CloseHandle( h1 );
2026 return FALSE;
2028 mode = (info.dwFileAttributes & FILE_ATTRIBUTE_READONLY) ? 0444 : 0666;
2029 if ((h2 = FILE_Create( dest, mode, fail_if_exists )) == HFILE_ERROR32)
2031 CloseHandle( h1 );
2032 return FALSE;
2034 while ((count = _lread32( h1, buffer, sizeof(buffer) )) > 0)
2036 char *p = buffer;
2037 while (count > 0)
2039 INT32 res = _lwrite32( h2, p, count );
2040 if (res <= 0) goto done;
2041 p += res;
2042 count -= res;
2045 ret = TRUE;
2046 done:
2047 CloseHandle( h1 );
2048 CloseHandle( h2 );
2049 return ret;
2053 /**************************************************************************
2054 * CopyFile32W (KERNEL32.37)
2056 BOOL32 WINAPI CopyFile32W( LPCWSTR source, LPCWSTR dest, BOOL32 fail_if_exists)
2058 LPSTR sourceA = HEAP_strdupWtoA( GetProcessHeap(), 0, source );
2059 LPSTR destA = HEAP_strdupWtoA( GetProcessHeap(), 0, dest );
2060 BOOL32 ret = CopyFile32A( sourceA, destA, fail_if_exists );
2061 HeapFree( GetProcessHeap(), 0, sourceA );
2062 HeapFree( GetProcessHeap(), 0, destA );
2063 return ret;
2067 /**************************************************************************
2068 * CopyFileEx32A (KERNEL32.858)
2070 * This implementation ignores most of the extra parameters passed-in into
2071 * the "ex" version of the method and calls the CopyFile method.
2072 * It will have to be fixed eventually.
2074 BOOL32 WINAPI CopyFileEx32A(LPCSTR sourceFilename,
2075 LPCSTR destFilename,
2076 LPPROGRESS_ROUTINE progressRoutine,
2077 LPVOID appData,
2078 LPBOOL32 cancelFlagPointer,
2079 DWORD copyFlags)
2081 BOOL32 failIfExists = FALSE;
2084 * Interpret the only flag that CopyFile can interpret.
2086 if ( (copyFlags & COPY_FILE_FAIL_IF_EXISTS) != 0)
2088 failIfExists = TRUE;
2091 return CopyFile32A(sourceFilename, destFilename, failIfExists);
2094 /**************************************************************************
2095 * CopyFileEx32W (KERNEL32.859)
2097 BOOL32 WINAPI CopyFileEx32W(LPCWSTR sourceFilename,
2098 LPCWSTR destFilename,
2099 LPPROGRESS_ROUTINE progressRoutine,
2100 LPVOID appData,
2101 LPBOOL32 cancelFlagPointer,
2102 DWORD copyFlags)
2104 LPSTR sourceA = HEAP_strdupWtoA( GetProcessHeap(), 0, sourceFilename );
2105 LPSTR destA = HEAP_strdupWtoA( GetProcessHeap(), 0, destFilename );
2107 BOOL32 ret = CopyFileEx32A(sourceA,
2108 destA,
2109 progressRoutine,
2110 appData,
2111 cancelFlagPointer,
2112 copyFlags);
2114 HeapFree( GetProcessHeap(), 0, sourceA );
2115 HeapFree( GetProcessHeap(), 0, destA );
2117 return ret;
2121 /***********************************************************************
2122 * SetFileTime (KERNEL32.650)
2124 BOOL32 WINAPI SetFileTime( HFILE32 hFile,
2125 const FILETIME *lpCreationTime,
2126 const FILETIME *lpLastAccessTime,
2127 const FILETIME *lpLastWriteTime )
2129 FILE_OBJECT *file = FILE_GetFile(hFile);
2130 struct utimbuf utimbuf;
2132 if (!file) return FILE_TYPE_UNKNOWN; /* FIXME: correct? */
2133 TRACE(file,"('%s',%p,%p,%p)\n",
2134 file->unix_name,
2135 lpCreationTime,
2136 lpLastAccessTime,
2137 lpLastWriteTime
2139 if (lpLastAccessTime)
2140 utimbuf.actime = DOSFS_FileTimeToUnixTime(lpLastAccessTime, NULL);
2141 else
2142 utimbuf.actime = 0; /* FIXME */
2143 if (lpLastWriteTime)
2144 utimbuf.modtime = DOSFS_FileTimeToUnixTime(lpLastWriteTime, NULL);
2145 else
2146 utimbuf.modtime = 0; /* FIXME */
2147 if (-1==utime(file->unix_name,&utimbuf))
2149 MSG("Couldn't set the time for file '%s'. Insufficient permissions !?\n", file->unix_name);
2150 FILE_ReleaseFile( file );
2151 FILE_SetDosError();
2152 return FALSE;
2154 FILE_ReleaseFile( file );
2155 return TRUE;
2158 /* Locks need to be mirrored because unix file locking is based
2159 * on the pid. Inside of wine there can be multiple WINE processes
2160 * that share the same unix pid.
2161 * Read's and writes should check these locks also - not sure
2162 * how critical that is at this point (FIXME).
2165 static BOOL32 DOS_AddLock(FILE_OBJECT *file, struct flock *f)
2167 DOS_FILE_LOCK *curr;
2168 DWORD processId;
2170 processId = GetCurrentProcessId();
2172 /* check if lock overlaps a current lock for the same file */
2173 for (curr = locks; curr; curr = curr->next) {
2174 if (strcmp(curr->unix_name, file->unix_name) == 0) {
2175 if ((f->l_start == curr->base) && (f->l_len == curr->len))
2176 return TRUE;/* region is identic */
2177 if ((f->l_start < (curr->base + curr->len)) &&
2178 ((f->l_start + f->l_len) > curr->base)) {
2179 /* region overlaps */
2180 return FALSE;
2185 curr = HeapAlloc( SystemHeap, 0, sizeof(DOS_FILE_LOCK) );
2186 curr->processId = GetCurrentProcessId();
2187 curr->base = f->l_start;
2188 curr->len = f->l_len;
2189 curr->unix_name = HEAP_strdupA( SystemHeap, 0, file->unix_name);
2190 curr->next = locks;
2191 curr->dos_file = file;
2192 locks = curr;
2193 return TRUE;
2196 static void DOS_RemoveFileLocks(FILE_OBJECT *file)
2198 DWORD processId;
2199 DOS_FILE_LOCK **curr;
2200 DOS_FILE_LOCK *rem;
2202 processId = GetCurrentProcessId();
2203 curr = &locks;
2204 while (*curr) {
2205 if ((*curr)->dos_file == file) {
2206 rem = *curr;
2207 *curr = (*curr)->next;
2208 HeapFree( SystemHeap, 0, rem->unix_name );
2209 HeapFree( SystemHeap, 0, rem );
2211 else
2212 curr = &(*curr)->next;
2216 static BOOL32 DOS_RemoveLock(FILE_OBJECT *file, struct flock *f)
2218 DWORD processId;
2219 DOS_FILE_LOCK **curr;
2220 DOS_FILE_LOCK *rem;
2222 processId = GetCurrentProcessId();
2223 for (curr = &locks; *curr; curr = &(*curr)->next) {
2224 if ((*curr)->processId == processId &&
2225 (*curr)->dos_file == file &&
2226 (*curr)->base == f->l_start &&
2227 (*curr)->len == f->l_len) {
2228 /* this is the same lock */
2229 rem = *curr;
2230 *curr = (*curr)->next;
2231 HeapFree( SystemHeap, 0, rem->unix_name );
2232 HeapFree( SystemHeap, 0, rem );
2233 return TRUE;
2236 /* no matching lock found */
2237 return FALSE;
2241 /**************************************************************************
2242 * LockFile (KERNEL32.511)
2244 BOOL32 WINAPI LockFile(
2245 HFILE32 hFile,DWORD dwFileOffsetLow,DWORD dwFileOffsetHigh,
2246 DWORD nNumberOfBytesToLockLow,DWORD nNumberOfBytesToLockHigh )
2248 struct flock f;
2249 FILE_OBJECT *file;
2251 TRACE(file, "handle %d offsetlow=%ld offsethigh=%ld nbyteslow=%ld nbyteshigh=%ld\n",
2252 hFile, dwFileOffsetLow, dwFileOffsetHigh,
2253 nNumberOfBytesToLockLow, nNumberOfBytesToLockHigh);
2255 if (dwFileOffsetHigh || nNumberOfBytesToLockHigh) {
2256 FIXME(file, "Unimplemented bytes > 32bits\n");
2257 return FALSE;
2260 f.l_start = dwFileOffsetLow;
2261 f.l_len = nNumberOfBytesToLockLow;
2262 f.l_whence = SEEK_SET;
2263 f.l_pid = 0;
2264 f.l_type = F_WRLCK;
2266 if (!(file = FILE_GetFile(hFile))) return FALSE;
2268 /* shadow locks internally */
2269 if (!DOS_AddLock(file, &f)) {
2270 DOS_ERROR( ER_LockViolation, EC_AccessDenied, SA_Ignore, EL_Disk );
2271 return FALSE;
2274 /* FIXME: Unix locking commented out for now, doesn't work with Excel */
2275 #ifdef USE_UNIX_LOCKS
2276 if (fcntl(file->unix_handle, F_SETLK, &f) == -1) {
2277 if (errno == EACCES || errno == EAGAIN) {
2278 DOS_ERROR( ER_LockViolation, EC_AccessDenied, SA_Ignore, EL_Disk );
2280 else {
2281 FILE_SetDosError();
2283 /* remove our internal copy of the lock */
2284 DOS_RemoveLock(file, &f);
2285 return FALSE;
2287 #endif
2288 return TRUE;
2292 /**************************************************************************
2293 * UnlockFile (KERNEL32.703)
2295 BOOL32 WINAPI UnlockFile(
2296 HFILE32 hFile,DWORD dwFileOffsetLow,DWORD dwFileOffsetHigh,
2297 DWORD nNumberOfBytesToUnlockLow,DWORD nNumberOfBytesToUnlockHigh )
2299 FILE_OBJECT *file;
2300 struct flock f;
2302 TRACE(file, "handle %d offsetlow=%ld offsethigh=%ld nbyteslow=%ld nbyteshigh=%ld\n",
2303 hFile, dwFileOffsetLow, dwFileOffsetHigh,
2304 nNumberOfBytesToUnlockLow, nNumberOfBytesToUnlockHigh);
2306 if (dwFileOffsetHigh || nNumberOfBytesToUnlockHigh) {
2307 WARN(file, "Unimplemented bytes > 32bits\n");
2308 return FALSE;
2311 f.l_start = dwFileOffsetLow;
2312 f.l_len = nNumberOfBytesToUnlockLow;
2313 f.l_whence = SEEK_SET;
2314 f.l_pid = 0;
2315 f.l_type = F_UNLCK;
2317 if (!(file = FILE_GetFile(hFile))) return FALSE;
2319 DOS_RemoveLock(file, &f); /* ok if fails - may be another wine */
2321 /* FIXME: Unix locking commented out for now, doesn't work with Excel */
2322 #ifdef USE_UNIX_LOCKS
2323 if (fcntl(file->unix_handle, F_SETLK, &f) == -1) {
2324 FILE_SetDosError();
2325 return FALSE;
2327 #endif
2328 return TRUE;
2331 /**************************************************************************
2332 * GetFileAttributesEx32A [KERNEL32.874]
2334 BOOL32 WINAPI GetFileAttributesEx32A(
2335 LPCSTR lpFileName, GET_FILEEX_INFO_LEVELS fInfoLevelId,
2336 LPVOID lpFileInformation)
2338 DOS_FULL_NAME full_name;
2339 BY_HANDLE_FILE_INFORMATION info;
2341 if (lpFileName == NULL) return FALSE;
2342 if (lpFileInformation == NULL) return FALSE;
2344 if (fInfoLevelId == GetFileExInfoStandard) {
2345 LPWIN32_FILE_ATTRIBUTE_DATA lpFad =
2346 (LPWIN32_FILE_ATTRIBUTE_DATA) lpFileInformation;
2347 if (!DOSFS_GetFullName( lpFileName, TRUE, &full_name )) return FALSE;
2348 if (!FILE_Stat( full_name.long_name, &info )) return FALSE;
2350 lpFad->dwFileAttributes = info.dwFileAttributes;
2351 lpFad->ftCreationTime = info.ftCreationTime;
2352 lpFad->ftLastAccessTime = info.ftLastAccessTime;
2353 lpFad->ftLastWriteTime = info.ftLastWriteTime;
2354 lpFad->nFileSizeHigh = info.nFileSizeHigh;
2355 lpFad->nFileSizeLow = info.nFileSizeLow;
2357 else {
2358 FIXME (file, "invalid info level %d!\n", fInfoLevelId);
2359 return FALSE;
2362 return TRUE;
2366 /**************************************************************************
2367 * GetFileAttributesEx32W [KERNEL32.875]
2369 BOOL32 WINAPI GetFileAttributesEx32W(
2370 LPCWSTR lpFileName, GET_FILEEX_INFO_LEVELS fInfoLevelId,
2371 LPVOID lpFileInformation)
2373 LPSTR nameA = HEAP_strdupWtoA( GetProcessHeap(), 0, lpFileName );
2374 BOOL32 res =
2375 GetFileAttributesEx32A( nameA, fInfoLevelId, lpFileInformation);
2376 HeapFree( GetProcessHeap(), 0, nameA );
2377 return res;