captive_directory_read: +workaround/implement for ext2fsd.sys-V0.10A
authorshort <>
Mon, 24 Feb 2003 01:08:58 +0000 (01:08 +0000)
committershort <>
Mon, 24 Feb 2003 01:08:58 +0000 (01:08 +0000)
 - we now also support FileBothDirInformation; not just FileIdBothDirInformation
captive_directory_new_internal(): Return some errors as non-fatal
 - by captive_NTSTATUS_to_GnomeVFSResult

src/libcaptive/client/directory.c
src/libcaptive/include/captive/client-directory.h

index 5c78cf5..2bb883e 100644 (file)
@@ -61,6 +61,8 @@ static void captive_directory_object_init(CaptiveDirectoryObject *captive_direct
 {
        captive_directory_object->dir_Handle=NULL;
        captive_directory_object->read_first=TRUE;
+       captive_directory_object->CaptiveDirectoryObject_QueryDirectory_type=
+                       CaptiveDirectoryObject_QueryDirectory_type_FileIdBothDirInformation;
 }
 
 
@@ -135,6 +137,8 @@ CaptiveDirectoryObject *captive_directory_object;
                        0);     /* Options */
        g_free(dir_ObjectAttributes.ObjectName);        /* left from captive_gnomevfs_uri_parent_init() */
        g_return_val_if_fail(NT_SUCCESS(err)==NT_SUCCESS(dir_IoStatusBlock.Status),GNOME_VFS_ERROR_GENERIC);
+       if (GNOME_VFS_OK!=(errvfsresult=captive_NTSTATUS_to_GnomeVFSResult(err)))
+               return errvfsresult;
        g_return_val_if_fail(NT_SUCCESS(err),GNOME_VFS_ERROR_GENERIC);
        g_return_val_if_fail(dir_IoStatusBlock.Information
                                        ==(!create ? FILE_OPENED : FILE_CREATED),
@@ -184,13 +188,14 @@ ULONG tmp_ULONG;
 
        g_return_val_if_fail(file_info!=NULL,GNOME_VFS_ERROR_GENERIC);
        g_return_val_if_fail(FileIdBothDirInformation!=NULL,GNOME_VFS_ERROR_GENERIC);
+       g_return_val_if_fail(IoStatusBlock!=NULL,GNOME_VFS_ERROR_GENERIC);
 
        g_return_val_if_fail(NT_SUCCESS(IoStatusBlock->Status),GNOME_VFS_ERROR_GENERIC);
-       /* do not exceed the returned buffer by this record;
-        * '->NextEntryOffset' is ==0 as we used 'ReturnSingleEntry==TRUE'
-        */
+       /* do not exceed the returned buffer by this record; Redundant now, see below. */
        g_assert((gpointer)(((char *)FileIdBothDirInformation)+FileIdBothDirInformation->NextEntryOffset)
                        <=(gpointer)(((char *)FileIdBothDirInformation)+IoStatusBlock->Information));
+       /* '->NextEntryOffset' is ==0 as we used 'ReturnSingleEntry==TRUE' */
+       g_assert(FileIdBothDirInformation->NextEntryOffset==0);
 
        file_info->valid_fields=0;
 
@@ -266,6 +271,57 @@ ULONG tmp_ULONG;
 }
 
 
+static GnomeVFSResult FileBothDirInformation_to_FileIdBothDirInformation(FILE_ID_BOTH_DIR_INFORMATION *FileIdBothDirInformation,
+               FILE_BOTH_DIR_INFORMATION *FileBothDirInformation,IO_STATUS_BLOCK *IoStatusBlock)
+{
+static LARGE_INTEGER FileId_counter;
+
+       g_return_val_if_fail(FileIdBothDirInformation!=NULL,GNOME_VFS_ERROR_GENERIC);
+       g_return_val_if_fail(FileBothDirInformation!=NULL,GNOME_VFS_ERROR_GENERIC);
+       g_return_val_if_fail(IoStatusBlock!=NULL,GNOME_VFS_ERROR_GENERIC);
+
+       g_return_val_if_fail(NT_SUCCESS(IoStatusBlock->Status),GNOME_VFS_ERROR_GENERIC);
+       /* do not exceed the returned buffer by this record; Redundant now, see below. */
+       g_assert((gpointer)(((char *)FileBothDirInformation)+FileBothDirInformation->NextEntryOffset)
+                       <=(gpointer)(((char *)FileBothDirInformation)+IoStatusBlock->Information));
+       /* '->NextEntryOffset' is ==0 as we used 'ReturnSingleEntry==TRUE' */
+       g_assert(FileBothDirInformation->NextEntryOffset==0);
+
+       g_assert((gpointer)(((char *)FileBothDirInformation->FileName)+FileBothDirInformation->FileNameLength)
+                       <=(gpointer)(((char *)FileBothDirInformation)+IoStatusBlock->Information));
+                                       /* ensure we fit below '->IoStatusBlock->Information' at least without the 0-terminator */
+       memcpy(FileIdBothDirInformation->FileName,FileBothDirInformation->FileName,
+                       FileBothDirInformation->FileNameLength);
+
+       /* NextEntryOffset already handled */
+       FileIdBothDirInformation->FileIndex      =FileBothDirInformation->FileIndex;
+       FileIdBothDirInformation->CreationTime   =FileBothDirInformation->CreationTime;
+       FileIdBothDirInformation->LastAccessTime =FileBothDirInformation->LastAccessTime;
+       FileIdBothDirInformation->LastWriteTime  =FileBothDirInformation->LastWriteTime;
+       FileIdBothDirInformation->ChangeTime     =FileBothDirInformation->ChangeTime;
+       FileIdBothDirInformation->EndOfFile      =FileBothDirInformation->EndOfFile;
+       FileIdBothDirInformation->AllocationSize =FileBothDirInformation->AllocationSize;
+       FileIdBothDirInformation->FileAttributes =FileBothDirInformation->FileAttributes;
+       FileIdBothDirInformation->FileNameLength =FileBothDirInformation->FileNameLength;
+       FileIdBothDirInformation->EaSize         =FileBothDirInformation->EaSize;
+       FileIdBothDirInformation->ShortNameLength=FileBothDirInformation->ShortNameLength;
+       g_assert(sizeof(FileIdBothDirInformation->ShortName)==sizeof(FileBothDirInformation->ShortName));
+       memcpy(FileIdBothDirInformation->ShortName,FileBothDirInformation->ShortName,
+                       sizeof(FileBothDirInformation->ShortName));
+       /* FIXME: Register filenames for uniqueness;
+        * Not needed now as 'FileId' field not used by libcaptive anywhere anyway.
+        */
+       FileIdBothDirInformation->FileId.QuadPart=FileId_counter.QuadPart++;
+       /* FileName already handled */
+
+       IoStatusBlock->Information=sizeof(*FileIdBothDirInformation)+FileIdBothDirInformation->FileNameLength;
+       /* '->NextEntryOffset' is ==0 as we used 'ReturnSingleEntry==TRUE' */
+       FileIdBothDirInformation->NextEntryOffset=0;
+
+       return GNOME_VFS_OK;
+}
+
+
 static GnomeVFSResult captive_directory_close(CaptiveDirectoryObject *captive_directory_object)
 {
 NTSTATUS err;
@@ -291,6 +347,7 @@ GnomeVFSResult captive_directory_read(CaptiveDirectoryObject *captive_directory_
 NTSTATUS err;
 IO_STATUS_BLOCK dir_IoStatusBlock;
 FILE_ID_BOTH_DIR_INFORMATION *FileIdBothDirInformation;
+FILE_BOTH_DIR_INFORMATION *FileBothDirInformation;
 GnomeVFSResult errvfsresult;
 
        if (CAPTIVE_IS_SANDBOX_PARENT())
@@ -300,24 +357,75 @@ GnomeVFSResult errvfsresult;
        g_return_val_if_fail(captive_directory_object->dir_Handle!=NULL,GNOME_VFS_ERROR_BAD_PARAMETERS);
        g_return_val_if_fail(file_info!=NULL,GNOME_VFS_ERROR_BAD_PARAMETERS);
 
-       FileIdBothDirInformation=(void *)captive_directory_object->QueryDirectory_buf;
-       err=NtQueryDirectoryFile(
-                       captive_directory_object->dir_Handle,   /* FileHandle */
-                       NULL,   /* PEvent; completion signalling; optional */
-                       NULL,   /* ApcRoutine; optional */
-                       NULL,   /* ApcContext; optional */
-                       &dir_IoStatusBlock,     /* IoStatusBlock */
-                       (gpointer)captive_directory_object->QueryDirectory_buf, /* FileInformation */
-                       sizeof(captive_directory_object->QueryDirectory_buf)    /* Length */
-                                       -sizeof(*FileIdBothDirInformation->FileName),   /* reserve space for 0-terminator */
-                       FileIdBothDirectoryInformation, /* FileInformationClass; =>FILE_ID_BOTH_DIR_INFORMATION */
-                       TRUE,   /* ReturnSingleEntry */
-                       NULL,   /* FileName; wildcards possible; optional */
-                       captive_directory_object->read_first);  /* RestartScan */
-       captive_directory_object->read_first=FALSE;
-       if (GNOME_VFS_OK!=(errvfsresult=captive_NTSTATUS_to_GnomeVFSResult(err)))
-               return errvfsresult;
-       g_return_val_if_fail(NT_SUCCESS(err),GNOME_VFS_ERROR_GENERIC);
+       FileIdBothDirInformation=(void *)captive_directory_object->QueryDirectory_buf.FileIdBothDirInformation;
+retry:
+       switch (captive_directory_object->CaptiveDirectoryObject_QueryDirectory_type) {
+
+               case CaptiveDirectoryObject_QueryDirectory_type_FileIdBothDirInformation:
+                       err=NtQueryDirectoryFile(
+                                       captive_directory_object->dir_Handle,   /* FileHandle */
+                                       NULL,   /* PEvent; completion signalling; optional */
+                                       NULL,   /* ApcRoutine; optional */
+                                       NULL,   /* ApcContext; optional */
+                                       &dir_IoStatusBlock,     /* IoStatusBlock */
+                                       (gpointer)captive_directory_object->QueryDirectory_buf.FileIdBothDirInformation,        /* FileInformation */
+                                       sizeof(captive_directory_object->QueryDirectory_buf.FileIdBothDirInformation)   /* Length */
+                                                       -sizeof(*FileIdBothDirInformation->FileName),   /* reserve space for 0-terminator */
+                                       FileIdBothDirectoryInformation, /* FileInformationClass; =>FILE_ID_BOTH_DIR_INFORMATION */
+                                       TRUE,   /* ReturnSingleEntry */
+                                       NULL,   /* FileName; wildcards possible; optional */
+                                       captive_directory_object->read_first);  /* RestartScan */
+                       if (err==STATUS_NO_SUCH_FILE) {
+                               /* 'FileIdBothDirInformation' not supported at least by ext2fsd.sys.
+                                * Emulate it from 'FileBothDirectoryInformation' here.
+                                */
+                               captive_directory_object->CaptiveDirectoryObject_QueryDirectory_type=
+                                               CaptiveDirectoryObject_QueryDirectory_type_FileBothDirInformation;
+                               goto retry;
+                               }
+
+                       captive_directory_object->read_first=FALSE;
+                       if (GNOME_VFS_OK!=(errvfsresult=captive_NTSTATUS_to_GnomeVFSResult(err)))
+                               return errvfsresult;
+                       g_return_val_if_fail(NT_SUCCESS(err),GNOME_VFS_ERROR_GENERIC);
+                       break;
+
+               case CaptiveDirectoryObject_QueryDirectory_type_FileBothDirInformation:
+                       FileBothDirInformation=(void *)captive_directory_object->QueryDirectory_buf.FileBothDirInformation;
+                       /* SL_INDEX_SPECIFIED is forbidden for ext2fsd.sys-V0.10A although
+                        * IIRC it was required for the native W32 filesystems.
+                        * Fortunately 'FileBothDirInformation' is just a workaround for ext2fsd.sys-V0.10A
+                        * which is not used for the native W32 filesystems and therefore it should be safe.
+                        * WARNING: Hack with 'FileIndex==0' to prevent SL_INDEX_SPECIFIED is just libcaptive
+                        * specific hack of reactos! See also NtQueryDirectoryFile().
+                        */
+                       FileBothDirInformation->FileIndex=0;
+                       err=NtQueryDirectoryFile(
+                                       captive_directory_object->dir_Handle,   /* FileHandle */
+                                       NULL,   /* PEvent; completion signalling; optional */
+                                       NULL,   /* ApcRoutine; optional */
+                                       NULL,   /* ApcContext; optional */
+                                       &dir_IoStatusBlock,     /* IoStatusBlock */
+                                       (gpointer)captive_directory_object->QueryDirectory_buf.FileBothDirInformation,  /* FileInformation */
+                                       sizeof(captive_directory_object->QueryDirectory_buf.FileBothDirInformation)     /* Length */
+                                                       -sizeof(*FileBothDirInformation->FileName),     /* reserve space for 0-terminator */
+                                       FileBothDirectoryInformation,   /* FileInformationClass; =>FILE_BOTH_DIR_INFORMATION */
+                                       TRUE,   /* ReturnSingleEntry */
+                                       NULL,   /* FileName; wildcards possible; optional */
+                                       captive_directory_object->read_first);  /* RestartScan */
+
+                       captive_directory_object->read_first=FALSE;
+                       if (GNOME_VFS_OK!=(errvfsresult=captive_NTSTATUS_to_GnomeVFSResult(err)))
+                               return errvfsresult;
+                       g_return_val_if_fail(NT_SUCCESS(err),GNOME_VFS_ERROR_GENERIC);
+                       
+                       errvfsresult=FileBothDirInformation_to_FileIdBothDirInformation(FileIdBothDirInformation,FileBothDirInformation,
+                                       &dir_IoStatusBlock);
+                       g_return_val_if_fail(errvfsresult==GNOME_VFS_OK,errvfsresult);
+                       break;
+
+               default: g_assert_not_reached();
+               }
 
        errvfsresult=FileIdBothDirInformation_to_GnomeVFSFileInfo(file_info,FileIdBothDirInformation,
                        &dir_IoStatusBlock);
index 8445b47..6b1049e 100644 (file)
@@ -45,10 +45,20 @@ struct _CaptiveDirectoryObject {
        HANDLE dir_Handle;
        gboolean read_first;
        /* 'QueryDirectory_buf' for NtQueryDirectoryFile() must be persistent
-        * to keep the state if !read_first
+        * to keep the state if !read_first.
+        * Both types of 'QueryDirectory_buf' MUST NOT be 'union' as we convert
+        * them by copying one to other.
         */
-       char QueryDirectory_buf[sizeof(FILE_ID_BOTH_DIR_INFORMATION)
-                       +0x1000 /* max 'FileName' length, 255 should be enough */ * sizeof(WCHAR /* *FILE_ID_BOTH_DIR_INFORMATION.FileName */ )];
+       struct {
+               char FileIdBothDirInformation[sizeof(FILE_ID_BOTH_DIR_INFORMATION)
+                               +0x1000 /* max 'FileName' length, 255 should be enough */ * sizeof(WCHAR /* *FILE_ID_BOTH_DIR_INFORMATION.FileName */ )];
+               char FileBothDirInformation[sizeof(FILE_BOTH_DIR_INFORMATION)
+                               +0x1000 /* max 'FileName' length, 255 should be enough */ * sizeof(WCHAR /* *FILE_ID_BOTH_DIR_INFORMATION.FileName */ )];
+               } QueryDirectory_buf;
+       enum {
+               CaptiveDirectoryObject_QueryDirectory_type_FileIdBothDirInformation,
+               CaptiveDirectoryObject_QueryDirectory_type_FileBothDirInformation,
+               } CaptiveDirectoryObject_QueryDirectory_type;
        };
 struct _CaptiveDirectoryObjectClass {
        GObjectClass parent_class;