Release 960114
[wine/gsoc-2012-control.git] / files / file.c
blob19cc6fb7f5715cadddd72d03d50c4d1439e1c0b9
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"
30 /***********************************************************************
31 * FILE_SetDosError
33 * Set the DOS error code from errno.
35 void FILE_SetDosError(void)
37 switch (errno)
39 case EAGAIN:
40 DOS_ERROR( ER_ShareViolation, EC_Temporary, SA_Retry, EL_Disk );
41 break;
42 case EBADF:
43 DOS_ERROR( ER_InvalidHandle, EC_ProgramError, SA_Abort, EL_Disk );
44 break;
45 case ENOSPC:
46 DOS_ERROR( ER_DiskFull, EC_MediaError, SA_Abort, EL_Disk );
47 break;
48 case EACCES:
49 case EPERM:
50 case EROFS:
51 DOS_ERROR( ER_WriteProtected, EC_AccessDenied, SA_Abort, EL_Disk );
52 break;
53 case EBUSY:
54 DOS_ERROR( ER_LockViolation, EC_AccessDenied, SA_Abort, EL_Disk );
55 break;
56 case ENOENT:
57 DOS_ERROR( ER_FileNotFound, EC_NotFound, SA_Abort, EL_Disk );
58 break;
59 case EISDIR:
60 DOS_ERROR( ER_CanNotMakeDir, EC_AccessDenied, SA_Abort, EL_Unknown );
61 break;
62 case ENFILE:
63 case EMFILE:
64 DOS_ERROR( ER_NoMoreFiles, EC_MediaError, SA_Abort, EL_Unknown );
65 break;
66 case EEXIST:
67 DOS_ERROR( ER_FileExists, EC_Exists, SA_Abort, EL_Disk );
68 break;
69 default:
70 perror( "int21: unknown errno" );
71 DOS_ERROR( ER_GeneralFailure, EC_SystemFailure, SA_Abort, EL_Unknown );
72 break;
77 /***********************************************************************
78 * FILE_AllocTaskHandle
80 * Allocate a DOS file handle for the current task.
82 static HFILE FILE_AllocTaskHandle( int handle )
84 PDB *pdb = (PDB *)GlobalLock( GetCurrentPDB() );
85 BYTE *files, *fp;
86 WORD i;
88 if (!pdb)
90 fprintf(stderr,"FILE_MakeTaskHandle: internal error, no current PDB.\n");
91 exit(1);
93 fp = files = PTR_SEG_TO_LIN( pdb->fileHandlesPtr );
94 for (i = pdb->nbFiles; (i > 0) && (*fp != 0xff); i--, fp++);
95 if (!i || (handle >= 0xff)) /* No more handles */
97 DOS_ERROR( ER_TooManyOpenFiles, EC_ProgramError, SA_Abort, EL_Disk );
98 return -1;
100 *fp = (BYTE)handle;
101 return (HFILE)(fp - files);
105 /***********************************************************************
106 * FILE_FreeTaskHandle
108 * Free a DOS file handle for the current task.
110 static void FILE_FreeTaskHandle( HFILE handle )
112 PDB *pdb = (PDB *)GlobalLock( GetCurrentPDB() );
113 BYTE *files;
115 if (!pdb)
117 fprintf(stderr,"FILE_FreeTaskHandle: internal error, no current PDB.\n");
118 exit(1);
120 files = PTR_SEG_TO_LIN( pdb->fileHandlesPtr );
121 if ((handle<0) || (handle >= (INT)pdb->nbFiles) || (files[handle] == 0xff))
123 fprintf( stderr, "FILE_FreeTaskHandle: invalid file handle %d\n",
124 handle );
125 return;
127 files[handle] = 0xff;
131 /***********************************************************************
132 * FILE_GetUnixHandle
134 * Return the Unix file handle associated to a DOS file handle.
136 int FILE_GetUnixHandle( HFILE handle )
138 PDB *pdb = (PDB *)GlobalLock( GetCurrentPDB() );
139 BYTE *files;
141 if (!pdb)
143 fprintf(stderr,"FILE_GetUnixHandle: internal error, no current PDB.\n");
144 exit(1);
146 files = PTR_SEG_TO_LIN( pdb->fileHandlesPtr );
147 if ((handle<0) || (handle >= (INT)pdb->nbFiles) || (files[handle] == 0xff))
149 DOS_ERROR( ER_InvalidHandle, EC_ProgramError, SA_Abort, EL_Disk );
150 return -1;
152 return (int)files[handle];
156 /***********************************************************************
157 * FILE_CloseAllFiles
159 * Close all open files of a given PDB. Used on task termination.
161 void FILE_CloseAllFiles( HANDLE hPDB )
163 BYTE *files;
164 WORD count;
165 PDB *pdb = (PDB *)GlobalLock( hPDB );
167 if (!pdb) return;
168 files = PTR_SEG_TO_LIN( pdb->fileHandlesPtr );
169 for (count = pdb->nbFiles; count > 0; count--, files++)
171 if (*files != 0xff)
173 close( (int)*files );
174 *files = 0xff;
180 /***********************************************************************
181 * FILE_Open
183 int FILE_Open( LPCSTR path, int mode )
185 const char *unixName;
186 int handle;
188 dprintf_file(stddeb, "FILE_Open: '%s' %04x\n", path, mode );
189 if ((unixName = DOSFS_IsDevice( path )) != NULL)
191 dprintf_file( stddeb, "FILE_Open: opening device '%s'\n", unixName );
192 if (!unixName[0]) /* Non-existing device */
194 DOS_ERROR( ER_FileNotFound, EC_NotFound, SA_Abort, EL_Disk );
195 return -1;
197 handle = open( unixName, mode );
199 else
201 if (!(unixName = DOSFS_GetUnixFileName( path, TRUE ))) return -1;
203 if ((handle = open( unixName, mode )) == -1)
205 if (Options.allowReadOnly && (mode == O_RDWR))
207 if ((handle = open( unixName, O_RDONLY )) != -1)
208 fprintf( stderr, "Warning: could not open %s for writing, opening read-only.\n", unixName );
212 if (handle == -1) FILE_SetDosError();
213 return handle;
217 /***********************************************************************
218 * FILE_Create
220 int FILE_Create( LPCSTR path, int mode, int unique )
222 const char *unixName;
223 int handle;
225 dprintf_file(stddeb, "FILE_Create: '%s' %04x %d\n", path, mode, unique );
227 if ((unixName = DOSFS_IsDevice( path )) != NULL)
229 dprintf_file(stddeb, "FILE_Create: creating device '%s'!\n", unixName);
230 DOS_ERROR( ER_AccessDenied, EC_NotFound, SA_Abort, EL_Disk );
231 return -1;
234 if (!(unixName = DOSFS_GetUnixFileName( path, FALSE ))) return -1;
235 if ((handle = open( unixName,
236 O_CREAT | O_TRUNC | O_RDWR | (unique ? O_EXCL : 0),
237 mode )) == -1)
238 FILE_SetDosError();
239 return handle;
243 /***********************************************************************
244 * FILE_Unlink
246 int FILE_Unlink( LPCSTR path )
248 const char *unixName;
250 dprintf_file(stddeb, "FILE_Unlink: '%s'\n", path );
252 if ((unixName = DOSFS_IsDevice( path )) != NULL)
254 dprintf_file(stddeb, "FILE_Unlink: removing device '%s'!\n", unixName);
255 DOS_ERROR( ER_FileNotFound, EC_NotFound, SA_Abort, EL_Disk );
256 return 0;
259 if (!(unixName = DOSFS_GetUnixFileName( path, TRUE ))) return 0;
260 if (unlink( unixName ) == -1)
262 FILE_SetDosError();
263 return 0;
265 return 1;
269 /***********************************************************************
270 * FILE_Stat
272 * Stat a Unix path name. Return 1 if OK.
274 int FILE_Stat( LPCSTR unixName, BYTE *pattr, DWORD *psize,
275 WORD *pdate, WORD *ptime )
277 struct stat st;
279 if (stat( unixName, &st ) == -1)
281 FILE_SetDosError();
282 return 0;
284 if (pattr) *pattr = FA_ARCHIVE | (S_ISDIR(st.st_mode) ? FA_DIRECTORY : 0);
285 if (psize) *psize = st.st_size;
286 DOSFS_ToDosDateTime( &st.st_mtime, pdate, ptime );
287 return 1;
291 /***********************************************************************
292 * FILE_Fstat
294 * Stat a DOS handle. Return 1 if OK.
296 int FILE_Fstat( HFILE hFile, BYTE *pattr, DWORD *psize,
297 WORD *pdate, WORD *ptime )
299 struct stat st;
300 int handle;
302 if ((handle = FILE_GetUnixHandle( hFile )) == -1) return 0;
303 if (fstat( handle, &st ) == -1)
305 FILE_SetDosError();
306 return 0;
308 if (pattr) *pattr = FA_ARCHIVE | (S_ISDIR(st.st_mode) ? FA_DIRECTORY : 0);
309 if (psize) *psize = st.st_size;
310 DOSFS_ToDosDateTime( &st.st_mtime, pdate, ptime );
311 return 1;
315 /***********************************************************************
316 * FILE_MakeDir
318 int FILE_MakeDir( LPCSTR path )
320 const char *unixName;
322 dprintf_file(stddeb, "FILE_MakeDir: '%s'\n", path );
324 if ((unixName = DOSFS_IsDevice( path )) != NULL)
326 dprintf_file(stddeb, "FILE_MakeDir: device '%s'!\n", unixName);
327 DOS_ERROR( ER_AccessDenied, EC_AccessDenied, SA_Abort, EL_Disk );
328 return 0;
330 if (!(unixName = DOSFS_GetUnixFileName( path, TRUE ))) return 0;
331 if ((mkdir( unixName, 0777 ) == -1) && (errno != EEXIST))
333 FILE_SetDosError();
334 return 0;
336 return 1;
340 /***********************************************************************
341 * FILE_RemoveDir
343 int FILE_RemoveDir( LPCSTR path )
345 const char *unixName;
347 dprintf_file(stddeb, "FILE_RemoveDir: '%s'\n", path );
349 if ((unixName = DOSFS_IsDevice( path )) != NULL)
351 dprintf_file(stddeb, "FILE_RemoveDir: device '%s'!\n", unixName);
352 DOS_ERROR( ER_FileNotFound, EC_NotFound, SA_Abort, EL_Disk );
353 return 0;
355 if (!(unixName = DOSFS_GetUnixFileName( path, TRUE ))) return 0;
356 if (rmdir( unixName ) == -1)
358 FILE_SetDosError();
359 return 0;
361 return 1;
365 /***********************************************************************
366 * FILE_Dup
368 * dup() function for DOS handles.
370 HFILE FILE_Dup( HFILE hFile )
372 int handle, newhandle;
373 HFILE dosHandle;
375 if ((handle = FILE_GetUnixHandle( hFile )) == -1) return HFILE_ERROR;
376 if ((newhandle = dup(handle)) == -1)
378 FILE_SetDosError();
379 return HFILE_ERROR;
381 if ((dosHandle = FILE_AllocTaskHandle( newhandle )) == HFILE_ERROR)
382 close( newhandle );
383 return dosHandle;
387 /***********************************************************************
388 * FILE_Dup2
390 * dup2() function for DOS handles.
392 HFILE FILE_Dup2( HFILE hFile1, HFILE hFile2 )
394 PDB *pdb = (PDB *)GlobalLock( GetCurrentPDB() );
395 BYTE *files;
396 int handle, newhandle;
398 if ((handle = FILE_GetUnixHandle( hFile1 )) == -1) return HFILE_ERROR;
399 if ((hFile2 < 0) || (hFile2 >= (INT)pdb->nbFiles))
401 DOS_ERROR( ER_InvalidHandle, EC_ProgramError, SA_Abort, EL_Disk );
402 return HFILE_ERROR;
405 if ((newhandle = dup(handle)) == -1)
407 FILE_SetDosError();
408 return HFILE_ERROR;
410 if (newhandle >= 0xff)
412 DOS_ERROR( ER_TooManyOpenFiles, EC_ProgramError, SA_Abort, EL_Disk );
413 close( newhandle );
414 return HFILE_ERROR;
416 files = PTR_SEG_TO_LIN( pdb->fileHandlesPtr );
417 if (files[hFile2] != 0xff) close( files[hFile2] );
418 files[hFile2] = (BYTE)newhandle;
419 return hFile2;
423 /***********************************************************************
424 * FILE_OpenFile
426 * Implementation of API function OpenFile(). Returns a Unix file handle.
428 int FILE_OpenFile( LPCSTR name, OFSTRUCT *ofs, UINT mode )
430 const char *unixName, *dosName;
431 char *p;
432 int handle, len, i, unixMode;
433 struct stat st;
435 ofs->cBytes = sizeof(OFSTRUCT);
436 ofs->nErrCode = 0;
437 if (mode & OF_REOPEN) name = ofs->szPathName;
438 dprintf_file( stddeb, "Openfile: %s %04x\n", name, mode );
440 /* OF_PARSE simply fills the structure */
442 if (mode & OF_PARSE)
444 if (!(dosName = DOSFS_GetDosTrueName( name, FALSE )))
446 ofs->nErrCode = DOS_ExtendedError;
447 return -1;
449 lstrcpyn( ofs->szPathName, dosName, sizeof(ofs->szPathName) );
450 ofs->fFixedDisk = (GetDriveType( dosName[0]-'A' ) != DRIVE_REMOVABLE);
451 return 0;
454 /* OF_CREATE is completely different from all other options, so
455 handle it first */
457 if (mode & OF_CREATE)
459 if ((unixName = DOSFS_GetUnixFileName( name, FALSE )) == NULL)
461 ofs->nErrCode = DOS_ExtendedError;
462 return -1;
464 dprintf_file( stddeb, "OpenFile: creating '%s'\n", unixName );
465 handle = open( unixName, O_TRUNC | O_RDWR | O_CREAT, 0666 );
466 if (handle == -1)
468 FILE_SetDosError();
469 ofs->nErrCode = DOS_ExtendedError;
470 return -1;
472 lstrcpyn( ofs->szPathName, DOSFS_GetDosTrueName( name, FALSE ),
473 sizeof(ofs->szPathName) );
474 return handle;
477 /* Now look for the file */
479 /* First try the current directory */
481 lstrcpyn( ofs->szPathName, name, sizeof(ofs->szPathName) );
482 if ((unixName = DOSFS_GetUnixFileName( ofs->szPathName, TRUE )) != NULL)
483 goto found;
485 /* Now try some different paths if none was specified */
487 if ((mode & OF_SEARCH) && !(mode & OF_REOPEN))
489 if (name[1] == ':') name += 2;
490 if ((p = strrchr( name, '\\' ))) name = p + 1;
491 if ((p = strrchr( name, '/' ))) name = p + 1;
492 if (!name[0]) goto not_found;
494 else
496 if ((name[1] == ':') || strchr( name, '/' ) || strchr( name, '\\' ))
497 goto not_found;
500 if ((len = sizeof(ofs->szPathName) - strlen(name) - 1) < 0) goto not_found;
502 /* Try the Windows directory */
504 GetWindowsDirectory( ofs->szPathName, len );
505 strcat( ofs->szPathName, "\\" );
506 strcat( ofs->szPathName, name );
507 if ((unixName = DOSFS_GetUnixFileName( ofs->szPathName, TRUE )) != NULL)
508 goto found;
510 /* Try the Windows system directory */
512 GetSystemDirectory( ofs->szPathName, len );
513 strcat( ofs->szPathName, "\\" );
514 strcat( ofs->szPathName, name );
515 if ((unixName = DOSFS_GetUnixFileName( ofs->szPathName, TRUE )) != NULL)
516 goto found;
518 /* Try the path of the current executable */
520 if (GetCurrentTask())
522 GetModuleFileName( GetCurrentTask(), ofs->szPathName, len );
523 if ((p = strrchr( ofs->szPathName, '\\' )))
525 strcpy( p + 1, name );
526 if ((unixName = DOSFS_GetUnixFileName( ofs->szPathName, TRUE )))
527 goto found;
531 /* Try all directories in path */
533 for (i = 0; ; i++)
535 if (!DIR_GetDosPath( i, ofs->szPathName, len )) break;
536 strcat( ofs->szPathName, "\\" );
537 strcat( ofs->szPathName, name );
538 if ((unixName = DOSFS_GetUnixFileName( ofs->szPathName, TRUE)) != NULL)
539 goto found;
542 not_found:
543 dprintf_file( stddeb, "OpenFile: '%s' not found\n", name );
544 DOS_ERROR( ER_FileNotFound, EC_NotFound, SA_Abort, EL_Disk );
545 ofs->nErrCode = ER_FileNotFound;
546 return -1;
548 found:
549 dprintf_file( stddeb, "OpenFile: found '%s'\n", unixName );
550 lstrcpyn( ofs->szPathName, DOSFS_GetDosTrueName( ofs->szPathName, FALSE ),
551 sizeof(ofs->szPathName) );
553 if (mode & OF_PARSE) return 0;
555 if (mode & OF_DELETE)
557 if (unlink( unixName ) == -1) goto not_found;
558 return 0;
561 switch(mode & 3)
563 case OF_WRITE:
564 unixMode = O_WRONLY; break;
565 case OF_READWRITE:
566 unixMode = O_RDWR; break;
567 case OF_READ:
568 default:
569 unixMode = O_RDONLY; break;
572 if ((handle = open( unixName, unixMode )) == -1)
574 if (Options.allowReadOnly && (unixMode == O_RDWR))
576 if ((handle = open( unixName, O_RDONLY )) != -1)
577 fprintf( stderr, "Warning: could not open %s for writing, opening read-only.\n", unixName );
580 if (handle == -1) goto not_found;
582 if (fstat( handle, &st ) != -1)
584 if ((mode & OF_VERIFY) && (mode & OF_REOPEN))
586 if (memcmp( ofs->reserved, &st.st_mtime, sizeof(ofs->reserved) ))
587 return -1;
589 memcpy( ofs->reserved, &st.st_mtime, sizeof(ofs->reserved) );
592 if (mode & OF_EXIST) close( handle );
594 return handle;
598 /***********************************************************************
599 * GetTempFileName (KERNEL.97)
601 INT GetTempFileName( BYTE drive, LPCSTR prefix, UINT unique, LPSTR buffer )
603 int i, handle;
604 UINT num = unique ? (unique & 0xffff) : time(NULL) & 0xffff;
605 char *p;
607 if (drive & TF_FORCEDRIVE)
609 sprintf( buffer, "%c:", drive & ~TF_FORCEDRIVE );
611 else
613 DIR_GetTempDosDir( buffer, 132 ); /* buffer must be at least 144 */
614 strcat( buffer, "\\" );
617 p = buffer + strlen(buffer);
618 for (i = 3; (i > 0) && (*prefix); i--) *p++ = *prefix++;
619 sprintf( p, "%04x.tmp", num );
621 if (unique)
623 lstrcpyn( buffer, DOSFS_GetDosTrueName( buffer, FALSE ), 144 );
624 dprintf_file( stddeb, "GetTempFileName: returning %s\n", buffer );
625 return unique;
628 /* Now try to create it */
632 if ((handle = FILE_Create( buffer, 0666, TRUE )) != -1)
633 { /* We created it */
634 dprintf_file( stddeb, "GetTempFileName: created %s\n", buffer );
635 close( handle );
636 break;
638 if (DOS_ExtendedError != ER_FileExists) break; /* No need to go on */
639 num++;
640 sprintf( p, "%04x.tmp", num );
641 } while (num != (unique & 0xffff));
643 lstrcpyn( buffer, DOSFS_GetDosTrueName( buffer, FALSE ), 144 );
644 dprintf_file( stddeb, "GetTempFileName: returning %s\n", buffer );
645 return num;
649 /***********************************************************************
650 * OpenFile (KERNEL.74)
652 HFILE OpenFile( LPCSTR name, OFSTRUCT *ofs, UINT mode )
654 int unixHandle;
655 HFILE handle;
657 if ((unixHandle = FILE_OpenFile( name, ofs, mode )) == -1)
658 return HFILE_ERROR;
659 if ((handle = FILE_AllocTaskHandle( unixHandle )) == HFILE_ERROR)
661 ofs->nErrCode = DOS_ExtendedError;
662 if (unixHandle) close( unixHandle );
664 if (!unixHandle) FILE_FreeTaskHandle( handle );
665 return handle;
669 /***********************************************************************
670 * _lclose (KERNEL.81)
672 HFILE _lclose( HFILE hFile )
674 int handle;
676 dprintf_file( stddeb, "_lclose: handle %d\n", hFile );
678 if ((handle = FILE_GetUnixHandle( hFile )) == -1) return HFILE_ERROR;
679 if (handle <= 2)
681 fprintf( stderr, "_lclose: internal error: closing handle %d\n", handle );
682 exit(1);
684 FILE_FreeTaskHandle( hFile );
685 close( handle );
686 return 0;
690 /***********************************************************************
691 * _lread (KERNEL.82)
693 INT _lread( HFILE hFile, LPSTR buffer, WORD count )
695 return (INT)_hread( hFile, buffer, (LONG)count );
699 /***********************************************************************
700 * _lcreat (KERNEL.83)
702 INT _lcreat( LPCSTR path, INT attr )
704 int unixHandle, mode;
705 HFILE handle;
707 dprintf_file( stddeb, "_lcreat: %s %02x\n", path, attr );
708 mode = (attr & 1) ? 0444 : 0666;
709 if ((unixHandle = FILE_Create( path, mode, FALSE )) == -1)
710 return HFILE_ERROR;
711 if ((handle = FILE_AllocTaskHandle( unixHandle )) == HFILE_ERROR)
712 close( unixHandle );
713 return handle;
717 /***********************************************************************
718 * _lcreat_uniq (Not a Windows API)
720 INT _lcreat_uniq( LPCSTR path, INT attr )
722 int unixHandle, mode;
723 HFILE handle;
725 dprintf_file( stddeb, "_lcreat: %s %02x\n", path, attr );
726 mode = (attr & 1) ? 0444 : 0666;
727 if ((unixHandle = FILE_Create( path, mode, TRUE )) == -1)
728 return HFILE_ERROR;
729 if ((handle = FILE_AllocTaskHandle( unixHandle )) == HFILE_ERROR)
730 close( unixHandle );
731 return handle;
735 /***********************************************************************
736 * _llseek (KERNEL.84)
738 LONG _llseek( HFILE hFile, LONG lOffset, INT nOrigin )
740 int handle, origin, result;
742 dprintf_file( stddeb, "_llseek: handle %d, offset %ld, origin %d\n",
743 hFile, lOffset, nOrigin);
745 if ((handle = FILE_GetUnixHandle( hFile )) == -1) return HFILE_ERROR;
746 switch(nOrigin)
748 case 1: origin = SEEK_CUR; break;
749 case 2: origin = SEEK_END; break;
750 default: origin = SEEK_SET; break;
753 if ((result = lseek( handle, lOffset, origin )) == -1) FILE_SetDosError();
754 return (result == -1) ? HFILE_ERROR : result;
758 /***********************************************************************
759 * _lopen (KERNEL.85)
761 HFILE _lopen( LPCSTR path, INT mode )
763 int unixHandle;
764 int unixMode;
765 HFILE handle;
767 dprintf_file(stddeb, "_lopen('%s',%04x)\n", path, mode );
769 switch(mode & 3)
771 case OF_WRITE:
772 unixMode = O_WRONLY | O_TRUNC;
773 break;
774 case OF_READWRITE:
775 unixMode = O_RDWR;
776 break;
777 case OF_READ:
778 default:
779 unixMode = O_RDONLY;
780 break;
782 if ((unixHandle = FILE_Open( path, unixMode )) == -1) return HFILE_ERROR;
783 if ((handle = FILE_AllocTaskHandle( unixHandle )) == HFILE_ERROR)
784 close( unixHandle );
785 return handle;
789 /***********************************************************************
790 * _lwrite (KERNEL.86)
792 INT _lwrite( HFILE hFile, LPCSTR buffer, WORD count )
794 return (INT)_hwrite( hFile, buffer, (LONG)count );
798 /***********************************************************************
799 * _hread (KERNEL.349)
801 LONG _hread( HFILE hFile, LPSTR buffer, LONG count )
803 int handle;
804 LONG result;
806 dprintf_file( stddeb, "_hread: %d %p %ld\n", hFile, buffer, count );
808 if ((handle = FILE_GetUnixHandle( hFile )) == -1) return HFILE_ERROR;
809 if (!count) return 0;
810 if ((result = read( handle, buffer, count )) == -1) FILE_SetDosError();
811 return (result == -1) ? HFILE_ERROR : result;
815 /***********************************************************************
816 * _hwrite (KERNEL.350)
818 LONG _hwrite( HFILE hFile, LPCSTR buffer, LONG count )
820 int handle;
821 LONG result;
823 dprintf_file( stddeb, "_hwrite: %d %p %ld\n", hFile, buffer, count );
825 if ((handle = FILE_GetUnixHandle( hFile )) == -1) return HFILE_ERROR;
827 if (count == 0) /* Expand or truncate at current position */
828 result = ftruncate( handle, lseek( handle, 0, SEEK_CUR ) );
829 else
830 result = write( handle, buffer, count );
832 if (result == -1) FILE_SetDosError();
833 return (result == -1) ? HFILE_ERROR : result;
837 /***********************************************************************
838 * SetHandleCount (KERNEL.199)
840 WORD SetHandleCount( WORD count )
842 HANDLE hPDB = GetCurrentPDB();
843 PDB *pdb = (PDB *)GlobalLock( hPDB );
844 BYTE *files = PTR_SEG_TO_LIN( pdb->fileHandlesPtr );
845 WORD i;
847 dprintf_file( stddeb, "SetHandleCount(%d)\n", count );
849 if (count < 20) count = 20; /* No point in going below 20 */
850 else if (count > 254) count = 254;
852 /* If shrinking the table, make sure all extra file handles are closed */
853 if (count < pdb->nbFiles)
855 for (i = count; i < pdb->nbFiles; i++)
856 if (files[i] != 0xff) /* File open */
858 DOS_ERROR( ER_TooManyOpenFiles, EC_ProgramError,
859 SA_Abort, EL_Disk );
860 return pdb->nbFiles;
864 if (count == 20)
866 if (pdb->nbFiles > 20)
868 memcpy( pdb->fileHandles, files, 20 );
869 #ifdef WINELIB
870 GlobalFree( pdb->fileHandlesPtr );
871 pdb->fileHandlesPtr = pdb->fileHandles;
872 #else
873 GlobalFree( GlobalHandle( SELECTOROF(pdb->fileHandlesPtr) ));
874 pdb->fileHandlesPtr = (SEGPTR)MAKELONG( 0x18,
875 GlobalHandleToSel( hPDB ) );
876 #endif
877 pdb->nbFiles = 20;
880 else /* More than 20, need a new file handles table */
882 BYTE *newfiles;
883 HANDLE newhandle = GlobalAlloc( GMEM_MOVEABLE, count );
884 if (!newhandle)
886 DOS_ERROR( ER_OutOfMemory, EC_OutOfResource, SA_Abort, EL_Memory );
887 return pdb->nbFiles;
889 newfiles = (BYTE *)GlobalLock( newhandle );
890 if (count > pdb->nbFiles)
892 memcpy( newfiles, files, pdb->nbFiles );
893 memset( newfiles + pdb->nbFiles, 0xff, count - pdb->nbFiles );
895 else memcpy( newfiles, files, count );
896 #ifdef WINELIB
897 if (pdb->nbFiles > 20) GlobalFree( pdb->fileHandlesPtr );
898 #else
899 if (pdb->nbFiles > 20)
900 GlobalFree( GlobalHandle( SELECTOROF(pdb->fileHandlesPtr) ));
901 #endif
902 pdb->fileHandlesPtr = WIN16_GlobalLock( newhandle );
903 pdb->nbFiles = count;
905 return pdb->nbFiles;