Release 960302
[wine/multimedia.git] / files / file.c
blob8ea3d1e9f526ab4997577be2d00966a82407903e
1 /*
2 * File handling functions
4 * Copyright 1993 John Burton
5 * Copyright 1996 Alexandre Julliard
6 */
8 #include <errno.h>
9 #include <fcntl.h>
10 #include <stdio.h>
11 #include <string.h>
12 #include <sys/errno.h>
13 #include <sys/stat.h>
14 #include <time.h>
15 #include <unistd.h>
17 #include "windows.h"
18 #include "directory.h"
19 #include "dos_fs.h"
20 #include "drive.h"
21 #include "global.h"
22 #include "msdos.h"
23 #include "options.h"
24 #include "ldt.h"
25 #include "task.h"
26 #include "stddebug.h"
27 #include "debug.h"
29 #define MAX_OPEN_FILES 64 /* Max. open files for all tasks; must be <255 */
31 typedef struct
33 int unix_handle;
34 int mode;
35 } DOS_FILE;
37 /* Global files array */
38 static DOS_FILE DOSFiles[MAX_OPEN_FILES];
41 /***********************************************************************
42 * FILE_AllocDOSFile
44 * Allocate a file from the DOS files array.
46 static BYTE FILE_AllocDOSFile( int unix_handle )
48 BYTE i;
49 for (i = 0; i < MAX_OPEN_FILES; i++) if (!DOSFiles[i].mode)
51 DOSFiles[i].unix_handle = unix_handle;
52 DOSFiles[i].mode = 1;
53 return i;
55 return 0xff;
59 /***********************************************************************
60 * FILE_FreeDOSFile
62 * Free a file from the DOS files array.
64 static BOOL FILE_FreeDOSFile( BYTE handle )
66 if (handle >= MAX_OPEN_FILES) return FALSE;
67 if (!DOSFiles[handle].mode) return FALSE;
68 DOSFiles[handle].mode = 0;
69 return TRUE;
73 /***********************************************************************
74 * FILE_GetUnixHandle
76 * Return the Unix handle for a global DOS file handle.
78 static int FILE_GetUnixHandle( BYTE handle )
80 if (handle >= MAX_OPEN_FILES) return -1;
81 if (!DOSFiles[handle].mode) return -1;
82 return DOSFiles[handle].unix_handle;
86 /***********************************************************************
87 * FILE_AllocTaskHandle
89 * Allocate a per-task file handle.
91 static HFILE FILE_AllocTaskHandle( int unix_handle )
93 PDB *pdb = (PDB *)GlobalLock( GetCurrentPDB() );
94 BYTE *files, *fp;
95 WORD i;
97 if (!pdb)
99 fprintf(stderr,"FILE_MakeTaskHandle: internal error, no current PDB.\n");
100 exit(1);
102 files = PTR_SEG_TO_LIN( pdb->fileHandlesPtr );
103 fp = files + 1; /* Don't use handle 0, as some programs don't like it */
104 for (i = pdb->nbFiles - 1; (i > 0) && (*fp != 0xff); i--, fp++);
105 if (!i || (*fp = FILE_AllocDOSFile( unix_handle )) == 0xff)
106 { /* No more handles or files */
107 DOS_ERROR( ER_TooManyOpenFiles, EC_ProgramError, SA_Abort, EL_Disk );
108 return -1;
110 dprintf_file(stddeb,
111 "FILE_AllocTaskHandle: returning task handle %d, file %d for unix handle %d file %d of %d \n",
112 (fp - files), *fp, unix_handle, pdb->nbFiles - i, pdb->nbFiles );
113 return (HFILE)(fp - files);
117 /***********************************************************************
118 * FILE_FreeTaskHandle
120 * Free a per-task file handle.
122 static void FILE_FreeTaskHandle( HFILE handle )
124 PDB *pdb = (PDB *)GlobalLock( GetCurrentPDB() );
125 BYTE *files;
127 if (!pdb)
129 fprintf(stderr,"FILE_FreeTaskHandle: internal error, no current PDB.\n");
130 exit(1);
132 files = PTR_SEG_TO_LIN( pdb->fileHandlesPtr );
133 dprintf_file( stddeb,"FILE_FreeTaskHandle: dos=%d file=%d\n",
134 handle, files[handle] );
135 if ((handle < 0) || (handle >= (INT)pdb->nbFiles) ||
136 !FILE_FreeDOSFile( files[handle] ))
138 fprintf( stderr, "FILE_FreeTaskHandle: invalid file handle %d\n",
139 handle );
140 return;
142 files[handle] = 0xff;
146 /***********************************************************************
147 * FILE_GetUnixTaskHandle
149 * Return the Unix file handle associated to a task file handle.
151 int FILE_GetUnixTaskHandle( HFILE handle )
153 PDB *pdb = (PDB *)GlobalLock( GetCurrentPDB() );
154 BYTE *files;
155 int unix_handle;
157 if (!pdb)
159 fprintf(stderr,"FILE_GetUnixHandle: internal error, no current PDB.\n");
160 exit(1);
162 files = PTR_SEG_TO_LIN( pdb->fileHandlesPtr );
163 if ((handle < 0) || (handle >= (INT)pdb->nbFiles) ||
164 ((unix_handle = FILE_GetUnixHandle( files[handle] )) == -1))
166 DOS_ERROR( ER_InvalidHandle, EC_ProgramError, SA_Abort, EL_Disk );
167 return -1;
169 return unix_handle;
173 /***********************************************************************
174 * FILE_CloseAllFiles
176 * Close all open files of a given PDB. Used on task termination.
178 void FILE_CloseAllFiles( HANDLE hPDB )
180 BYTE *files;
181 WORD count;
182 PDB *pdb = (PDB *)GlobalLock( hPDB );
183 int unix_handle;
185 if (!pdb) return;
186 files = PTR_SEG_TO_LIN( pdb->fileHandlesPtr );
187 dprintf_file(stddeb,"FILE_CloseAllFiles: closing %d files\n",pdb->nbFiles);
188 for (count = pdb->nbFiles; count > 0; count--, files++)
190 if (*files != 0xff)
192 if ((unix_handle = FILE_GetUnixHandle( *files )) != -1)
194 close( unix_handle );
195 FILE_FreeDOSFile( *files );
197 *files = 0xff;
203 /***********************************************************************
204 * FILE_SetDosError
206 * Set the DOS error code from errno.
208 void FILE_SetDosError(void)
210 dprintf_file(stddeb, "FILE_SetDosError: errno = %d\n", errno );
211 switch (errno)
213 case EAGAIN:
214 DOS_ERROR( ER_ShareViolation, EC_Temporary, SA_Retry, EL_Disk );
215 break;
216 case EBADF:
217 DOS_ERROR( ER_InvalidHandle, EC_ProgramError, SA_Abort, EL_Disk );
218 break;
219 case ENOSPC:
220 DOS_ERROR( ER_DiskFull, EC_MediaError, SA_Abort, EL_Disk );
221 break;
222 case EACCES:
223 case EPERM:
224 case EROFS:
225 DOS_ERROR( ER_AccessDenied, EC_AccessDenied, SA_Abort, EL_Disk );
226 break;
227 case EBUSY:
228 DOS_ERROR( ER_LockViolation, EC_AccessDenied, SA_Abort, EL_Disk );
229 break;
230 case ENOENT:
231 DOS_ERROR( ER_FileNotFound, EC_NotFound, SA_Abort, EL_Disk );
232 break;
233 case EISDIR:
234 DOS_ERROR( ER_CanNotMakeDir, EC_AccessDenied, SA_Abort, EL_Unknown );
235 break;
236 case ENFILE:
237 case EMFILE:
238 DOS_ERROR( ER_NoMoreFiles, EC_MediaError, SA_Abort, EL_Unknown );
239 break;
240 case EEXIST:
241 DOS_ERROR( ER_FileExists, EC_Exists, SA_Abort, EL_Disk );
242 break;
243 default:
244 perror( "int21: unknown errno" );
245 DOS_ERROR( ER_GeneralFailure, EC_SystemFailure, SA_Abort, EL_Unknown );
246 break;
251 /***********************************************************************
252 * FILE_OpenUnixFile
254 static int FILE_OpenUnixFile( const char *name, int mode )
256 int handle;
257 struct stat st;
259 if ((handle = open( name, mode )) == -1)
261 if (Options.allowReadOnly && (mode == O_RDWR))
263 if ((handle = open( name, O_RDONLY )) != -1)
264 fprintf( stderr, "Warning: could not open %s for writing, opening read-only.\n", name );
267 if (handle != -1) /* Make sure it's not a directory */
269 if ((fstat( handle, &st ) == -1))
271 FILE_SetDosError();
272 close( handle );
273 handle = -1;
275 else if (S_ISDIR(st.st_mode))
277 DOS_ERROR( ER_AccessDenied, EC_AccessDenied, SA_Abort, EL_Disk );
278 close( handle );
279 handle = -1;
282 return handle;
286 /***********************************************************************
287 * FILE_Open
289 int FILE_Open( LPCSTR path, int mode )
291 const char *unixName;
293 dprintf_file(stddeb, "FILE_Open: '%s' %04x\n", path, mode );
294 if ((unixName = DOSFS_IsDevice( path )) != NULL)
296 dprintf_file( stddeb, "FILE_Open: opening device '%s'\n", unixName );
297 if (!unixName[0]) /* Non-existing device */
299 dprintf_file(stddeb, "FILE_Open: Non-existing device\n");
300 DOS_ERROR( ER_FileNotFound, EC_NotFound, SA_Abort, EL_Disk );
301 return -1;
304 else if (!(unixName = DOSFS_GetUnixFileName( path, TRUE ))) return -1;
305 return FILE_OpenUnixFile( unixName, mode );
309 /***********************************************************************
310 * FILE_Create
312 int FILE_Create( LPCSTR path, int mode, int unique )
314 const char *unixName;
315 int handle;
317 dprintf_file(stddeb, "FILE_Create: '%s' %04x %d\n", path, mode, unique );
319 if ((unixName = DOSFS_IsDevice( path )) != NULL)
321 dprintf_file(stddeb, "FILE_Create: creating device '%s'!\n", unixName);
322 DOS_ERROR( ER_AccessDenied, EC_NotFound, SA_Abort, EL_Disk );
323 return -1;
326 if (!(unixName = DOSFS_GetUnixFileName( path, FALSE ))) return -1;
327 if ((handle = open( unixName,
328 O_CREAT | O_TRUNC | O_RDWR | (unique ? O_EXCL : 0),
329 mode )) == -1)
330 FILE_SetDosError();
331 return handle;
335 /***********************************************************************
336 * FILE_Unlink
338 int FILE_Unlink( LPCSTR path )
340 const char *unixName;
342 dprintf_file(stddeb, "FILE_Unlink: '%s'\n", path );
344 if ((unixName = DOSFS_IsDevice( path )) != NULL)
346 dprintf_file(stddeb, "FILE_Unlink: removing device '%s'!\n", unixName);
347 DOS_ERROR( ER_FileNotFound, EC_NotFound, SA_Abort, EL_Disk );
348 return 0;
351 if (!(unixName = DOSFS_GetUnixFileName( path, TRUE ))) return 0;
352 if (unlink( unixName ) == -1)
354 FILE_SetDosError();
355 return 0;
357 return 1;
361 /***********************************************************************
362 * FILE_Stat
364 * Stat a Unix path name. Return 1 if OK.
366 int FILE_Stat( LPCSTR unixName, BYTE *pattr, DWORD *psize,
367 WORD *pdate, WORD *ptime )
369 struct stat st;
371 if (stat( unixName, &st ) == -1)
373 FILE_SetDosError();
374 return 0;
376 if (pattr) *pattr = FA_ARCHIVE | (S_ISDIR(st.st_mode) ? FA_DIRECTORY : 0);
377 if (psize) *psize = S_ISDIR(st.st_mode) ? 0 : st.st_size;
378 DOSFS_ToDosDateTime( &st.st_mtime, pdate, ptime );
379 return 1;
383 /***********************************************************************
384 * FILE_Fstat
386 * Stat a DOS handle. Return 1 if OK.
388 int FILE_Fstat( HFILE hFile, BYTE *pattr, DWORD *psize,
389 WORD *pdate, WORD *ptime )
391 struct stat st;
392 int handle;
394 if ((handle = FILE_GetUnixTaskHandle( hFile )) == -1) return 0;
395 if (fstat( handle, &st ) == -1)
397 FILE_SetDosError();
398 return 0;
400 if (pattr) *pattr = FA_ARCHIVE | (S_ISDIR(st.st_mode) ? FA_DIRECTORY : 0);
401 if (psize) *psize = S_ISDIR(st.st_mode) ? 0 : st.st_size;
402 DOSFS_ToDosDateTime( &st.st_mtime, pdate, ptime );
403 return 1;
407 /***********************************************************************
408 * FILE_MakeDir
410 int FILE_MakeDir( LPCSTR path )
412 const char *unixName;
414 dprintf_file(stddeb, "FILE_MakeDir: '%s'\n", path );
416 if ((unixName = DOSFS_IsDevice( path )) != NULL)
418 dprintf_file(stddeb, "FILE_MakeDir: device '%s'!\n", unixName);
419 DOS_ERROR( ER_AccessDenied, EC_AccessDenied, SA_Abort, EL_Disk );
420 return 0;
422 if (!(unixName = DOSFS_GetUnixFileName( path, FALSE ))) return 0;
423 if ((mkdir( unixName, 0777 ) == -1) && (errno != EEXIST))
425 FILE_SetDosError();
426 return 0;
428 return 1;
432 /***********************************************************************
433 * FILE_RemoveDir
435 int FILE_RemoveDir( LPCSTR path )
437 const char *unixName;
439 dprintf_file(stddeb, "FILE_RemoveDir: '%s'\n", path );
441 if ((unixName = DOSFS_IsDevice( path )) != NULL)
443 dprintf_file(stddeb, "FILE_RemoveDir: device '%s'!\n", unixName);
444 DOS_ERROR( ER_FileNotFound, EC_NotFound, SA_Abort, EL_Disk );
445 return 0;
447 if (!(unixName = DOSFS_GetUnixFileName( path, TRUE ))) return 0;
448 if (rmdir( unixName ) == -1)
450 FILE_SetDosError();
451 return 0;
453 return 1;
457 /***********************************************************************
458 * FILE_Dup
460 * dup() function for DOS handles.
462 HFILE FILE_Dup( HFILE hFile )
464 int handle, newhandle;
465 HFILE dosHandle;
467 if ((handle = FILE_GetUnixTaskHandle( hFile )) == -1) return HFILE_ERROR;
468 dprintf_file( stddeb, "FILE_Dup for handle %d\n",handle);
469 if ((newhandle = dup(handle)) == -1)
471 FILE_SetDosError();
472 return HFILE_ERROR;
474 if ((dosHandle = FILE_AllocTaskHandle( newhandle )) == HFILE_ERROR)
475 close( newhandle );
476 dprintf_file( stddeb, "FILE_Dup return handle %d\n",dosHandle);
477 return dosHandle;
481 /***********************************************************************
482 * FILE_Dup2
484 * dup2() function for DOS handles.
486 HFILE FILE_Dup2( HFILE hFile1, HFILE hFile2 )
488 PDB *pdb = (PDB *)GlobalLock( GetCurrentPDB() );
489 BYTE *files;
490 int handle, newhandle;
492 if ((handle = FILE_GetUnixTaskHandle( hFile1 )) == -1) return HFILE_ERROR;
493 dprintf_file( stddeb, "FILE_Dup2 for handle %d\n",handle);
494 if ((hFile2 < 0) || (hFile2 >= (INT)pdb->nbFiles))
496 DOS_ERROR( ER_InvalidHandle, EC_ProgramError, SA_Abort, EL_Disk );
497 return HFILE_ERROR;
500 if ((newhandle = dup(handle)) == -1)
502 FILE_SetDosError();
503 return HFILE_ERROR;
505 if (newhandle >= 0xff)
507 DOS_ERROR( ER_TooManyOpenFiles, EC_ProgramError, SA_Abort, EL_Disk );
508 close( newhandle );
509 return HFILE_ERROR;
511 files = PTR_SEG_TO_LIN( pdb->fileHandlesPtr );
512 if (files[hFile2] != 0xff)
514 dprintf_file( stddeb, "FILE_Dup2 closing old handle2 %d\n",
515 files[hFile2]);
516 close( files[hFile2] );
518 files[hFile2] = (BYTE)newhandle;
519 dprintf_file( stddeb, "FILE_Dup2 return handle2 %d\n",newhandle);
520 return hFile2;
524 /***********************************************************************
525 * FILE_OpenFile
527 * Implementation of API function OpenFile(). Returns a Unix file handle.
529 int FILE_OpenFile( LPCSTR name, OFSTRUCT *ofs, UINT mode )
531 const char *unixName, *dosName;
532 char *p;
533 int handle, len, i, unixMode;
534 struct stat st;
536 ofs->cBytes = sizeof(OFSTRUCT);
537 ofs->nErrCode = 0;
538 if (mode & OF_REOPEN) name = ofs->szPathName;
539 dprintf_file( stddeb, "FILE_Openfile: %s %04x\n", name, mode );
541 /* OF_PARSE simply fills the structure */
543 if (mode & OF_PARSE)
545 if (!(dosName = DOSFS_GetDosTrueName( name, FALSE )))
547 ofs->nErrCode = DOS_ExtendedError;
548 dprintf_file( stddeb, "FILE_Openfile: %s return = -1\n", name);
549 return -1;
551 lstrcpyn( ofs->szPathName, dosName, sizeof(ofs->szPathName) );
552 ofs->fFixedDisk = (GetDriveType( dosName[0]-'A' ) != DRIVE_REMOVABLE);
553 dprintf_file( stddeb, "FILE_Openfile: %s return = 0\n", name);
554 return 0;
557 /* OF_CREATE is completely different from all other options, so
558 handle it first */
560 if (mode & OF_CREATE)
562 if ((unixName = DOSFS_GetUnixFileName( name, FALSE )) == NULL)
564 ofs->nErrCode = DOS_ExtendedError;
565 dprintf_file( stddeb, "FILE_Openfile: %s return = -1\n", name);
566 return -1;
568 dprintf_file( stddeb, "FILE_OpenFile: creating '%s'\n", unixName );
569 handle = open( unixName, O_TRUNC | O_RDWR | O_CREAT, 0666 );
570 if (handle == -1)
572 FILE_SetDosError();
573 ofs->nErrCode = DOS_ExtendedError;
574 dprintf_file( stddeb, "FILE_Openfile: %s return = -1\n", name);
575 return -1;
577 lstrcpyn( ofs->szPathName, DOSFS_GetDosTrueName( name, FALSE ),
578 sizeof(ofs->szPathName) );
579 dprintf_file( stddeb, "FILE_Openfile: %s return = %d \n", name, handle);
580 return handle;
583 /* Now look for the file */
585 /* First try the current directory */
587 lstrcpyn( ofs->szPathName, name, sizeof(ofs->szPathName) );
588 if ((unixName = DOSFS_GetUnixFileName( ofs->szPathName, TRUE )) != NULL)
589 goto found;
591 /* Now try some different paths if none was specified */
593 if ((mode & OF_SEARCH) && !(mode & OF_REOPEN))
595 if (name[1] == ':') name += 2;
596 if ((p = strrchr( name, '\\' ))) name = p + 1;
597 if ((p = strrchr( name, '/' ))) name = p + 1;
598 if (!name[0]) goto not_found;
600 else
602 if ((name[1] == ':') || strchr( name, '/' ) || strchr( name, '\\' ))
603 goto not_found;
606 if ((len = sizeof(ofs->szPathName) - strlen(name) - 1) < 0) goto not_found;
608 /* Try the Windows directory */
610 GetWindowsDirectory( ofs->szPathName, len );
611 strcat( ofs->szPathName, "\\" );
612 strcat( ofs->szPathName, name );
613 if ((unixName = DOSFS_GetUnixFileName( ofs->szPathName, TRUE )) != NULL)
614 goto found;
616 /* Try the Windows system directory */
618 GetSystemDirectory( ofs->szPathName, len );
619 strcat( ofs->szPathName, "\\" );
620 strcat( ofs->szPathName, name );
621 if ((unixName = DOSFS_GetUnixFileName( ofs->szPathName, TRUE )) != NULL)
622 goto found;
624 /* Try the path of the current executable */
626 if (GetCurrentTask())
628 GetModuleFileName( GetCurrentTask(), ofs->szPathName, len );
629 if ((p = strrchr( ofs->szPathName, '\\' )))
631 strcpy( p + 1, name );
632 if ((unixName = DOSFS_GetUnixFileName( ofs->szPathName, TRUE )))
633 goto found;
637 /* Try all directories in path */
639 for (i = 0; ; i++)
641 if (!DIR_GetDosPath( i, ofs->szPathName, len )) break;
642 strcat( ofs->szPathName, "\\" );
643 strcat( ofs->szPathName, name );
644 if ((unixName = DOSFS_GetUnixFileName( ofs->szPathName, TRUE)) != NULL)
645 goto found;
648 not_found:
649 dprintf_file( stddeb, "FILE_OpenFile: '%s' not found\n", name );
650 DOS_ERROR( ER_FileNotFound, EC_NotFound, SA_Abort, EL_Disk );
651 ofs->nErrCode = ER_FileNotFound;
652 dprintf_file( stddeb, "FILE_Openfile: %s return =-1\n", name);
653 return -1;
655 found:
656 dprintf_file( stddeb, "FILE_OpenFile: found '%s'\n", unixName );
657 lstrcpyn( ofs->szPathName, DOSFS_GetDosTrueName( ofs->szPathName, FALSE ),
658 sizeof(ofs->szPathName) );
660 if (mode & OF_DELETE)
662 if (unlink( unixName ) == -1) goto not_found;
663 dprintf_file( stddeb, "FILE_Openfile: %s return = 0\n", name);
664 return 0;
667 switch(mode & 3)
669 case OF_WRITE:
670 unixMode = O_WRONLY; break;
671 case OF_READWRITE:
672 unixMode = O_RDWR; break;
673 case OF_READ:
674 default:
675 unixMode = O_RDONLY; break;
678 if ((handle = FILE_OpenUnixFile( unixName, unixMode )) == -1)
679 goto not_found;
681 if (fstat( handle, &st ) != -1)
683 if ((mode & OF_VERIFY) && (mode & OF_REOPEN))
685 if (memcmp( ofs->reserved, &st.st_mtime, sizeof(ofs->reserved) ))
687 dprintf_file( stddeb, "FILE_Openfile: %s return = -1\n", name);
688 close( handle );
689 return -1;
692 memcpy( ofs->reserved, &st.st_mtime, sizeof(ofs->reserved) );
695 if (mode & OF_EXIST)
697 close( handle );
698 return 0;
700 dprintf_file( stddeb, "FILE_Openfile: %s return = %d\n", name,handle);
702 return handle;
706 /***********************************************************************
707 * FILE_Read
709 LONG FILE_Read( HFILE hFile, LPSTR buffer, LONG count )
711 int handle;
712 LONG result;
714 dprintf_file( stddeb, "FILE_Read: %d %p %ld\n", hFile, buffer, count );
715 if ((handle = FILE_GetUnixTaskHandle( hFile )) == -1) return -1;
716 if (!count) return 0;
717 if ((result = read( handle, buffer, count )) == -1) FILE_SetDosError();
718 return result;
722 /***********************************************************************
723 * GetTempFileName (KERNEL.97)
725 INT GetTempFileName( BYTE drive, LPCSTR prefix, UINT unique, LPSTR buffer )
727 int i, handle;
728 UINT num = unique ? (unique & 0xffff) : time(NULL) & 0xffff;
729 char *p;
731 if (drive & TF_FORCEDRIVE)
733 sprintf( buffer, "%c:", drive & ~TF_FORCEDRIVE );
735 else
737 DIR_GetTempDosDir( buffer, 132 ); /* buffer must be at least 144 */
738 strcat( buffer, "\\" );
741 p = buffer + strlen(buffer);
742 for (i = 3; (i > 0) && (*prefix); i--) *p++ = *prefix++;
743 sprintf( p, "%04x.tmp", num );
745 if (unique)
747 lstrcpyn( buffer, DOSFS_GetDosTrueName( buffer, FALSE ), 144 );
748 dprintf_file( stddeb, "GetTempFileName: returning %s\n", buffer );
749 return unique;
752 /* Now try to create it */
756 if ((handle = FILE_Create( buffer, 0666, TRUE )) != -1)
757 { /* We created it */
758 dprintf_file( stddeb, "GetTempFileName: created %s\n", buffer );
759 close( handle );
760 break;
762 if (DOS_ExtendedError != ER_FileExists) break; /* No need to go on */
763 num++;
764 sprintf( p, "%04x.tmp", num );
765 } while (num != (unique & 0xffff));
767 lstrcpyn( buffer, DOSFS_GetDosTrueName( buffer, FALSE ), 144 );
768 dprintf_file( stddeb, "GetTempFileName: returning %s\n", buffer );
769 return num;
773 /***********************************************************************
774 * OpenFile (KERNEL.74)
776 HFILE OpenFile( LPCSTR name, OFSTRUCT *ofs, UINT mode )
778 int unixHandle;
779 HFILE handle;
781 dprintf_file( stddeb, "OpenFile %s \n",name);
782 if ((unixHandle = FILE_OpenFile( name, ofs, mode )) == -1)
783 return HFILE_ERROR;
784 if ((handle = FILE_AllocTaskHandle( unixHandle )) == HFILE_ERROR)
786 ofs->nErrCode = DOS_ExtendedError;
787 if (unixHandle) close( unixHandle );
789 if (!unixHandle) FILE_FreeTaskHandle( handle );
790 return handle;
794 /***********************************************************************
795 * _lclose (KERNEL.81)
797 HFILE _lclose( HFILE hFile )
799 int handle;
802 if ((handle = FILE_GetUnixTaskHandle( hFile )) == -1) return HFILE_ERROR;
803 dprintf_file( stddeb, "_lclose: doshandle %d unixhandle %d\n", hFile,handle );
804 if (handle <= 2)
806 fprintf( stderr, "_lclose: internal error: closing handle %d\n", handle );
807 exit(1);
809 FILE_FreeTaskHandle( hFile );
810 close( handle );
811 return 0;
815 /***********************************************************************
816 * _lread (KERNEL.82)
818 INT _lread( HFILE hFile, SEGPTR buffer, WORD count )
820 return (INT)_hread( hFile, buffer, (LONG)count );
824 /***********************************************************************
825 * _lcreat (KERNEL.83)
827 INT _lcreat( LPCSTR path, INT attr )
829 int unixHandle, mode;
830 HFILE handle;
832 dprintf_file( stddeb, "_lcreat: %s %02x\n", path, attr );
833 mode = (attr & 1) ? 0444 : 0666;
834 if ((unixHandle = FILE_Create( path, mode, FALSE )) == -1)
835 return HFILE_ERROR;
836 if ((handle = FILE_AllocTaskHandle( unixHandle )) == HFILE_ERROR)
837 close( unixHandle );
838 return handle;
842 /***********************************************************************
843 * _lcreat_uniq (Not a Windows API)
845 INT _lcreat_uniq( LPCSTR path, INT attr )
847 int unixHandle, mode;
848 HFILE handle;
850 dprintf_file( stddeb, "_lcreat: %s %02x\n", path, attr );
851 mode = (attr & 1) ? 0444 : 0666;
852 if ((unixHandle = FILE_Create( path, mode, TRUE )) == -1)
853 return HFILE_ERROR;
854 if ((handle = FILE_AllocTaskHandle( unixHandle )) == HFILE_ERROR)
855 close( unixHandle );
856 return handle;
860 /***********************************************************************
861 * _llseek (KERNEL.84)
863 LONG _llseek( HFILE hFile, LONG lOffset, INT nOrigin )
865 int handle, origin, result;
867 dprintf_file( stddeb, "_llseek: handle %d, offset %ld, origin %d\n",
868 hFile, lOffset, nOrigin);
870 if ((handle = FILE_GetUnixTaskHandle( hFile )) == -1) return HFILE_ERROR;
871 switch(nOrigin)
873 case 1: origin = SEEK_CUR; break;
874 case 2: origin = SEEK_END; break;
875 default: origin = SEEK_SET; break;
878 if ((result = lseek( handle, lOffset, origin )) == -1) FILE_SetDosError();
879 return (result == -1) ? HFILE_ERROR : result;
883 /***********************************************************************
884 * _lopen (KERNEL.85)
886 HFILE _lopen( LPCSTR path, INT mode )
888 int unixHandle;
889 int unixMode;
890 HFILE handle;
892 dprintf_file(stddeb, "_lopen('%s',%04x)\n", path, mode );
894 switch(mode & 3)
896 case OF_WRITE:
897 unixMode = O_WRONLY | O_TRUNC;
898 break;
899 case OF_READWRITE:
900 unixMode = O_RDWR;
901 break;
902 case OF_READ:
903 default:
904 unixMode = O_RDONLY;
905 break;
907 if ((unixHandle = FILE_Open( path, unixMode )) == -1) return HFILE_ERROR;
908 if ((handle = FILE_AllocTaskHandle( unixHandle )) == HFILE_ERROR)
909 close( unixHandle );
910 return handle;
914 /***********************************************************************
915 * _lwrite (KERNEL.86)
917 INT _lwrite( HFILE hFile, LPCSTR buffer, WORD count )
919 return (INT)_hwrite( hFile, buffer, (LONG)count );
923 /***********************************************************************
924 * _hread (KERNEL.349)
926 LONG _hread( HFILE hFile, SEGPTR buffer, LONG count )
928 #ifndef WINELIB
929 LONG maxlen;
931 dprintf_file( stddeb, "_hread: %d %08lx %ld\n",
932 hFile, (DWORD)buffer, count );
934 /* Some programs pass a count larger than the allocated buffer */
935 maxlen = GetSelectorLimit( SELECTOROF(buffer) ) - OFFSETOF(buffer) + 1;
936 if (count > maxlen) count = maxlen;
937 #endif
938 return FILE_Read( hFile, PTR_SEG_TO_LIN(buffer), count );
942 /***********************************************************************
943 * _hwrite (KERNEL.350)
945 LONG _hwrite( HFILE hFile, LPCSTR buffer, LONG count )
947 int handle;
948 LONG result;
950 dprintf_file( stddeb, "_hwrite: %d %p %ld\n", hFile, buffer, count );
952 if ((handle = FILE_GetUnixTaskHandle( hFile )) == -1) return HFILE_ERROR;
954 if (count == 0) /* Expand or truncate at current position */
955 result = ftruncate( handle, lseek( handle, 0, SEEK_CUR ) );
956 else
957 result = write( handle, buffer, count );
959 if (result == -1) FILE_SetDosError();
960 return (result == -1) ? HFILE_ERROR : result;
964 /***********************************************************************
965 * SetHandleCount (KERNEL.199)
967 WORD SetHandleCount( WORD count )
969 HANDLE hPDB = GetCurrentPDB();
970 PDB *pdb = (PDB *)GlobalLock( hPDB );
971 BYTE *files = PTR_SEG_TO_LIN( pdb->fileHandlesPtr );
972 WORD i;
974 dprintf_file( stddeb, "SetHandleCount(%d)\n", count );
976 if (count < 20) count = 20; /* No point in going below 20 */
977 else if (count > 254) count = 254;
979 /* If shrinking the table, make sure all extra file handles are closed */
980 if (count < pdb->nbFiles)
982 for (i = count; i < pdb->nbFiles; i++)
983 if (files[i] != 0xff) /* File open */
985 DOS_ERROR( ER_TooManyOpenFiles, EC_ProgramError,
986 SA_Abort, EL_Disk );
987 return pdb->nbFiles;
991 if (count == 20)
993 if (pdb->nbFiles > 20)
995 memcpy( pdb->fileHandles, files, 20 );
996 #ifdef WINELIB
997 GlobalFree( pdb->fileHandlesPtr );
998 pdb->fileHandlesPtr = pdb->fileHandles;
999 #else
1000 GlobalFree( GlobalHandle( SELECTOROF(pdb->fileHandlesPtr) ));
1001 pdb->fileHandlesPtr = (SEGPTR)MAKELONG( 0x18,
1002 GlobalHandleToSel( hPDB ) );
1003 #endif
1004 pdb->nbFiles = 20;
1007 else /* More than 20, need a new file handles table */
1009 BYTE *newfiles;
1010 HANDLE newhandle = GlobalAlloc( GMEM_MOVEABLE, count );
1011 if (!newhandle)
1013 DOS_ERROR( ER_OutOfMemory, EC_OutOfResource, SA_Abort, EL_Memory );
1014 return pdb->nbFiles;
1016 newfiles = (BYTE *)GlobalLock( newhandle );
1017 if (count > pdb->nbFiles)
1019 memcpy( newfiles, files, pdb->nbFiles );
1020 memset( newfiles + pdb->nbFiles, 0xff, count - pdb->nbFiles );
1022 else memcpy( newfiles, files, count );
1023 #ifdef WINELIB
1024 if (pdb->nbFiles > 20) GlobalFree( pdb->fileHandlesPtr );
1025 #else
1026 if (pdb->nbFiles > 20)
1027 GlobalFree( GlobalHandle( SELECTOROF(pdb->fileHandlesPtr) ));
1028 #endif
1029 pdb->fileHandlesPtr = WIN16_GlobalLock( newhandle );
1030 pdb->nbFiles = count;
1032 return pdb->nbFiles;