Group commit for recovery after disk crash.
See Changelog for changes WRT release 990110.

diff --git a/files/file.c b/files/file.c
index fddb304..2cfe9e2 100644
--- a/files/file.c
+++ b/files/file.c
@@ -67,6 +67,8 @@
 static DOS_FILE_LOCK *locks = NULL;
 static void DOS_RemoveFileLocks(FILE_OBJECT *file);
 
+/* Size of per-process table of DOS handles */
+#define DOS_TABLE_SIZE 256
 
 
 /***********************************************************************
@@ -421,13 +423,18 @@
     /* If write access failed, retry without GENERIC_WRITE */
 
     if ((reply.handle == -1) && !Options.failReadOnly &&
-        (access & GENERIC_WRITE) && (GetLastError() == ERROR_ACCESS_DENIED))
+        (access & GENERIC_WRITE)) 
     {
-        req.access &= ~GENERIC_WRITE;
-        CLIENT_SendRequest( REQ_CREATE_FILE, -1, 2,
-                            &req, sizeof(req),
-                            filename, strlen(filename) + 1 );
-        CLIENT_WaitSimpleReply( &reply, sizeof(reply), NULL );
+    	DWORD lasterror = GetLastError();
+	if ((lasterror == ERROR_ACCESS_DENIED) || 
+	    (lasterror == ERROR_WRITE_PROTECT))
+        {
+	    req.access &= ~GENERIC_WRITE;
+	    CLIENT_SendRequest( REQ_CREATE_FILE, -1, 2,
+				&req, sizeof(req),
+				filename, strlen(filename) + 1 );
+	    CLIENT_WaitSimpleReply( &reply, sizeof(reply), NULL );
+	}
     }
     if (reply.handle == -1) return INVALID_HANDLE_VALUE32;
 
@@ -730,25 +737,6 @@
 
 
 /***********************************************************************
- *           FILE_Dup2
- *
- * dup2() function for DOS handles.
- */
-HFILE32 FILE_Dup2( HFILE32 hFile1, HFILE32 hFile2 )
-{
-    FILE_OBJECT *file;
-
-    TRACE(file, "FILE_Dup2 for handle %d\n", hFile1 );
-    /* FIXME: should use DuplicateHandle */
-    if (!(file = FILE_GetFile( hFile1, 0, NULL ))) return HFILE_ERROR32;
-    if (!HANDLE_SetObjPtr( PROCESS_Current(), hFile2, &file->header, 0 ))
-        hFile2 = HFILE_ERROR32;
-    FILE_ReleaseFile( file );
-    return hFile2;
-}
-
-
-/***********************************************************************
  *           GetTempFileName16   (KERNEL.97)
  */
 UINT16 WINAPI GetTempFileName16( BYTE drive, LPCSTR prefix, UINT16 unique,
@@ -1014,7 +1002,7 @@
 HFILE16 WINAPI OpenFile16( LPCSTR name, OFSTRUCT *ofs, UINT16 mode )
 {
     TRACE(file,"OpenFile16(%s,%i)\n", name, mode);
-    return HFILE32_TO_HFILE16(FILE_DoOpenFile( name, ofs, mode, FALSE ));
+    return FILE_AllocDosHandle( FILE_DoOpenFile( name, ofs, mode, FALSE ) );
 }
 
 
@@ -1028,12 +1016,117 @@
 
 
 /***********************************************************************
+ *           FILE_AllocDosHandle
+ *
+ * Allocate a DOS handle for a Win32 handle. The Win32 handle is no
+ * longer valid after this function (even on failure).
+ */
+HFILE16 FILE_AllocDosHandle( HANDLE32 handle )
+{
+    int i;
+    HANDLE32 *ptr = PROCESS_Current()->dos_handles;
+
+    if (!handle || (handle == INVALID_HANDLE_VALUE32))
+        return INVALID_HANDLE_VALUE16;
+
+    if (!ptr)
+    {
+        if (!(ptr = HeapAlloc( SystemHeap, HEAP_ZERO_MEMORY,
+                               sizeof(*ptr) * DOS_TABLE_SIZE )))
+            goto error;
+        PROCESS_Current()->dos_handles = ptr;
+        ptr[0] = GetStdHandle(STD_INPUT_HANDLE);
+        ptr[1] = GetStdHandle(STD_OUTPUT_HANDLE);
+        ptr[2] = GetStdHandle(STD_ERROR_HANDLE);
+        ptr[3] = GetStdHandle(STD_ERROR_HANDLE);
+        ptr[4] = GetStdHandle(STD_ERROR_HANDLE);
+    }
+
+    for (i = 0; i < DOS_TABLE_SIZE; i++, ptr++)
+        if (!*ptr)
+        {
+            *ptr = handle;
+            TRACE( file, "Got %d for h32 %d\n", i, handle );
+            return i;
+        }
+error:
+    DOS_ERROR( ER_TooManyOpenFiles, EC_ProgramError, SA_Abort, EL_Disk );
+    CloseHandle( handle );
+    return INVALID_HANDLE_VALUE16;
+}
+
+
+/***********************************************************************
+ *           FILE_GetHandle32
+ *
+ * Return the Win32 handle for a DOS handle.
+ */
+HANDLE32 FILE_GetHandle32( HFILE16 hfile )
+{
+    HANDLE32 *table = PROCESS_Current()->dos_handles;
+    if ((hfile >= DOS_TABLE_SIZE) || !table || !table[hfile])
+    {
+        DOS_ERROR( ER_InvalidHandle, EC_ProgramError, SA_Abort, EL_Disk );
+        return INVALID_HANDLE_VALUE32;
+    }
+    return table[hfile];
+}
+
+
+/***********************************************************************
+ *           FILE_Dup2
+ *
+ * dup2() function for DOS handles.
+ */
+HFILE16 FILE_Dup2( HFILE16 hFile1, HFILE16 hFile2 )
+{
+    HANDLE32 *table = PROCESS_Current()->dos_handles;
+    HANDLE32 new_handle;
+
+    if ((hFile1 >= DOS_TABLE_SIZE) || (hFile2 >= DOS_TABLE_SIZE) ||
+        !table || !table[hFile1])
+    {
+        DOS_ERROR( ER_InvalidHandle, EC_ProgramError, SA_Abort, EL_Disk );
+        return HFILE_ERROR16;
+    }
+    if (hFile2 < 5)
+    {
+        FIXME( file, "stdio handle closed, need proper conversion\n" );
+        DOS_ERROR( ER_InvalidHandle, EC_ProgramError, SA_Abort, EL_Disk );
+        return HFILE_ERROR16;
+    }
+    if (!DuplicateHandle( GetCurrentProcess(), table[hFile1],
+                          GetCurrentProcess(), &new_handle,
+                          0, FALSE, DUPLICATE_SAME_ACCESS ))
+        return HFILE_ERROR16;
+    if (table[hFile2]) CloseHandle( table[hFile2] );
+    table[hFile2] = new_handle;
+    return hFile2;
+}
+
+
+/***********************************************************************
  *           _lclose16   (KERNEL.81)
  */
 HFILE16 WINAPI _lclose16( HFILE16 hFile )
 {
-    TRACE(file, "handle %d\n", hFile );
-    return CloseHandle( HFILE16_TO_HFILE32( hFile )  ) ? 0 : HFILE_ERROR16;
+    HANDLE32 *table = PROCESS_Current()->dos_handles;
+
+    if (hFile < 5)
+    {
+        FIXME( file, "stdio handle closed, need proper conversion\n" );
+        DOS_ERROR( ER_InvalidHandle, EC_ProgramError, SA_Abort, EL_Disk );
+        return HFILE_ERROR16;
+    }
+    if ((hFile >= DOS_TABLE_SIZE) || !table || !table[hFile])
+    {
+        DOS_ERROR( ER_InvalidHandle, EC_ProgramError, SA_Abort, EL_Disk );
+        return HFILE_ERROR16;
+    }
+    TRACE( file, "%d (handle32=%d)\n", hFile, table[hFile] );
+    CloseHandle( table[hFile] );
+    table[hFile] = 0;
+    return 0;
 }
 
 
@@ -1126,7 +1219,7 @@
     /* Some programs pass a count larger than the allocated buffer */
     maxlen = GetSelectorLimit( SELECTOROF(buffer) ) - OFFSETOF(buffer) + 1;
     if (count > maxlen) count = maxlen;
-    return _lread32(HFILE16_TO_HFILE32(hFile), PTR_SEG_TO_LIN(buffer), count );
+    return _lread32(FILE_GetHandle32(hFile), PTR_SEG_TO_LIN(buffer), count );
 }
 
 
@@ -1155,7 +1248,7 @@
  */
 UINT16 WINAPI _lread16( HFILE16 hFile, LPVOID buffer, UINT16 count )
 {
-    return (UINT16)_lread32(HFILE16_TO_HFILE32(hFile), buffer, (LONG)count );
+    return (UINT16)_lread32(FILE_GetHandle32(hFile), buffer, (LONG)count );
 }
 
 
@@ -1165,7 +1258,7 @@
 HFILE16 WINAPI _lcreat16( LPCSTR path, INT16 attr )
 {
     TRACE(file, "%s %02x\n", path, attr );
-    return (HFILE16) HFILE32_TO_HFILE16(_lcreat32( path, attr ));
+    return FILE_AllocDosHandle( _lcreat32( path, attr ) );
 }
 
 
@@ -1182,14 +1275,14 @@
 
 
 /***********************************************************************
- *           _lcreat_uniq   (Not a Windows API)
+ *           _lcreat16_uniq   (Not a Windows API)
  */
-HFILE32 _lcreat_uniq( LPCSTR path, INT32 attr )
+HFILE16 _lcreat16_uniq( LPCSTR path, INT32 attr )
 {
     TRACE(file, "%s %02x\n", path, attr );
-    return CreateFile32A( path, GENERIC_READ | GENERIC_WRITE,
-                          FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
-                          CREATE_NEW, attr, -1 );
+    return FILE_AllocDosHandle( CreateFile32A( path, GENERIC_READ | GENERIC_WRITE,
+                                               FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
+                                               CREATE_NEW, attr, -1 ));
 }
 
 
@@ -1236,7 +1329,7 @@
  */
 LONG WINAPI _llseek16( HFILE16 hFile, LONG lOffset, INT16 nOrigin )
 {
-    return SetFilePointer( HFILE16_TO_HFILE32(hFile), lOffset, NULL, nOrigin );
+    return SetFilePointer( FILE_GetHandle32(hFile), lOffset, NULL, nOrigin );
 }
 
 
@@ -1254,7 +1347,7 @@
  */
 HFILE16 WINAPI _lopen16( LPCSTR path, INT16 mode )
 {
-    return HFILE32_TO_HFILE16(_lopen32( path, mode ));
+    return FILE_AllocDosHandle( _lopen32( path, mode ) );
 }
 
 
@@ -1276,7 +1369,7 @@
  */
 UINT16 WINAPI _lwrite16( HFILE16 hFile, LPCSTR buffer, UINT16 count )
 {
-    return (UINT16)_hwrite32( HFILE16_TO_HFILE32(hFile), buffer, (LONG)count );
+    return (UINT16)_hwrite32( FILE_GetHandle32(hFile), buffer, (LONG)count );
 }
 
 /***********************************************************************
@@ -1293,7 +1386,7 @@
  */
 LONG WINAPI _hread16( HFILE16 hFile, LPVOID buffer, LONG count)
 {
-    return _lread32( HFILE16_TO_HFILE32(hFile), buffer, count );
+    return _lread32( FILE_GetHandle32(hFile), buffer, count );
 }
 
 
@@ -1311,7 +1404,7 @@
  */
 LONG WINAPI _hwrite16( HFILE16 hFile, LPCSTR buffer, LONG count )
 {
-    return _hwrite32( HFILE16_TO_HFILE32(hFile), buffer, count );
+    return _hwrite32( FILE_GetHandle32(hFile), buffer, count );
 }