[gvfs] afp: work on file enumeration



commit d38d13dfd156cfe0e43eb1d03462a176298ce256
Author: Carl-Anton Ingmarsson <ca ingmarsson gmail com>
Date:   Tue Jun 21 00:35:18 2011 +0200

    afp: work on file enumeration

 daemon/gvfsafpconnection.c |   42 ++++++----
 daemon/gvfsafpconnection.h |   31 +++++--
 daemon/gvfsafpserver.c     |    1 +
 daemon/gvfsafpserver.h     |    2 +-
 daemon/gvfsbackendafp.c    |  208 +++++++++++++++++++++++++++++++++++++++++---
 5 files changed, 246 insertions(+), 38 deletions(-)
---
diff --git a/daemon/gvfsafpconnection.c b/daemon/gvfsafpconnection.c
index a10eea6..8fc623d 100644
--- a/daemon/gvfsafpconnection.c
+++ b/daemon/gvfsafpconnection.c
@@ -53,13 +53,7 @@ g_vfs_afp_name_ref (GVfsAfpName *afp_name)
 char *
 g_vfs_afp_name_get_string (GVfsAfpName *afp_name)
 {
-  char *str;
-
-  str = g_malloc (afp_name->len + 1);
-  memcpy (str, afp_name->str, afp_name->len);
-  str[afp_name->len] = 0;
-
-  return str;
+  return g_strndup (afp_name->str, afp_name->len);
 }
 
 GVfsAfpName *
@@ -102,12 +96,12 @@ g_vfs_afp_name_new_from_gstring (guint32 text_encoding, GString *string)
  */
 struct _GVfsAfpReplyClass
 {
-	GDataInputStreamClass parent_class;
+	GObjectClass parent_class;
 };
 
 struct _GVfsAfpReply
 {
-	GDataInputStream parent_instance;
+	GObject parent_instance;
 
   AfpResultCode result_code;
 
@@ -262,11 +256,7 @@ g_vfs_afp_reply_read_pascal (GVfsAfpReply *reply, char **str)
   }
 
   if (str)
-  {
-    *str = g_malloc (strsize + 1);
-    memcpy (*str, reply->data + reply->pos, strsize);
-    (*str)[strsize] = '\0';
-  }
+    *str = g_strndup (reply->data + reply->pos, strsize);
 
   reply->pos += strsize;
   
@@ -356,6 +346,12 @@ g_vfs_afp_reply_skip_to_even (GVfsAfpReply *reply)
   return TRUE;
 }
 
+gint
+g_vfs_afp_reply_get_pos (GVfsAfpReply *reply)
+{
+  return reply->pos;
+}
+
 AfpResultCode
 g_vfs_afp_reply_get_result_code (GVfsAfpReply *reply)
 {
@@ -410,14 +406,28 @@ g_vfs_afp_command_put_pascal (GVfsAfpCommand *command, const char *str)
 {
   size_t len;
 
-  len = strlen (str);
-  len = (len <= 256) ? len : 256;
+  len = MIN (strlen (str), 256);
 
   g_data_output_stream_put_byte (G_DATA_OUTPUT_STREAM (command), len, NULL, NULL);
   g_output_stream_write (G_OUTPUT_STREAM (command), str, len, NULL, NULL);
 }
 
 void
+g_vfs_afp_command_put_afp_name (GVfsAfpCommand *command, GVfsAfpName *afp_name)
+{
+#if 0
+  g_data_output_stream_put_uint32 (G_DATA_OUTPUT_STREAM (command),
+                                   afp_name->text_encoding, NULL, NULL);
+#endif
+  
+  g_data_output_stream_put_uint16 (G_DATA_OUTPUT_STREAM (command),
+                                   afp_name->len, NULL, NULL);
+
+  g_output_stream_write_all (G_OUTPUT_STREAM (command), afp_name->str,
+                             afp_name->len, NULL, NULL, NULL);
+}
+
+void
 g_vfs_afp_command_pad_to_even (GVfsAfpCommand *command)
 { 
   if (g_vfs_afp_command_get_size (command) % 2 == 1)
diff --git a/daemon/gvfsafpconnection.h b/daemon/gvfsafpconnection.h
index 3f92c9b..f922460 100644
--- a/daemon/gvfsafpconnection.h
+++ b/daemon/gvfsafpconnection.h
@@ -133,6 +133,13 @@ enum {
 
 typedef enum
 {
+  AFP_PATH_TYPE_SHORT_NAME = 1,
+  AFP_PATH_TYPE_LONG_NAME  = 2,
+  AFP_PATH_TYPE_UTF8_NAME  = 3
+} AfpPathType;
+
+typedef enum
+{
   AFP_DIR_BITMAP_ATTRIBUTE_BIT          = 0x1,
   AFP_DIR_BITMAP_PARENT_DIR_ID_BIT      = 0x2,
   AFP_DIR_BITMAP_CREATE_DATE_BIT        = 0x4,
@@ -203,10 +210,13 @@ typedef enum
 
 typedef enum
 {
-  AFP_RESULT_NO_ERROR = 0,
-  AFP_RESULT_USER_NOT_AUTH = -5023,
-  AFP_RESULT_AUTH_CONTINUE = -5001,
-  AFP_RESULT_NO_MORE_SESSIONS = -1068
+  AFP_RESULT_NO_ERROR         = 0,
+  AFP_RESULT_NO_MORE_SESSIONS = -1068,
+  AFP_RESULT_ACCESS_DENIED    = -5000, 
+  AFP_RESULT_AUTH_CONTINUE    = -5001,
+  AFP_RESULT_OBJECT_NOT_FOUND = -5018,
+  AFP_RESULT_PARAM_ERR        = -5019,
+  AFP_RESULT_USER_NOT_AUTH    = -5023
 } AfpResultCode;
 
 /*
@@ -262,6 +272,7 @@ gboolean        g_vfs_afp_reply_seek              (GVfsAfpReply *reply, gint off
 gboolean        g_vfs_afp_reply_skip_to_even      (GVfsAfpReply *reply);
 
 AfpResultCode   g_vfs_afp_reply_get_result_code   (GVfsAfpReply *reply);
+gint            g_vfs_afp_reply_get_pos           (GVfsAfpReply *reply);
 
 GType           g_vfs_afp_reply_get_type         (void) G_GNUC_CONST;
 
@@ -280,13 +291,15 @@ typedef struct _GVfsAfpCommandClass GVfsAfpCommandClass;
 typedef struct _GVfsAfpCommand GVfsAfpCommand;
 
 
-GVfsAfpCommand* g_vfs_afp_command_new         (AfpCommandType type);
+GVfsAfpCommand* g_vfs_afp_command_new          (AfpCommandType type);
+
+void            g_vfs_afp_command_put_pascal   (GVfsAfpCommand *command, const char *str);
+void            g_vfs_afp_command_put_afp_name (GVfsAfpCommand *command, GVfsAfpName *afp_name);
 
-void            g_vfs_afp_command_put_pascal  (GVfsAfpCommand *command, const char *str);
-void            g_vfs_afp_command_pad_to_even (GVfsAfpCommand *command);
+void            g_vfs_afp_command_pad_to_even  (GVfsAfpCommand *command);
 
-gsize           g_vfs_afp_command_get_size    (GVfsAfpCommand *command);
-char*           g_vfs_afp_command_get_data    (GVfsAfpCommand *command);
+gsize           g_vfs_afp_command_get_size     (GVfsAfpCommand *command);
+char*           g_vfs_afp_command_get_data     (GVfsAfpCommand *command);
 
 GType           g_vfs_afp_command_get_type (void) G_GNUC_CONST;
 
diff --git a/daemon/gvfsafpserver.c b/daemon/gvfsafpserver.c
index d76b8f0..1cd8745 100644
--- a/daemon/gvfsafpserver.c
+++ b/daemon/gvfsafpserver.c
@@ -315,6 +315,7 @@ dhx2_login (GVfsAfpServer *afp_serv,
 
   res = g_vfs_afp_connection_send_command_sync (afp_serv->conn, comm,
                                                 cancellable, error);
+  g_object_unref (comm);
   if (!res)
     goto error;
   
diff --git a/daemon/gvfsafpserver.h b/daemon/gvfsafpserver.h
index 545997a..2ec5325 100644
--- a/daemon/gvfsafpserver.h
+++ b/daemon/gvfsafpserver.h
@@ -34,7 +34,7 @@ typedef enum
 {
   AFP_VERSION_INVALID,
   AFP_VERSION_3_0,
-  AFP_VERSIOM_3_1,
+  AFP_VERSION_3_1,
   AFP_VERSION_3_2,
   AFP_VERSION_3_3
 } AfpVersion;
diff --git a/daemon/gvfsbackendafp.c b/daemon/gvfsbackendafp.c
index b17a029..bf0d7ae 100644
--- a/daemon/gvfsbackendafp.c
+++ b/daemon/gvfsbackendafp.c
@@ -40,6 +40,8 @@
 
 #include "gvfsbackendafp.h"
 
+static const gint16 ENUMERATE_REQ_COUNT = G_MAXINT16;
+
 struct _GVfsBackendAfpClass
 {
 	GVfsBackendClass parent_class;
@@ -73,20 +75,22 @@ is_root (const char *filename)
   return *p == 0;
 }
 
-# if 0
-static GString *
+
+static GVfsAfpName *
 filename_to_afp_pathname (const char *filename)
 {
   GString *pathname;
 
   pathname = g_string_new (NULL);
+
+  g_string_append_c (pathname, 0);
   
-  while (filename && *filename == '/')
+  while (*filename == '/')
       filename++;
   
-  while (filename)
+  while (*filename != 0)
   {
-    char *end;
+    const char *end;
 
     end = strchr (filename, '/');
     if (!end)
@@ -95,13 +99,192 @@ filename_to_afp_pathname (const char *filename)
     g_string_append_c (pathname, 0);
     g_string_append_len (pathname, filename, end - filename);
 
-    while (filename && *filename == '/')
+    filename = end;	
+    while (*filename == '/')
       filename++;
   }
 
-  return pathname;
+  return g_vfs_afp_name_new_from_gstring (kTextEncodingUnicodeV3_0,
+                                          pathname);
+}
+
+static void
+enumerate_ext2_cb (GVfsAfpConnection *afp_connection,
+                   GVfsAfpReply      *reply,
+                   GError            *error,
+                   gpointer           user_data)
+{
+  GVfsJobEnumerate *job = G_VFS_JOB_ENUMERATE (user_data);
+
+  AfpResultCode res_code;
+  guint16 file_bitmap;
+  guint16  dir_bitmap;
+  gint16 count, i;
+  
+  if (!reply)
+  {
+    g_vfs_job_failed_from_error (G_VFS_JOB (job), error);
+    return;
+  }
+
+  res_code = g_vfs_afp_reply_get_result_code (reply);
+  if (res_code == AFP_RESULT_OBJECT_NOT_FOUND)
+  {
+    g_vfs_job_succeeded (G_VFS_JOB (job));
+    g_vfs_job_enumerate_done (job);
+    return;
+  }
+  else if (res_code != AFP_RESULT_NO_ERROR)
+  {
+    g_vfs_job_failed_literal (G_VFS_JOB (job), G_IO_ERROR,
+                              G_IO_ERROR_FAILED, _("Enumeration of files failed"));
+    return;
+  }
+
+  g_vfs_afp_reply_read_uint16 (reply, &file_bitmap);
+  g_vfs_afp_reply_read_uint16 (reply, &dir_bitmap);
+
+  g_vfs_afp_reply_read_int16 (reply, &count);
+  for (i = 0; i < count; i++)
+  {
+    gint start_pos;
+    guint16 struct_length;
+    guint8 FileDir;
+
+    start_pos = g_vfs_afp_reply_get_pos (reply);
+    
+    g_vfs_afp_reply_read_uint16 (reply, &struct_length);
+    g_vfs_afp_reply_read_byte (reply, &FileDir);
+    /* pad byte */
+    g_vfs_afp_reply_read_byte (reply, NULL);
+    
+    /* Directory */
+    if (FileDir & 0x80)
+    {
+      if (dir_bitmap & AFP_FILE_BITMAP_UTF8_NAME_BIT)
+      {
+        guint16 UTF8Name_offset;
+        gint old_pos;
+        GVfsAfpName *afp_name;
+        char *utf8_name;
+
+        g_vfs_afp_reply_read_uint16 (reply, &UTF8Name_offset);
+
+        old_pos = g_vfs_afp_reply_get_pos (reply);
+        g_vfs_afp_reply_seek (reply, start_pos + UTF8Name_offset + 4, G_SEEK_SET);
+
+        g_vfs_afp_reply_read_afp_name (reply, TRUE, &afp_name);
+        utf8_name = g_vfs_afp_name_get_string (afp_name);
+        g_debug ("Directory: %s\n", utf8_name);        
+
+        g_vfs_afp_name_unref (afp_name);
+        g_free (utf8_name);
+        
+        g_vfs_afp_reply_seek (reply, old_pos, G_SEEK_SET);
+      }
+    }
+    
+    /* File */
+    else
+    {
+      if (file_bitmap & AFP_FILE_BITMAP_UTF8_NAME_BIT)
+      {
+        guint16 UTF8Name_offset;
+        gint old_pos;
+        GVfsAfpName *afp_name;
+        char *utf8_name;
+
+        g_vfs_afp_reply_read_uint16 (reply, &UTF8Name_offset);
+
+        old_pos = g_vfs_afp_reply_get_pos (reply);
+        g_vfs_afp_reply_seek (reply, start_pos + UTF8Name_offset + 4, G_SEEK_SET);
+
+        g_vfs_afp_reply_read_afp_name (reply, TRUE, &afp_name);
+        utf8_name = g_vfs_afp_name_get_string (afp_name);
+        g_debug ("File: %s\n", utf8_name);        
+
+        g_vfs_afp_name_unref (afp_name);
+        g_free (utf8_name);
+        
+        g_vfs_afp_reply_seek (reply, old_pos, G_SEEK_SET);
+      }
+    }
+
+    g_vfs_afp_reply_seek (reply, start_pos + struct_length, G_SEEK_SET);
+  }
+
+  g_vfs_job_succeeded (G_VFS_JOB (job));
+  g_vfs_job_enumerate_done (job);
+}
+  
+static gboolean
+try_enumerate (GVfsBackend *backend,
+               GVfsJobEnumerate *job,
+               const char *filename,
+               GFileAttributeMatcher *attribute_matcher,
+               GFileQueryInfoFlags flags)
+{
+  GVfsBackendAfp *afp_backend = G_VFS_BACKEND_AFP (backend);
+
+  if (afp_backend->server->version >= AFP_VERSION_3_1)
+  {
+    GVfsAfpCommand *comm;
+    AfpFileBitmap file_bitmap;
+    AfpDirBitmap dir_bitmap;
+    GVfsAfpName *Pathname;
+
+    comm = g_vfs_afp_command_new (AFP_COMMAND_ENUMERATE_EXT2);
+    /* pad byte */
+    g_data_output_stream_put_byte (G_DATA_OUTPUT_STREAM (comm), 0, NULL, NULL);
+
+    /* Volume ID */
+    g_data_output_stream_put_uint16 (G_DATA_OUTPUT_STREAM (comm),
+                                     afp_backend->volume_id, NULL, NULL);
+
+    /* Directory ID 2 == / */
+    g_data_output_stream_put_int32 (G_DATA_OUTPUT_STREAM (comm), 2, NULL, NULL);
+
+    /* File Bitmap */
+    file_bitmap = AFP_FILE_BITMAP_UTF8_NAME_BIT;
+    g_data_output_stream_put_int16 (G_DATA_OUTPUT_STREAM (comm),  file_bitmap,
+                                    NULL, NULL);
+    /* Dir Bitmap */
+    dir_bitmap = AFP_DIR_BITMAP_UTF8_NAME_BIT;
+    g_data_output_stream_put_int16 (G_DATA_OUTPUT_STREAM (comm),  dir_bitmap,
+                                    NULL, NULL);
+
+    /* Req Count */
+    g_data_output_stream_put_int16 (G_DATA_OUTPUT_STREAM (comm),  ENUMERATE_REQ_COUNT,
+                                    NULL, NULL);
+    /* StartIndex */
+    g_data_output_stream_put_int32 (G_DATA_OUTPUT_STREAM (comm),  1,
+                                    NULL, NULL);
+    /* MaxReplySize */
+    g_data_output_stream_put_int32 (G_DATA_OUTPUT_STREAM (comm),  G_MAXINT32,
+                                    NULL, NULL);
+
+    /* PathType */
+    g_data_output_stream_put_byte (G_DATA_OUTPUT_STREAM (comm), AFP_PATH_TYPE_UTF8_NAME,
+                                   NULL, NULL);
+
+    Pathname = filename_to_afp_pathname (filename);
+    g_vfs_afp_command_put_afp_name (comm, Pathname);
+    g_vfs_afp_name_unref (Pathname);
+
+    g_vfs_afp_connection_queue_command (afp_backend->server->conn, comm,
+                                        enumerate_ext2_cb,
+                                        G_VFS_JOB (job)->cancellable, job);
+    g_object_unref (comm);
+  }
+
+  else
+  {
+    g_vfs_job_failed_literal (G_VFS_JOB (job), G_IO_ERROR, G_IO_ERROR_FAILED,
+                              "Enumeration not supported for AFP_VERSION_3_0 yet");
+  }
+
+  return TRUE;
 }
-#endif
 
 static void
 get_vol_parms_cb (GVfsAfpConnection *afp_connection,
@@ -157,8 +340,6 @@ try_query_info (GVfsBackend *backend,
 {
   GVfsBackendAfp *afp_backend = G_VFS_BACKEND_AFP (backend);
   
-  g_debug ("filename: %s\n", filename);
-  
   if (is_root (filename))
   {
     GIcon *icon;
@@ -181,8 +362,8 @@ try_query_info (GVfsBackend *backend,
       /* pad byte */
       g_data_output_stream_put_byte (G_DATA_OUTPUT_STREAM (comm), 0, NULL, NULL);
       /* Volume ID */
-      g_data_output_stream_put_uint16 (G_DATA_OUTPUT_STREAM (comm),
-                                       afp_backend->volume_id, NULL, NULL);
+      g_data_output_stream_put_int16 (G_DATA_OUTPUT_STREAM (comm),
+                                      afp_backend->volume_id, NULL, NULL);
 
       bitmap = AFP_VOLUME_BITMAP_CREATE_DATE_BIT | AFP_VOLUME_BITMAP_MOD_DATE_BIT;
       g_data_output_stream_put_uint16 (G_DATA_OUTPUT_STREAM (comm), bitmap, NULL, NULL);
@@ -190,6 +371,7 @@ try_query_info (GVfsBackend *backend,
       g_vfs_afp_connection_queue_command (afp_backend->server->conn, comm,
                                           get_vol_parms_cb, G_VFS_JOB (job)->cancellable,
                                           job);
+      g_object_unref (comm);
       return TRUE;
     }
 
@@ -249,6 +431,7 @@ do_mount (GVfsBackend *backend,
   res = g_vfs_afp_connection_send_command_sync (afp_backend->server->conn,
                                                 comm, G_VFS_JOB (job)->cancellable,
                                                 &err);
+  g_object_unref (comm);
   if (!res)
     goto error;
 
@@ -397,6 +580,7 @@ g_vfs_backend_afp_class_init (GVfsBackendAfpClass *klass)
 	backend_class->try_mount = try_mount;
   backend_class->mount = do_mount;
   backend_class->try_query_info = try_query_info;
+  backend_class->try_enumerate = try_enumerate;
 }
 
 void



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]