Implemented sub-second W32 filesystem interface by new: CaptiveFileInfoObject
[captive.git] / src / libcaptive / client / file-parent.c
index e0348ff..8fdf41e 100644 (file)
@@ -25,6 +25,8 @@
 #include "vfs-parent.h"
 #include "reactos/ntos/types.h"        /* for ULONG */
 #include "parent-connector.h"
+#include "captive/client.h"    /* for captive_path_normalize() */
+#include <ctype.h>
 
 
 static gpointer captive_file_parent_object_parent_class=NULL;
@@ -40,9 +42,9 @@ static GnomeVFSResult captive_file_parent_seek
 static GnomeVFSResult captive_file_parent_tell(CaptiveFileObject *captive_file_object,GnomeVFSFileOffset *offset_return);
 static GnomeVFSResult captive_file_parent_remove(CaptiveFileObject *captive_file_object);
 static GnomeVFSResult captive_file_parent_file_info_get
-               (CaptiveFileObject *captive_file_object,GnomeVFSFileInfo *file_info);
+               (CaptiveFileObject *captive_file_object,CaptiveFileInfoObject **captive_file_info_object_return);
 static GnomeVFSResult captive_file_parent_file_info_set
-               (CaptiveFileObject *captive_file_object,const GnomeVFSFileInfo *info,GnomeVFSSetFileInfoMask mask);
+               (CaptiveFileObject *captive_file_object,CaptiveFileInfoObject *captive_file_info_object,GnomeVFSSetFileInfoMask mask);
 static GnomeVFSResult captive_file_parent_truncate(CaptiveFileObject *captive_file_object,GnomeVFSFileSize file_size);
 static GnomeVFSResult captive_file_parent_move
                (CaptiveFileObject *captive_file_object_old,const gchar *pathname_new,gboolean force_replace);
@@ -180,6 +182,8 @@ GnomeVFSResult captive_file_parent_new_open(CaptiveFileObject **captive_file_obj
 {
 CaptiveFileParentObject *captive_file_parent_object;
 GnomeVFSResult r;
+gint retried=0;
+gint retried_commit=0;
 
        g_return_val_if_fail(captive_file_object_return!=NULL,GNOME_VFS_ERROR_BAD_PARAMETERS);
        g_return_val_if_fail(CAPTIVE_VFS_PARENT_IS_OBJECT(captive_vfs_object),GNOME_VFS_ERROR_BAD_PARAMETERS);
@@ -193,18 +197,30 @@ GnomeVFSResult r;
 
        captive_file_parent_init(captive_file_parent_object,captive_vfs_object);
 
-       if (GNOME_VFS_OK!=(r=captive_parent_connector_connect(CAPTIVE_PARENT_CONNECTOR(captive_file_parent_object))))
-               return r;
-
-       if (GNOME_VFS_OK!=(r=captive_sandbox_parent_file_new_open(captive_file_parent_object))) {
-               g_object_unref(captive_file_parent_object);
-               *captive_file_object_return=NULL;
-               return r;
-               }
-
-       *captive_file_object_return=CAPTIVE_FILE_OBJECT(captive_file_parent_object);
-       return (*captive_file_parent_object_captive_parent_connector_open_orig)
-                       (CAPTIVE_PARENT_CONNECTOR(captive_file_parent_object));
+       do {
+               if (GNOME_VFS_OK!=(r=captive_parent_connector_connect(CAPTIVE_PARENT_CONNECTOR(captive_file_parent_object))))
+                       return r;
+               if (GNOME_VFS_ERROR_SERVICE_NOT_AVAILABLE
+                               !=(r=captive_sandbox_parent_file_new_open(captive_file_parent_object))) {
+                       if (GNOME_VFS_ERROR_SERVICE_OBSOLETE==r) {
+                               if (!retried_commit++) {
+                                       if (GNOME_VFS_OK!=(r=captive_vfs_commit(captive_vfs_object)))
+                                               return r;
+                                       retried=0;
+                                       continue;
+                                       }
+                               }
+                       if (GNOME_VFS_OK!=r) {
+                               g_object_unref(captive_file_parent_object);
+                               *captive_file_object_return=NULL;
+                               return r;
+                               }
+                       *captive_file_object_return=CAPTIVE_FILE_OBJECT(captive_file_parent_object);
+                       return (*captive_file_parent_object_captive_parent_connector_open_orig)
+                                       (CAPTIVE_PARENT_CONNECTOR(captive_file_parent_object));
+                       }
+               } while (!retried++);
+       return r;
 }
 
 
@@ -213,6 +229,8 @@ GnomeVFSResult captive_file_parent_new_create(CaptiveFileObject **captive_file_o
 {
 CaptiveFileParentObject *captive_file_parent_object;
 GnomeVFSResult r;
+gint retried=0;
+gint retried_commit=0;
 
        g_return_val_if_fail(captive_file_object_return!=NULL,GNOME_VFS_ERROR_BAD_PARAMETERS);
        g_return_val_if_fail(CAPTIVE_VFS_PARENT_IS_OBJECT(captive_vfs_object),GNOME_VFS_ERROR_BAD_PARAMETERS);
@@ -229,16 +247,31 @@ GnomeVFSResult r;
        if (GNOME_VFS_OK!=(r=captive_parent_connector_connect(CAPTIVE_PARENT_CONNECTOR(captive_file_parent_object))))
                return r;
 
-       if (GNOME_VFS_OK!=(r=captive_sandbox_parent_file_new_create(captive_file_parent_object,exclusive,perm))) {
-               g_object_unref(captive_file_parent_object);
-               *captive_file_object_return=NULL;
-               return r;
-               }
-       captive_parent_connector_set_dirty(CAPTIVE_PARENT_CONNECTOR(captive_file_parent_object));
-
-       *captive_file_object_return=CAPTIVE_FILE_OBJECT(captive_file_parent_object);
-       return (*captive_file_parent_object_captive_parent_connector_open_orig)
-                       (CAPTIVE_PARENT_CONNECTOR(captive_file_parent_object));
+       do {
+               if (GNOME_VFS_OK!=(r=captive_parent_connector_connect(CAPTIVE_PARENT_CONNECTOR(captive_file_parent_object))))
+                       return r;
+               if (GNOME_VFS_ERROR_SERVICE_NOT_AVAILABLE
+                               !=(r=captive_sandbox_parent_file_new_create(captive_file_parent_object,exclusive,perm))) {
+                       if (GNOME_VFS_ERROR_SERVICE_OBSOLETE==r) {
+                               if (!retried_commit++) {
+                                       if (GNOME_VFS_OK!=(r=captive_vfs_commit(captive_vfs_object)))
+                                               return r;
+                                       retried=0;
+                                       continue;
+                                       }
+                               }
+                       if (GNOME_VFS_OK!=r) {
+                               g_object_unref(captive_file_parent_object);
+                               *captive_file_object_return=NULL;
+                               return r;
+                               }
+                       captive_parent_connector_set_dirty(CAPTIVE_PARENT_CONNECTOR(captive_file_parent_object));
+                       *captive_file_object_return=CAPTIVE_FILE_OBJECT(captive_file_parent_object);
+                       return (*captive_file_parent_object_captive_parent_connector_open_orig)
+                                       (CAPTIVE_PARENT_CONNECTOR(captive_file_parent_object));
+                       }
+               } while (!retried++);
+       return r;
 }
 
 
@@ -315,6 +348,7 @@ static GnomeVFSResult captive_file_parent_read(CaptiveFileObject *captive_file_o
 CaptiveFileParentObject *captive_file_parent_object;
 GnomeVFSResult r;
 gint retried=0;
+gint retried_commit=0;
 
        g_return_val_if_fail(CAPTIVE_FILE_PARENT_IS_OBJECT(captive_file_object),GNOME_VFS_ERROR_BAD_PARAMETERS);
        g_return_val_if_fail(buffer!=NULL,GNOME_VFS_ERROR_BAD_PARAMETERS);
@@ -327,8 +361,17 @@ gint retried=0;
                if (GNOME_VFS_OK!=(r=captive_parent_connector_open(CAPTIVE_PARENT_CONNECTOR(captive_file_parent_object))))
                        return r;
                if (GNOME_VFS_ERROR_SERVICE_NOT_AVAILABLE
-                               !=(r=captive_sandbox_parent_file_read(captive_file_parent_object,buffer,num_bytes,bytes_read_return)))
+                               !=(r=captive_sandbox_parent_file_read(captive_file_parent_object,buffer,num_bytes,bytes_read_return))) {
+                       if (GNOME_VFS_ERROR_SERVICE_OBSOLETE==r) {
+                               if (!retried_commit++) {
+                                       if (GNOME_VFS_OK!=(r=captive_vfs_commit(captive_file_object->vfs)))
+                                               return r;
+                                       retried=0;
+                                       continue;
+                                       }
+                               }
                        return r;
+                       }
                } while (!retried++);
        return r;
 }
@@ -442,14 +485,14 @@ gint retried=0;
 
 
 static GnomeVFSResult captive_file_parent_file_info_get
-               (CaptiveFileObject *captive_file_object,GnomeVFSFileInfo *file_info)
+               (CaptiveFileObject *captive_file_object,CaptiveFileInfoObject **captive_file_info_object_return)
 {
 CaptiveFileParentObject *captive_file_parent_object;
 GnomeVFSResult r;
 gint retried=0;
 
        g_return_val_if_fail(CAPTIVE_FILE_PARENT_IS_OBJECT(captive_file_object),GNOME_VFS_ERROR_BAD_PARAMETERS);
-       g_return_val_if_fail(file_info!=NULL,GNOME_VFS_ERROR_BAD_PARAMETERS);
+       g_return_val_if_fail(captive_file_info_object_return!=NULL,GNOME_VFS_ERROR_BAD_PARAMETERS);
 
        captive_file_parent_object=CAPTIVE_FILE_PARENT_OBJECT(captive_file_object);
 
@@ -457,7 +500,7 @@ gint retried=0;
                if (GNOME_VFS_OK!=(r=captive_parent_connector_open(CAPTIVE_PARENT_CONNECTOR(captive_file_parent_object))))
                        return r;
                if (GNOME_VFS_ERROR_SERVICE_NOT_AVAILABLE
-                               !=(r=captive_sandbox_parent_file_file_info_get(captive_file_parent_object,file_info)))
+                               !=(r=captive_sandbox_parent_file_file_info_get(captive_file_parent_object,captive_file_info_object_return)))
                        return r;
                } while (!retried++);
        return r;
@@ -465,14 +508,14 @@ gint retried=0;
 
 
 static GnomeVFSResult captive_file_parent_file_info_set
-               (CaptiveFileObject *captive_file_object,const GnomeVFSFileInfo *info,GnomeVFSSetFileInfoMask mask)
+               (CaptiveFileObject *captive_file_object,CaptiveFileInfoObject *captive_file_info_object,GnomeVFSSetFileInfoMask mask)
 {
 CaptiveFileParentObject *captive_file_parent_object;
 GnomeVFSResult r;
 gint retried=0;
 
        g_return_val_if_fail(CAPTIVE_FILE_PARENT_IS_OBJECT(captive_file_object),GNOME_VFS_ERROR_BAD_PARAMETERS);
-       g_return_val_if_fail(info!=NULL,GNOME_VFS_ERROR_BAD_PARAMETERS);
+       g_return_val_if_fail(CAPTIVE_FILE_INFO_IS_OBJECT(captive_file_info_object),GNOME_VFS_ERROR_BAD_PARAMETERS);
 
        captive_file_parent_object=CAPTIVE_FILE_PARENT_OBJECT(captive_file_object);
 
@@ -480,7 +523,7 @@ gint retried=0;
                if (GNOME_VFS_OK!=(r=captive_parent_connector_open(CAPTIVE_PARENT_CONNECTOR(captive_file_parent_object))))
                        return r;
                if (GNOME_VFS_ERROR_SERVICE_NOT_AVAILABLE
-                               !=(r=captive_sandbox_parent_file_file_info_set(captive_file_parent_object,info,mask))) {
+                               !=(r=captive_sandbox_parent_file_file_info_set(captive_file_parent_object,captive_file_info_object,mask))) {
                        if (GNOME_VFS_OK==r)
                                captive_parent_connector_set_dirty(CAPTIVE_PARENT_CONNECTOR(captive_file_parent_object));
                        return r;
@@ -520,19 +563,48 @@ static GnomeVFSResult captive_file_parent_move
 CaptiveFileParentObject *captive_file_parent_object_old;
 GnomeVFSResult r;
 gint retried=0;
+gchar *chksub_pathname_old_cased,*chksub_pathname_new_cased;   /* case-sensitive version */
+gchar *chksub_pathname_old,*chksub_pathname_new,*chksub_s_old,*chksub_s_new;
 
        g_return_val_if_fail(CAPTIVE_FILE_PARENT_IS_OBJECT(captive_file_object_old),GNOME_VFS_ERROR_BAD_PARAMETERS);
        g_return_val_if_fail(pathname_new!=NULL,GNOME_VFS_ERROR_BAD_PARAMETERS);
 
        captive_file_parent_object_old=CAPTIVE_FILE_PARENT_OBJECT(captive_file_object_old);
 
+       /* Prevent "mv dir dir/subdir" as it is not catched by ntfs.sys of NT-5.1sp1. */
+       /* FIXME: Move to 'CaptiveFileSlaveObject' but it has no '->pathname' stored now! */
+       /* FIXME: UTF8 may not be compared correctly - we should use g_utf8_collate() */
+       chksub_pathname_old_cased=captive_path_normalize(captive_file_parent_object_old->pathname);
+       chksub_pathname_new_cased=captive_path_normalize(pathname_new);
+       chksub_pathname_old=g_utf8_casefold(chksub_pathname_old_cased,
+                       -1);    /* len; '\0'-terminated */
+       chksub_pathname_new=g_utf8_casefold(chksub_pathname_new_cased,
+                       -1);    /* len; '\0'-terminated */
+       g_free(chksub_pathname_old_cased);
+       g_free(chksub_pathname_new_cased);
+       for (
+                       chksub_s_old=chksub_pathname_old,chksub_s_new=chksub_pathname_new;
+                       *chksub_s_old && *chksub_s_new && tolower(*chksub_s_old)==tolower(*chksub_s_new);
+                       chksub_s_old++,chksub_s_new++);
+       g_assert(chksub_s_old>chksub_pathname_old);
+       g_assert(chksub_s_new>chksub_pathname_new);
+       if (!*chksub_s_old && (!*chksub_s_new || *chksub_s_new=='/'))
+               return GNOME_VFS_ERROR_DIRECTORY_BUSY;
+       if (!*chksub_s_new && (!*chksub_s_old || *chksub_s_old=='/'))
+               return GNOME_VFS_ERROR_DIRECTORY_BUSY;
+       g_free(chksub_pathname_old);
+       g_free(chksub_pathname_new);
+
        do {
                if (GNOME_VFS_OK!=(r=captive_parent_connector_open(CAPTIVE_PARENT_CONNECTOR(captive_file_parent_object_old))))
                        return r;
                if (GNOME_VFS_ERROR_SERVICE_NOT_AVAILABLE
                                !=(r=captive_sandbox_parent_file_move(captive_file_parent_object_old,pathname_new,force_replace))) {
-                       if (GNOME_VFS_OK==r)
+                       if (GNOME_VFS_OK==r) {
+                               g_free(captive_file_parent_object_old->pathname);
+                               captive_file_parent_object_old->pathname=g_strdup(pathname_new);
                                captive_parent_connector_set_dirty(CAPTIVE_PARENT_CONNECTOR(captive_file_parent_object_old));
+                               }
                        return r;
                        }
                } while (!retried++);