Finished and deployed CORBA sandbox separation
[captive.git] / src / libcaptive / client / directory.c
index 6877972..7960091 100644 (file)
 #include "config.h"
 
 #include "captive/client-directory.h"  /* self */
+#include "directory.h" /* self-priv */
 #include "lib.h"
 #include <glib/gmessages.h>
 #include "captive/unicode.h"
 #include "reactos/ntos/types.h"        /* for HANDLE */
 #include "reactos/ddk/iotypes.h"       /* for IO_STATUS_BLOCK */
 #include "reactos/ddk/iofuncs.h"       /* for IoCreateFile() */
-#include "captive/sandbox.h"
+#include "result.h"
+#include "captive/leave.h"
+#include "captive/usecount.h"
+#include "vfs.h"
+#include "captive/parent-Directory.h"
 
 
 static gpointer captive_directory_object_parent_class=NULL;
@@ -36,12 +41,9 @@ static GnomeVFSResult captive_directory_close(CaptiveDirectoryObject *captive_di
 
 static void captive_directory_object_finalize(CaptiveDirectoryObject *captive_directory_object)
 {
-GnomeVFSResult errvfsresult;
-
        g_return_if_fail(captive_directory_object!=NULL);
 
-       errvfsresult=captive_directory_close(captive_directory_object);
-       g_assert(errvfsresult==GNOME_VFS_OK);
+       captive_directory_close(captive_directory_object);      /* errors ignored */
 
        G_OBJECT_CLASS(captive_directory_object_parent_class)->finalize((GObject *)captive_directory_object);
 }
@@ -60,6 +62,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;
 }
 
 
@@ -88,23 +92,18 @@ static const GTypeInfo captive_directory_object_info={
 }
 
 
-GnomeVFSResult captive_directory_new_open(CaptiveDirectoryObject **captive_directory_object_return,const gchar *pathname)
+static GnomeVFSResult captive_directory_new_internal
+               (CaptiveDirectoryObject *captive_directory_object,const gchar *pathname,gboolean create,guint create_perm)
 {
 GnomeVFSResult errvfsresult;
 OBJECT_ATTRIBUTES dir_ObjectAttributes;
 HANDLE dir_Handle;
 IO_STATUS_BLOCK dir_IoStatusBlock;
 NTSTATUS err;
-CaptiveDirectoryObject *captive_directory_object;
 
-       if (CAPTIVE_IS_SANDBOX_PARENT())
-               return captive_sandbox_parent_directory_new_open(captive_directory_object_return,pathname);
-
-       g_return_val_if_fail(captive_directory_object_return!=NULL,GNOME_VFS_ERROR_BAD_PARAMETERS);
+       g_return_val_if_fail(captive_directory_object!=NULL,GNOME_VFS_ERROR_BAD_PARAMETERS);
        g_return_val_if_fail(pathname!=NULL,GNOME_VFS_ERROR_BAD_PARAMETERS);
 
-       *captive_directory_object_return=NULL;
-
        errvfsresult=captive_ObjectAttributes_init(pathname,&dir_ObjectAttributes);
        g_return_val_if_fail(errvfsresult==GNOME_VFS_OK,errvfsresult);
        
@@ -117,9 +116,9 @@ CaptiveDirectoryObject *captive_directory_object;
                        &dir_ObjectAttributes,  /* ObjectAttributes */
                        &dir_IoStatusBlock,     /* IoStatusBlock */
                        NULL,   /* AllocationSize; ignored for open */
-                       FILE_ATTRIBUTE_NORMAL,  /* FileAttributes; ignored for open */
-                       FILE_SHARE_WRITE,       /* ShareAccess; 0 means exclusive */
-                       FILE_OPEN,      /* CreateDisposition */
+                       (!create || create_perm&0200 ? FILE_ATTRIBUTE_NORMAL: FILE_ATTRIBUTE_READONLY), /* FileAttributes; ignored for open */
+                       (FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE),       /* ShareAccess; 0 means exclusive */
+                       (!create ? FILE_OPEN : FILE_CREATE),    /* CreateDisposition */
                        /* FILE_SYNCHRONOUS_IO_{,NON}ALERT: We need to allow W32 filesystem
                         * any waits to not to let it return STATUS_CANT_WAIT us.
                         * Alertability should have only effect on asynchronous events
@@ -133,17 +132,82 @@ 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==FILE_OPENED,GNOME_VFS_ERROR_GENERIC);
+       g_return_val_if_fail(dir_IoStatusBlock.Information
+                                       ==(!create ? FILE_OPENED : FILE_CREATED),
+                       GNOME_VFS_ERROR_GENERIC);
+
+       captive_directory_object->dir_Handle=dir_Handle;
+
+       return GNOME_VFS_OK;
+}
+
+
+GnomeVFSResult captive_directory_new_open(CaptiveDirectoryObject **captive_directory_object_return,
+               CaptiveVfsObject *captive_vfs_object,const gchar *pathname)
+{
+GnomeVFSResult r;
+CaptiveDirectoryObject *captive_directory_object;
+
+       g_return_val_if_fail(captive_directory_object_return!=NULL,GNOME_VFS_ERROR_BAD_PARAMETERS);
+       g_return_val_if_fail(captive_vfs_object!=NULL,GNOME_VFS_ERROR_BAD_PARAMETERS);
+       g_return_val_if_fail(pathname!=NULL,GNOME_VFS_ERROR_BAD_PARAMETERS);
 
        captive_directory_object=g_object_new(
                        CAPTIVE_DIRECTORY_TYPE_OBJECT,  /* object_type */
                        NULL);  /* first_property_name; FIXME: support properties */
+       captive_directory_object->dir_Handle=NULL;
+       captive_directory_object->vfs=captive_vfs_object;
+       *captive_directory_object_return=captive_directory_object;
 
-       captive_directory_object->dir_Handle=dir_Handle;
+       if (captive_vfs_object->is_sandbox_parent)
+               return captive_sandbox_parent_directory_new_open(captive_directory_object,pathname);
+
+       r=captive_directory_new_internal(captive_directory_object,pathname,
+                       FALSE,  /* create */
+                       0);     /* create_perm; ignored */
 
+       captive_leave();
+       if (r==GNOME_VFS_OK)
+               captive_usecount(+1);
+       else
+               g_object_unref(captive_directory_object);
+       return r;
+}
+
+
+GnomeVFSResult captive_directory_new_make(CaptiveDirectoryObject **captive_directory_object_return,
+               CaptiveVfsObject *captive_vfs_object,const gchar *pathname,guint perm)
+{
+GnomeVFSResult r;
+CaptiveDirectoryObject *captive_directory_object;
+
+       g_return_val_if_fail(captive_directory_object_return!=NULL,GNOME_VFS_ERROR_BAD_PARAMETERS);
+       g_return_val_if_fail(captive_vfs_object!=NULL,GNOME_VFS_ERROR_BAD_PARAMETERS);
+       g_return_val_if_fail(pathname!=NULL,GNOME_VFS_ERROR_BAD_PARAMETERS);
+
+       captive_directory_object=g_object_new(
+                       CAPTIVE_DIRECTORY_TYPE_OBJECT,  /* object_type */
+                       NULL);  /* first_property_name; FIXME: support properties */
+       captive_directory_object->dir_Handle=NULL;
+       captive_directory_object->vfs=captive_vfs_object;
        *captive_directory_object_return=captive_directory_object;
-       return GNOME_VFS_OK;
+
+       if (captive_vfs_object->is_sandbox_parent)
+               return captive_sandbox_parent_directory_new_make(captive_directory_object,pathname,perm);
+
+       r=captive_directory_new_internal(captive_directory_object,pathname,
+                       TRUE,   /* create */
+                       perm);  /* create_perm; ignored */
+
+       captive_leave();
+       if (r==GNOME_VFS_OK)
+               captive_usecount(+1);
+       else
+               g_object_unref(captive_directory_object);
+       return r;
 }
 
 
@@ -156,13 +220,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;
 
@@ -238,22 +303,77 @@ 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;
 HANDLE dir_Handle;
 
-       if (CAPTIVE_IS_SANDBOX_PARENT())
+       g_return_val_if_fail(captive_directory_object!=NULL,GNOME_VFS_ERROR_BAD_PARAMETERS);
+
+       if (captive_directory_object->vfs->is_sandbox_parent)
                return captive_sandbox_parent_directory_close(captive_directory_object);
 
-       g_return_val_if_fail(captive_directory_object!=NULL,GNOME_VFS_ERROR_BAD_PARAMETERS);
-       g_return_val_if_fail(captive_directory_object->dir_Handle!=NULL,GNOME_VFS_ERROR_BAD_PARAMETERS);        /* already closed */
+       if (captive_directory_object->dir_Handle!=NULL) {       /* not yet already closed */
+               captive_usecount(-1);   /* close() errors notwithstanding */
 
-       dir_Handle=captive_directory_object->dir_Handle;
-       captive_directory_object->dir_Handle=NULL;
-       err=NtClose(dir_Handle);
-       g_return_val_if_fail(NT_SUCCESS(err),GNOME_VFS_ERROR_GENERIC);
+               dir_Handle=captive_directory_object->dir_Handle;
+               captive_directory_object->dir_Handle=NULL;
+               err=NtClose(dir_Handle);
+               g_return_val_if_fail(NT_SUCCESS(err),GNOME_VFS_ERROR_GENERIC);
+               }
 
+       captive_leave();
        return GNOME_VFS_OK;
 }
 
@@ -263,37 +383,122 @@ 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())
+       g_return_val_if_fail(captive_directory_object!=NULL,GNOME_VFS_ERROR_BAD_PARAMETERS);
+       g_return_val_if_fail(file_info!=NULL,GNOME_VFS_ERROR_BAD_PARAMETERS);
+
+       if (captive_directory_object->vfs->is_sandbox_parent)
                return captive_sandbox_parent_directory_read(captive_directory_object,file_info);
 
-       g_return_val_if_fail(captive_directory_object!=NULL,GNOME_VFS_ERROR_BAD_PARAMETERS);
        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 (err==STATUS_NO_MORE_FILES)
-               return GNOME_VFS_ERROR_EOF;
-       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);
        g_return_val_if_fail(errvfsresult==GNOME_VFS_OK,errvfsresult);
 
+       captive_leave();
+       return GNOME_VFS_OK;
+}
+
+
+GnomeVFSResult captive_directory_remove(CaptiveDirectoryObject *captive_directory_object)
+{
+NTSTATUS err;
+FILE_DISPOSITION_INFORMATION FileDispositionInformation_struct;
+IO_STATUS_BLOCK dir_IoStatusBlock;
+GnomeVFSResult errvfsresult;
+
+       g_return_val_if_fail(captive_directory_object!=NULL,GNOME_VFS_ERROR_BAD_PARAMETERS);
+
+       if (captive_directory_object->vfs->is_sandbox_parent)
+               return captive_sandbox_parent_directory_remove(captive_directory_object);
+
+       g_return_val_if_fail(captive_directory_object->dir_Handle!=NULL,GNOME_VFS_ERROR_BAD_PARAMETERS);
+
+       FileDispositionInformation_struct.DoDeleteFile=TRUE;
+
+       err=NtSetInformationFile(
+                       captive_directory_object->dir_Handle,   /* FileHandle */
+                       &dir_IoStatusBlock,     /* IoStatusBlock */
+                       &FileDispositionInformation_struct,     /* FileInformation */
+                       sizeof(FileDispositionInformation_struct),      /* Length */
+                       FileDispositionInformation);    /* FileInformationClass */
+       if (GNOME_VFS_OK!=(errvfsresult=captive_NTSTATUS_to_GnomeVFSResult(err)))
+               return errvfsresult;
+       g_return_val_if_fail(NT_SUCCESS(err),GNOME_VFS_ERROR_GENERIC);
+
+       captive_leave();
        return GNOME_VFS_OK;
 }