File attribute renames: std:: -> standard:: fs:: -> filesystem:: id::fs ->
[platform/upstream/glib.git] / gio / glocalfileinfo.c
index 5f6176b..a633fd1 100644 (file)
 
 #include <config.h>
 
+#ifdef HAVE_SYS_TIME_H
 #include <sys/time.h>
+#endif
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <string.h>
+#ifdef HAVE_UNISTD_H
 #include <unistd.h>
+#endif
 #include <fcntl.h>
 #include <errno.h>
 #ifdef HAVE_GRP_H
 #endif /* HAVE_XATTR */
 
 #include <glib/gstdio.h>
+#include <glib/gchecksum.h>
+#include <gfileattribute-priv.h>
+
 #include "glibintl.h"
 
+#ifdef G_OS_WIN32
+#include <windows.h>
+#include <io.h>
+#ifndef W_OK
+#define W_OK 2
+#endif
+#ifndef R_OK
+#define R_OK 4
+#endif
+#ifndef X_OK
+#define X_OK 0 /* not really */
+#endif
+#ifndef S_ISREG
+#define S_ISREG(m) (((m) & _S_IFMT) == _S_IFREG)
+#endif
+#ifndef S_ISDIR
+#define S_ISDIR(m) (((m) & _S_IFMT) == _S_IFDIR)
+#endif
+#ifndef S_IXUSR
+#define S_IXUSR _S_IEXEC
+#endif
+#endif
+
 #include "glocalfileinfo.h"
 #include "gioerror.h"
 #include "gthemedicon.h"
 #include "gcontenttype.h"
 #include "gcontenttypeprivate.h"
 
+#include "gioalias.h"
+
 struct ThumbMD5Context {
        guint32 buf[4];
        guint32 bits[2];
        unsigned char in[64];
 };
-
+#ifndef G_OS_WIN32
 typedef struct {
   char *user_name;
   char *real_name;
 } UidData;
-
+#endif
 G_LOCK_DEFINE_STATIC (uid_cache);
 static GHashTable *uid_cache = NULL;
 
 G_LOCK_DEFINE_STATIC (gid_cache);
 static GHashTable *gid_cache = NULL;
 
-static void thumb_md5 (const char *string, unsigned char digest[16]);
-
 char *
 _g_local_file_info_create_etag (struct stat *statbuf)
 {
@@ -147,15 +177,15 @@ read_link (const gchar *full_name)
 
 /* Get the SELinux security context */
 static void
-get_selinux_context (const char *path,
-                    GFileInfo *info,
+get_selinux_context (const char            *path,
+                    GFileInfo             *info,
                     GFileAttributeMatcher *attribute_matcher,
-                    gboolean follow_symlinks)
+                    gboolean               follow_symlinks)
 {
 #ifdef HAVE_SELINUX
   char *context;
 
-  if (!g_file_attribute_matcher_matches (attribute_matcher, "selinux:context"))
+  if (!g_file_attribute_matcher_matches (attribute_matcher, "selinux::context"))
     return;
   
   if (is_selinux_enabled ())
@@ -173,7 +203,7 @@ get_selinux_context (const char *path,
 
       if (context)
        {
-         g_file_info_set_attribute_string (info, "selinux:context", context);
+         g_file_info_set_attribute_string (info, "selinux::context", context);
          freecon(context);
        }
     }
@@ -182,6 +212,47 @@ get_selinux_context (const char *path,
 
 #ifdef HAVE_XATTR
 
+/* Wrappers to hide away differences between (Linux) getxattr/lgetxattr and
+ * (Mac) getxattr(..., XATTR_NOFOLLOW)
+ */
+#ifdef HAVE_XATTR_NOFOLLOW
+#define g_fgetxattr(fd,name,value,size)  fgetxattr(fd,name,value,size,0,0)
+#define g_flistxattr(fd,name,size)       flistxattr(fd,name,size,0)
+#define g_setxattr(path,name,value,size) setxattr(path,name,value,size,0,0)
+#else
+#define g_fgetxattr     fgetxattr
+#define g_flistxattr    flistxattr
+#define g_setxattr(path,name,value,size) setxattr(path,name,value,size,0)
+#endif
+
+static ssize_t
+g_getxattr (const char *path, const char *name, void *value, size_t size,
+            gboolean follow_symlinks)
+{
+#ifdef HAVE_XATTR_NOFOLLOW
+  return getxattr (path, name, value, size, 0, follow_symlinks ? 0 : XATTR_NOFOLLOW);
+#else
+  if (follow_symlinks)
+    return getxattr (path, name, value, size);
+  else
+    return lgetxattr (path, name, value, size);
+#endif
+}
+
+static ssize_t
+g_listxattr(const char *path, char *namebuf, size_t size,
+            gboolean follow_symlinks)
+{
+#ifdef HAVE_XATTR_NOFOLLOW
+  return listxattr (path, namebuf, size, follow_symlinks ? 0 : XATTR_NOFOLLOW);
+#else
+  if (follow_symlinks)
+    return listxattr (path, namebuf, size);
+  else
+    return llistxattr (path, namebuf, size);
+#endif
+}
+
 static gboolean
 valid_char (char c)
 {
@@ -200,7 +271,8 @@ name_is_valid (const char *str)
 }
 
 static char *
-hex_escape_string (const char *str, gboolean *free_return)
+hex_escape_string (const char *str, 
+                   gboolean   *free_return)
 {
   int num_invalid, i;
   char *escaped_str, *p;
@@ -246,7 +318,9 @@ hex_escape_string (const char *str, gboolean *free_return)
 }
 
 static char *
-hex_unescape_string (const char *str, int *out_len, gboolean *free_return)
+hex_unescape_string (const char *str, 
+                     int        *out_len, 
+                     gboolean   *free_return)
 {
   int i;
   char *unescaped_str, *p;
@@ -290,10 +364,10 @@ hex_unescape_string (const char *str, int *out_len, gboolean *free_return)
 }
 
 static void
-escape_xattr (GFileInfo *info,
+escape_xattr (GFileInfo  *info,
              const char *gio_attr, /* gio attribute name */
              const char *value, /* Is zero terminated */
-             size_t len /* not including zero termination */)
+             size_t      len /* not including zero termination */)
 {
   char *escaped_val;
   gboolean free_escaped_val;
@@ -308,39 +382,30 @@ escape_xattr (GFileInfo *info,
 
 static void
 get_one_xattr (const char *path,
-              GFileInfo *info,
+              GFileInfo  *info,
               const char *gio_attr,
               const char *xattr,
-              gboolean follow_symlinks)
+              gboolean    follow_symlinks)
 {
   char value[64];
   char *value_p;
   ssize_t len;
 
-  if (follow_symlinks)  
-    len = getxattr (path, xattr, value, sizeof (value)-1);
-  else
-    len = lgetxattr (path, xattr,value, sizeof (value)-1);
+  len = g_getxattr (path, xattr, value, sizeof (value)-1, follow_symlinks);
 
   value_p = NULL;
   if (len >= 0)
     value_p = value;
   else if (len == -1 && errno == ERANGE)
     {
-      if (follow_symlinks)  
-       len = getxattr (path, xattr, NULL, 0);
-      else
-       len = lgetxattr (path, xattr, NULL, 0);
+      len = g_getxattr (path, xattr, NULL, 0, follow_symlinks);
 
       if (len < 0)
        return;
 
       value_p = g_malloc (len+1);
 
-      if (follow_symlinks)  
-       len = getxattr (path, xattr, value_p, len);
-      else
-       len = lgetxattr (path, xattr, value_p, len);
+      len = g_getxattr (path, xattr, value_p, len, follow_symlinks);
 
       if (len < 0)
        {
@@ -363,11 +428,11 @@ get_one_xattr (const char *path,
 #endif /* defined HAVE_XATTR */
 
 static void
-get_xattrs (const char *path,
-           gboolean user,
-           GFileInfo *info,
+get_xattrs (const char            *path,
+           gboolean               user,
+           GFileInfo             *info,
            GFileAttributeMatcher *matcher,
-           gboolean follow_symlinks)
+           gboolean               follow_symlinks)
 {
 #ifdef HAVE_XATTR
   gboolean all;
@@ -384,10 +449,7 @@ get_xattrs (const char *path,
 
   if (all)
     {
-      if (follow_symlinks)
-       list_res_size = listxattr (path, NULL, 0);
-      else
-       list_res_size = llistxattr (path, NULL, 0);
+      list_res_size = g_listxattr (path, NULL, 0, follow_symlinks);
 
       if (list_res_size == -1 ||
          list_res_size == 0)
@@ -398,10 +460,7 @@ get_xattrs (const char *path,
 
     retry:
       
-      if (follow_symlinks)
-       list_res_size = listxattr (path, list, list_size);
-      else
-       list_res_size = llistxattr (path, list, list_size);
+      list_res_size = g_listxattr (path, list, list_size, follow_symlinks);
       
       if (list_res_size == -1 && errno == ERANGE)
        {
@@ -425,12 +484,12 @@ get_xattrs (const char *path,
              if (user)
                {
                  escaped_attr = hex_escape_string (attr + 5, &free_escaped_attr);
-                 gio_attr = g_strconcat ("xattr:", escaped_attr, NULL);
+                 gio_attr = g_strconcat ("xattr::", escaped_attr, NULL);
                }
              else
                {
                  escaped_attr = hex_escape_string (attr, &free_escaped_attr);
-                 gio_attr = g_strconcat ("xattr_sys:", escaped_attr, NULL);
+                 gio_attr = g_strconcat ("xattr-sys::", escaped_attr, NULL);
                }
              
              if (free_escaped_attr)
@@ -478,8 +537,8 @@ get_xattrs (const char *path,
 
 #ifdef HAVE_XATTR
 static void
-get_one_xattr_from_fd (int fd,
-                      GFileInfo *info,
+get_one_xattr_from_fd (int         fd,
+                      GFileInfo  *info,
                       const char *gio_attr,
                       const char *xattr)
 {
@@ -487,21 +546,21 @@ get_one_xattr_from_fd (int fd,
   char *value_p;
   ssize_t len;
 
-  len = fgetxattr (fd, xattr, value, sizeof (value)-1);
+  len = g_fgetxattr (fd, xattr, value, sizeof (value)-1);
 
   value_p = NULL;
   if (len >= 0)
     value_p = value;
   else if (len == -1 && errno == ERANGE)
     {
-      len = fgetxattr (fd, xattr, NULL, 0);
+      len = g_fgetxattr (fd, xattr, NULL, 0);
 
       if (len < 0)
        return;
 
       value_p = g_malloc (len+1);
 
-      len = fgetxattr (fd, xattr, value_p, len);
+      len = g_fgetxattr (fd, xattr, value_p, len);
 
       if (len < 0)
        {
@@ -523,9 +582,9 @@ get_one_xattr_from_fd (int fd,
 #endif /* defined HAVE_XATTR */
 
 static void
-get_xattrs_from_fd (int fd,
-                   gboolean user,
-                   GFileInfo *info,
+get_xattrs_from_fd (int                    fd,
+                   gboolean               user,
+                   GFileInfo             *info,
                    GFileAttributeMatcher *matcher)
 {
 #ifdef HAVE_XATTR
@@ -539,11 +598,11 @@ get_xattrs_from_fd (int fd,
   if (user)
     all = g_file_attribute_matcher_enumerate_namespace (matcher, "xattr");
   else
-    all = g_file_attribute_matcher_enumerate_namespace (matcher, "xattr_sys");
+    all = g_file_attribute_matcher_enumerate_namespace (matcher, "xattr-sys");
 
   if (all)
     {
-      list_res_size = flistxattr (fd, NULL, 0);
+      list_res_size = g_flistxattr (fd, NULL, 0);
 
       if (list_res_size == -1 ||
          list_res_size == 0)
@@ -554,7 +613,7 @@ get_xattrs_from_fd (int fd,
 
     retry:
       
-      list_res_size = flistxattr (fd, list, list_size);
+      list_res_size = g_flistxattr (fd, list, list_size);
       
       if (list_res_size == -1 && errno == ERANGE)
        {
@@ -578,12 +637,12 @@ get_xattrs_from_fd (int fd,
              if (user)
                {
                  escaped_attr = hex_escape_string (attr + 5, &free_escaped_attr);
-                 gio_attr = g_strconcat ("xattr:", escaped_attr, NULL);
+                 gio_attr = g_strconcat ("xattr::", escaped_attr, NULL);
                }
              else
                {
                  escaped_attr = hex_escape_string (attr, &free_escaped_attr);
-                 gio_attr = g_strconcat ("xattr_sys:", escaped_attr, NULL);
+                 gio_attr = g_strconcat ("xattr-sys::", escaped_attr, NULL);
                }
              
              if (free_escaped_attr)
@@ -631,10 +690,10 @@ get_xattrs_from_fd (int fd,
 
 #ifdef HAVE_XATTR
 static gboolean
-set_xattr (char *filename,
-          const char *escaped_attribute,
-          const GFileAttributeValue *attr_value,
-          GError **error)
+set_xattr (char                       *filename,
+          const char                 *escaped_attribute,
+          const GFileAttributeValue  *attr_value,
+          GError                    **error)
 {
   char *attribute, *value;
   gboolean free_attribute, free_value;
@@ -663,14 +722,14 @@ set_xattr (char *filename,
       return FALSE;
     }
 
-  if (g_str_has_prefix (escaped_attribute, "xattr:"))
+  if (g_str_has_prefix (escaped_attribute, "xattr::"))
     {
       escaped_attribute += 6;
       is_user = TRUE;
     }
   else
     {
-      g_assert (g_str_has_prefix (escaped_attribute, "xattr_sys:"));
+      g_warn_if_fail (g_str_has_prefix (escaped_attribute, "xattr-sys::"));
       escaped_attribute += 10;
       is_user = FALSE;
     }
@@ -678,13 +737,12 @@ set_xattr (char *filename,
   attribute = hex_unescape_string (escaped_attribute, NULL, &free_attribute);
   value = hex_unescape_string (attr_value->u.string, &val_len, &free_value);
 
-
   if (is_user)
     a = g_strconcat ("user.", attribute, NULL);
   else
     a = attribute;
   
-  res = setxattr (filename, a, value, val_len, 0);
+  res = g_setxattr (filename, a, value, val_len);
   errsv = errno;
   
   if (is_user)
@@ -712,9 +770,9 @@ set_xattr (char *filename,
 
 
 void
-_g_local_file_info_get_parent_info (const char             *dir,
-                                   GFileAttributeMatcher  *attribute_matcher,
-                                   GLocalParentFileInfo   *parent_info)
+_g_local_file_info_get_parent_info (const char            *dir,
+                                   GFileAttributeMatcher *attribute_matcher,
+                                   GLocalParentFileInfo  *parent_info)
 {
   struct stat statbuf;
   int res;
@@ -739,7 +797,11 @@ _g_local_file_info_get_parent_info (const char             *dir,
        */
       if (res == 0)
        {
+#ifdef S_ISVTX
          parent_info->is_sticky = (statbuf.st_mode & S_ISVTX) != 0;
+#else
+         parent_info->is_sticky = FALSE;
+#endif
          parent_info->owner = statbuf.st_uid;
          parent_info->device = statbuf.st_dev;
        }
@@ -748,10 +810,10 @@ _g_local_file_info_get_parent_info (const char             *dir,
 
 static void
 get_access_rights (GFileAttributeMatcher *attribute_matcher,
-                  GFileInfo *info,
-                  const gchar *path,
-                  struct stat *statbuf,
-                  GLocalParentFileInfo *parent_info)
+                  GFileInfo             *info,
+                  const gchar           *path,
+                  struct stat           *statbuf,
+                  GLocalParentFileInfo  *parent_info)
 {
   if (g_file_attribute_matcher_matches (attribute_matcher,
                                        G_FILE_ATTRIBUTE_ACCESS_CAN_READ))
@@ -778,11 +840,13 @@ get_access_rights (GFileAttributeMatcher *attribute_matcher,
        {
          if (parent_info->is_sticky)
            {
+#ifndef G_OS_WIN32
              uid_t uid = geteuid ();
 
              if (uid == statbuf->st_uid ||
                  uid == parent_info->owner ||
                  uid == 0)
+#endif
                writable = TRUE;
            }
          else
@@ -805,7 +869,8 @@ get_access_rights (GFileAttributeMatcher *attribute_matcher,
 }
 
 static void
-set_info_from_stat (GFileInfo *info, struct stat *statbuf,
+set_info_from_stat (GFileInfo             *info, 
+                    struct stat           *statbuf,
                    GFileAttributeMatcher *attribute_matcher)
 {
   GFileType file_type;
@@ -816,6 +881,7 @@ set_info_from_stat (GFileInfo *info, struct stat *statbuf,
     file_type = G_FILE_TYPE_REGULAR;
   else if (S_ISDIR (statbuf->st_mode))
     file_type = G_FILE_TYPE_DIRECTORY;
+#ifndef G_OS_WIN32
   else if (S_ISCHR (statbuf->st_mode) ||
           S_ISBLK (statbuf->st_mode) ||
           S_ISFIFO (statbuf->st_mode)
@@ -824,6 +890,7 @@ set_info_from_stat (GFileInfo *info, struct stat *statbuf,
 #endif
           )
     file_type = G_FILE_TYPE_SPECIAL;
+#endif
 #ifdef S_ISLNK
   else if (S_ISLNK (statbuf->st_mode))
     file_type = G_FILE_TYPE_SYMBOLIC_LINK;
@@ -884,10 +951,10 @@ set_info_from_stat (GFileInfo *info, struct stat *statbuf,
     }
 
   if (g_file_attribute_matcher_matches (attribute_matcher,
-                                       G_FILE_ATTRIBUTE_ID_FS))
+                                       G_FILE_ATTRIBUTE_ID_FILESYSTEM))
     {
       char *id = _g_local_file_info_create_fs_id (statbuf);
-      g_file_info_set_attribute_string (info, G_FILE_ATTRIBUTE_ID_FS, id);
+      g_file_info_set_attribute_string (info, G_FILE_ATTRIBUTE_ID_FILESYSTEM, id);
       g_free (id);
     }
 }
@@ -925,7 +992,7 @@ make_valid_utf8 (const char *name)
   
   g_string_append (string, remainder);
 
-  g_assert (g_utf8_validate (string->str, -1, NULL));
+  g_warn_if_fail (g_utf8_validate (string->str, -1, NULL));
   
   return g_string_free (string, FALSE);
 }
@@ -946,7 +1013,7 @@ convert_pwd_string_to_utf8 (char *pwd_str)
   
   return utf8_string;
 }
-
+#ifndef G_OS_WIN32
 static void
 uid_data_free (UidData *data)
 {
@@ -1044,7 +1111,6 @@ get_realname_from_uid (uid_t uid)
   return res;
 }
 
-
 /* called with lock held */
 static char *
 lookup_gid_name (gid_t gid)
@@ -1094,27 +1160,30 @@ get_groupname_from_gid (gid_t gid)
   G_UNLOCK (gid_cache);
   return res;
 }
+#endif /* !G_OS_WIN32 */
 
 static char *
-get_content_type (const char *basename,
-                 const char *path,
-                 struct stat *statbuf,
-                 gboolean is_symlink,
-                 gboolean symlink_broken,
-                 GFileQueryInfoFlags flags,
-                 gboolean fast)
+get_content_type (const char          *basename,
+                 const char          *path,
+                 struct stat         *statbuf,
+                 gboolean             is_symlink,
+                 gboolean             symlink_broken,
+                 GFileQueryInfoFlags  flags,
+                 gboolean             fast)
 {
   if (is_symlink &&
       (symlink_broken || (flags & G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS)))
     return g_strdup  ("inode/symlink");
   else if (S_ISDIR(statbuf->st_mode))
     return g_strdup ("inode/directory");
+#ifndef G_OS_WIN32
   else if (S_ISCHR(statbuf->st_mode))
     return g_strdup ("inode/chardevice");
   else if (S_ISBLK(statbuf->st_mode))
     return g_strdup ("inode/blockdevice");
   else if (S_ISFIFO(statbuf->st_mode))
     return g_strdup ("inode/fifo");
+#endif
 #ifdef S_ISSOCK
   else if (S_ISSOCK(statbuf->st_mode))
     return g_strdup ("inode/socket");
@@ -1158,51 +1227,37 @@ get_content_type (const char *basename,
   
 }
 
-static char *
-thumb_digest_to_ascii (unsigned char digest[16], const char *suffix)
-{
-  static const char hex_digits[] = "0123456789abcdef";
-  char *res;
-  int i;
-  
-  res = g_malloc (33 + strlen (suffix));
-  
-  for (i = 0; i < 16; i++) {
-    res[2*i] = hex_digits[digest[i] >> 4];
-    res[2*i+1] = hex_digits[digest[i] & 0xf];
-  }
-  
-  res[32] = 0;
-
-  strcat (res, suffix);
-  
-  return res;
-}
-
-
 static void
 get_thumbnail_attributes (const char *path,
-                         GFileInfo *info)
+                          GFileInfo  *info)
 {
+  GChecksum *checksum;
   char *uri;
-  unsigned char digest[16];
   char *filename;
   char *basename;
 
   uri = g_filename_to_uri (path, NULL, NULL);
-  thumb_md5 (uri, digest);
-  g_free (uri);
 
-  basename = thumb_digest_to_ascii (digest, ".png");
+  checksum = g_checksum_new (G_CHECKSUM_MD5);
+  g_checksum_update (checksum, (const guchar *) uri, strlen (uri));
 
-  filename = g_build_filename (g_get_home_dir(), ".thumbnails", "normal", basename, NULL);
+  basename = g_strconcat (g_checksum_get_string (checksum), ".png", NULL);
+  g_checksum_free (checksum);
+
+  filename = g_build_filename (g_get_home_dir(),
+                               ".thumbnails", "normal", basename,
+                               NULL);
 
   if (g_file_test (filename, G_FILE_TEST_IS_REGULAR))
     g_file_info_set_attribute_byte_string (info, G_FILE_ATTRIBUTE_THUMBNAIL_PATH, filename);
   else
     {
       g_free (filename);
-      filename = g_build_filename (g_get_home_dir(), ".thumbnails", "fail", "gnome-thumbnail-factory", basename, NULL);
+      filename = g_build_filename (g_get_home_dir(),
+                                   ".thumbnails", "fail",
+                                   "gnome-thumbnail-factory",
+                                   basename,
+                                   NULL);
 
       if (g_file_test (filename, G_FILE_TEST_IS_REGULAR))
        g_file_info_set_attribute_boolean (info, G_FILE_ATTRIBUTE_THUMBNAILING_FAILED, TRUE);
@@ -1211,14 +1266,105 @@ get_thumbnail_attributes (const char *path,
   g_free (filename);
 }
 
+#ifdef G_OS_WIN32
+static void
+win32_get_file_user_info (const gchar* filename,
+                         gchar **group_name, 
+                         gchar **user_name, 
+                         gchar **real_name)
+{
+  PSECURITY_DESCRIPTOR psd = NULL;
+  DWORD sd_size = 0; /* first call calculates the size required */
+  
+  wchar_t *wfilename = g_utf8_to_utf16 (filename, -1, NULL, NULL, NULL);
+  if ((GetFileSecurityW (wfilename, 
+                        GROUP_SECURITY_INFORMATION | OWNER_SECURITY_INFORMATION,
+                       NULL,
+                       sd_size,
+                       &sd_size) || (ERROR_INSUFFICIENT_BUFFER == GetLastError())) &&
+     (psd = g_try_malloc (sd_size)) != NULL &&
+     GetFileSecurityW (wfilename, 
+                       GROUP_SECURITY_INFORMATION | OWNER_SECURITY_INFORMATION,
+                      psd,
+                      sd_size,
+                      &sd_size))
+    {
+      PSID psid = 0;
+      BOOL defaulted;
+      SID_NAME_USE name_use = 0; /* don't care? */
+      wchar_t *name = NULL;
+      wchar_t *domain = NULL;
+      DWORD name_len = 0;
+      DWORD domain_len = 0;
+      /* get the user name */
+      do {
+        if (!user_name)
+         break;
+       if (!GetSecurityDescriptorOwner (psd, &psid, &defaulted))
+         break;
+       if (!LookupAccountSidW (NULL, /* local machine */
+                                psid, 
+                               name, &name_len,
+                               domain, &domain_len, /* no domain info yet */
+                               &name_use)  && (ERROR_INSUFFICIENT_BUFFER != GetLastError()))
+         break;
+       name = g_try_malloc (name_len*sizeof(wchar_t));
+       domain = g_try_malloc (domain_len*sizeof(wchar_t));
+       if (name && domain &&
+            LookupAccountSidW (NULL, /* local machine */
+                               psid, 
+                              name, &name_len,
+                              domain, &domain_len, /* no domain info yet */
+                              &name_use))
+         {
+           *user_name = g_utf16_to_utf8 (name, -1, NULL, NULL, NULL);
+         }
+       g_free (name);
+       g_free (domain);
+      } while (FALSE);
+
+      /* get the group name */
+      do {
+        if (!group_name)
+         break;
+       if (!GetSecurityDescriptorGroup (psd, &psid, &defaulted))
+         break;
+       if (!LookupAccountSidW (NULL, /* local machine */
+                                psid, 
+                               name, &name_len,
+                               domain, &domain_len, /* no domain info yet */
+                               &name_use)  && (ERROR_INSUFFICIENT_BUFFER != GetLastError()))
+         break;
+       name = g_try_malloc (name_len*sizeof(wchar_t));
+       domain = g_try_malloc (domain_len*sizeof(wchar_t));
+       if (name && domain &&
+            LookupAccountSidW (NULL, /* local machine */
+                               psid, 
+                              name, &name_len,
+                              domain, &domain_len, /* no domain info yet */
+                              &name_use))
+         {
+           *group_name = g_utf16_to_utf8 (name, -1, NULL, NULL, NULL);
+         }
+       g_free (name);
+       g_free (domain);
+      } while (FALSE);
+
+      /* TODO: get real name */
+
+      g_free (psd);
+    }
+  g_free (wfilename);
+}
+#endif /* G_OS_WIN32 */
 
 GFileInfo *
-_g_local_file_info_get (const char *basename,
-                       const char *path,
-                       GFileAttributeMatcher *attribute_matcher,
-                       GFileQueryInfoFlags flags,
-                       GLocalParentFileInfo *parent_info,
-                       GError **error)
+_g_local_file_info_get (const char             *basename,
+                       const char             *path,
+                       GFileAttributeMatcher  *attribute_matcher,
+                       GFileQueryInfoFlags     flags,
+                       GLocalParentFileInfo   *parent_info,
+                       GError                **error)
 {
   GFileInfo *info;
   struct stat statbuf;
@@ -1278,11 +1424,11 @@ _g_local_file_info_get (const char *basename,
     g_file_info_set_is_hidden (info, TRUE);
 
   if (basename != NULL && basename[strlen (basename) -1] == '~')
-    g_file_info_set_attribute_boolean (info, G_FILE_ATTRIBUTE_STD_IS_BACKUP, TRUE);
+    g_file_info_set_attribute_boolean (info, G_FILE_ATTRIBUTE_STANDARD_IS_BACKUP, TRUE);
 
   if (is_symlink &&
       g_file_attribute_matcher_matches (attribute_matcher,
-                                       G_FILE_ATTRIBUTE_STD_SYMLINK_TARGET))
+                                       G_FILE_ATTRIBUTE_STANDARD_SYMLINK_TARGET))
     {
       char *link = read_link (path);
       g_file_info_set_symlink_target (info, link);
@@ -1290,7 +1436,7 @@ _g_local_file_info_get (const char *basename,
     }
 
   if (g_file_attribute_matcher_matches (attribute_matcher,
-                                       G_FILE_ATTRIBUTE_STD_DISPLAY_NAME))
+                                       G_FILE_ATTRIBUTE_STANDARD_DISPLAY_NAME))
     {
       char *display_name = g_filename_display_basename (path);
       
@@ -1305,7 +1451,7 @@ _g_local_file_info_get (const char *basename,
     }
   
   if (g_file_attribute_matcher_matches (attribute_matcher,
-                                       G_FILE_ATTRIBUTE_STD_EDIT_NAME))
+                                       G_FILE_ATTRIBUTE_STANDARD_EDIT_NAME))
     {
       char *edit_name = g_filename_display_basename (path);
       g_file_info_set_edit_name (info, edit_name);
@@ -1314,18 +1460,18 @@ _g_local_file_info_get (const char *basename,
 
   
   if (g_file_attribute_matcher_matches (attribute_matcher,
-                                       G_FILE_ATTRIBUTE_STD_COPY_NAME))
+                                       G_FILE_ATTRIBUTE_STANDARD_COPY_NAME))
     {
       char *copy_name = g_filename_to_utf8 (basename, -1, NULL, NULL, NULL);
       if (copy_name)
-       g_file_info_set_attribute_string (info, G_FILE_ATTRIBUTE_STD_COPY_NAME, copy_name);
+       g_file_info_set_attribute_string (info, G_FILE_ATTRIBUTE_STANDARD_COPY_NAME, copy_name);
       g_free (copy_name);
     }
 
   if (g_file_attribute_matcher_matches (attribute_matcher,
-                                       G_FILE_ATTRIBUTE_STD_CONTENT_TYPE) ||
+                                       G_FILE_ATTRIBUTE_STANDARD_CONTENT_TYPE) ||
       g_file_attribute_matcher_matches (attribute_matcher,
-                                       G_FILE_ATTRIBUTE_STD_ICON))
+                                       G_FILE_ATTRIBUTE_STANDARD_ICON))
     {
       char *content_type = get_content_type (basename, path, &statbuf, is_symlink, symlink_broken, flags, FALSE);
 
@@ -1334,7 +1480,7 @@ _g_local_file_info_get (const char *basename,
          g_file_info_set_content_type (info, content_type);
 
          if (g_file_attribute_matcher_matches (attribute_matcher,
-                                               G_FILE_ATTRIBUTE_STD_ICON))
+                                               G_FILE_ATTRIBUTE_STANDARD_ICON))
            {
              char *mimetype_icon, *generic_mimetype_icon, *type_icon, *p;
              char *icon_names[3];
@@ -1385,13 +1531,13 @@ _g_local_file_info_get (const char *basename,
     }
 
   if (g_file_attribute_matcher_matches (attribute_matcher,
-                                       G_FILE_ATTRIBUTE_STD_FAST_CONTENT_TYPE))
+                                       G_FILE_ATTRIBUTE_STANDARD_FAST_CONTENT_TYPE))
     {
       char *content_type = get_content_type (basename, path, &statbuf, is_symlink, symlink_broken, flags, TRUE);
       
       if (content_type)
        {
-         g_file_info_set_attribute_string (info, G_FILE_ATTRIBUTE_STD_FAST_CONTENT_TYPE, content_type);
+         g_file_info_set_attribute_string (info, G_FILE_ATTRIBUTE_STANDARD_FAST_CONTENT_TYPE, content_type);
          g_free (content_type);
        }
     }
@@ -1399,9 +1545,13 @@ _g_local_file_info_get (const char *basename,
   if (g_file_attribute_matcher_matches (attribute_matcher,
                                        G_FILE_ATTRIBUTE_OWNER_USER))
     {
-      char *name;
+      char *name = NULL;
       
+#ifdef G_OS_WIN32
+      win32_get_file_user_info (path, NULL, &name, NULL);
+#else
       name = get_username_from_uid (statbuf.st_uid);
+#endif
       if (name)
        g_file_info_set_attribute_string (info, G_FILE_ATTRIBUTE_OWNER_USER, name);
       g_free (name);
@@ -1410,9 +1560,12 @@ _g_local_file_info_get (const char *basename,
   if (g_file_attribute_matcher_matches (attribute_matcher,
                                        G_FILE_ATTRIBUTE_OWNER_USER_REAL))
     {
-      char *name;
-      
+      char *name = NULL;
+#ifdef G_OS_WIN32
+      win32_get_file_user_info (path, NULL, NULL, &name);
+#else
       name = get_realname_from_uid (statbuf.st_uid);
+#endif
       if (name)
        g_file_info_set_attribute_string (info, G_FILE_ATTRIBUTE_OWNER_USER_REAL, name);
       g_free (name);
@@ -1421,9 +1574,12 @@ _g_local_file_info_get (const char *basename,
   if (g_file_attribute_matcher_matches (attribute_matcher,
                                        G_FILE_ATTRIBUTE_OWNER_GROUP))
     {
-      char *name;
-      
+      char *name = NULL;
+#ifdef G_OS_WIN32
+      win32_get_file_user_info (path, &name, NULL, NULL);
+#else
       name = get_groupname_from_gid (statbuf.st_gid);
+#endif
       if (name)
        g_file_info_set_attribute_string (info, G_FILE_ATTRIBUTE_OWNER_GROUP, name);
       g_free (name);
@@ -1450,8 +1606,8 @@ _g_local_file_info_get (const char *basename,
 }
 
 GFileInfo *
-_g_local_file_info_get_from_fd (int fd,
-                               char *attributes,
+_g_local_file_info_get_from_fd (int      fd,
+                               char    *attributes,
                                GError **error)
 {
   struct stat stat_buf;
@@ -1500,9 +1656,9 @@ _g_local_file_info_get_from_fd (int fd,
 }
 
 static gboolean
-get_uint32 (const GFileAttributeValue *value,
-           guint32 *val_out,
-           GError **error)
+get_uint32 (const GFileAttributeValue  *value,
+           guint32                    *val_out,
+           GError                    **error)
 {
   if (value->type != G_FILE_ATTRIBUTE_TYPE_UINT32)
     {
@@ -1517,9 +1673,9 @@ get_uint32 (const GFileAttributeValue *value,
 }
 
 static gboolean
-get_uint64 (const GFileAttributeValue *value,
-           guint64 *val_out,
-           GError **error)
+get_uint64 (const GFileAttributeValue  *value,
+           guint64                    *val_out,
+           GError                    **error)
 {
   if (value->type != G_FILE_ATTRIBUTE_TYPE_UINT64)
     {
@@ -1535,9 +1691,9 @@ get_uint64 (const GFileAttributeValue *value,
 
 #if defined(HAVE_SYMLINK)
 static gboolean
-get_byte_string (const GFileAttributeValue *value,
-                const char **val_out,
-                GError **error)
+get_byte_string (const GFileAttributeValue  *value,
+                const char                **val_out,
+                GError                    **error)
 {
   if (value->type != G_FILE_ATTRIBUTE_TYPE_BYTE_STRING)
     {
@@ -1553,9 +1709,9 @@ get_byte_string (const GFileAttributeValue *value,
 #endif
 
 static gboolean
-set_unix_mode (char *filename,
-              const GFileAttributeValue *value,
-              GError **error)
+set_unix_mode (char                       *filename,
+              const GFileAttributeValue  *value,
+              GError                    **error)
 {
   guint32 val;
   
@@ -1575,11 +1731,11 @@ set_unix_mode (char *filename,
 
 #ifdef HAVE_CHOWN
 static gboolean
-set_unix_uid_gid (char *filename,
-                 const GFileAttributeValue *uid_value,
-                 const GFileAttributeValue *gid_value,
-                 GFileQueryInfoFlags flags,
-                 GError **error)
+set_unix_uid_gid (char                       *filename,
+                 const GFileAttributeValue  *uid_value,
+                 const GFileAttributeValue  *gid_value,
+                 GFileQueryInfoFlags         flags,
+                 GError                    **error)
 {
   int res;
   guint32 val;
@@ -1623,9 +1779,9 @@ set_unix_uid_gid (char *filename,
 
 #ifdef HAVE_SYMLINK
 static gboolean
-set_symlink (char *filename,
-            const GFileAttributeValue *value,
-            GError **error)
+set_symlink (char                       *filename,
+            const GFileAttributeValue  *value,
+            GError                    **error)
 {
   const char *val;
   struct stat statbuf;
@@ -1680,7 +1836,9 @@ set_symlink (char *filename,
 #endif
 
 static int
-lazy_stat (char *filename, struct stat *statbuf, gboolean *called_stat)
+lazy_stat (char        *filename, 
+           struct stat *statbuf, 
+           gboolean    *called_stat)
 {
   int res;
 
@@ -1698,12 +1856,12 @@ lazy_stat (char *filename, struct stat *statbuf, gboolean *called_stat)
 
 #ifdef HAVE_UTIMES
 static gboolean
-set_mtime_atime (char *filename,
-                const GFileAttributeValue *mtime_value,
-                const GFileAttributeValue *mtime_usec_value,
-                const GFileAttributeValue *atime_value,
-                const GFileAttributeValue *atime_usec_value,
-                GError **error)
+set_mtime_atime (char                       *filename,
+                const GFileAttributeValue  *mtime_value,
+                const GFileAttributeValue  *mtime_usec_value,
+                const GFileAttributeValue  *atime_value,
+                const GFileAttributeValue  *atime_usec_value,
+                GError                    **error)
 {
   int res;
   guint64 val;
@@ -1780,44 +1938,49 @@ set_mtime_atime (char *filename,
 #endif
 
 gboolean
-_g_local_file_info_set_attribute (char *filename,
-                                 const char *attribute,
-                                 const GFileAttributeValue *value,
-                                 GFileQueryInfoFlags flags,
-                                 GCancellable *cancellable,
-                                 GError **error)
+_g_local_file_info_set_attribute (char                       *filename,
+                                 const char                 *attribute,
+                                 GFileAttributeType          type,
+                                 gpointer                    value_p,
+                                 GFileQueryInfoFlags         flags,
+                                 GCancellable               *cancellable,
+                                 GError                    **error)
 {
+  GFileAttributeValue value = { 0 };
+
+  _g_file_attribute_value_set_from_pointer (&value, type, value_p, FALSE);
+  
   if (strcmp (attribute, G_FILE_ATTRIBUTE_UNIX_MODE) == 0)
-    return set_unix_mode (filename, value, error);
+    return set_unix_mode (filename, &value, error);
   
 #ifdef HAVE_CHOWN
   else if (strcmp (attribute, G_FILE_ATTRIBUTE_UNIX_UID) == 0)
-    return set_unix_uid_gid (filename, value, NULL, flags, error);
+    return set_unix_uid_gid (filename, &value, NULL, flags, error);
   else if (strcmp (attribute, G_FILE_ATTRIBUTE_UNIX_GID) == 0)
-    return set_unix_uid_gid (filename, NULL, value, flags, error);
+    return set_unix_uid_gid (filename, NULL, &value, flags, error);
 #endif
   
 #ifdef HAVE_SYMLINK
-  else if (strcmp (attribute, G_FILE_ATTRIBUTE_STD_SYMLINK_TARGET) == 0)
-    return set_symlink (filename, value, error);
+  else if (strcmp (attribute, G_FILE_ATTRIBUTE_STANDARD_SYMLINK_TARGET) == 0)
+    return set_symlink (filename, &value, error);
 #endif
 
 #ifdef HAVE_UTIMES
   else if (strcmp (attribute, G_FILE_ATTRIBUTE_TIME_MODIFIED) == 0)
-    return set_mtime_atime (filename, value, NULL, NULL, NULL, error);
+    return set_mtime_atime (filename, &value, NULL, NULL, NULL, error);
   else if (strcmp (attribute, G_FILE_ATTRIBUTE_TIME_MODIFIED_USEC) == 0)
-    return set_mtime_atime (filename, NULL, value, NULL, NULL, error);
+    return set_mtime_atime (filename, NULL, &value, NULL, NULL, error);
   else if (strcmp (attribute, G_FILE_ATTRIBUTE_TIME_ACCESS) == 0)
-    return set_mtime_atime (filename, NULL, NULL, value, NULL, error);
+    return set_mtime_atime (filename, NULL, NULL, &value, NULL, error);
   else if (strcmp (attribute, G_FILE_ATTRIBUTE_TIME_ACCESS_USEC) == 0)
-    return set_mtime_atime (filename, NULL, NULL, NULL, value, error);
+    return set_mtime_atime (filename, NULL, NULL, NULL, &value, error);
 #endif
 
 #ifdef HAVE_XATTR
-  else if (g_str_has_prefix (attribute, "xattr:"))
-    return set_xattr (filename, attribute, value, error);
-  else if (g_str_has_prefix (attribute, "xattr_sys:"))
-    return set_xattr (filename, attribute, value, error);
+  else if (g_str_has_prefix (attribute, "xattr::"))
+    return set_xattr (filename, attribute, &value, error);
+  else if (g_str_has_prefix (attribute, "xattr-sys::"))
+    return set_xattr (filename, attribute, &value, error);
 #endif
   
   g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
@@ -1826,11 +1989,11 @@ _g_local_file_info_set_attribute (char *filename,
 }
 
 gboolean
-_g_local_file_info_set_attributes  (char                       *filename,
-                                   GFileInfo                  *info,
-                                   GFileQueryInfoFlags         flags,
-                                   GCancellable               *cancellable,
-                                   GError                    **error)
+_g_local_file_info_set_attributes  (char                 *filename,
+                                   GFileInfo            *info,
+                                   GFileQueryInfoFlags   flags,
+                                   GCancellable         *cancellable,
+                                   GError              **error)
 {
   GFileAttributeValue *value, *uid, *gid;
   GFileAttributeValue *mtime, *mtime_usec, *atime, *atime_usec;
@@ -1844,7 +2007,7 @@ _g_local_file_info_set_attributes  (char                       *filename,
 
   /* Set symlink first, since this recreates the file */
 #ifdef HAVE_SYMLINK
-  value = g_file_info_get_attribute (info, G_FILE_ATTRIBUTE_STD_SYMLINK_TARGET);
+  value = _g_file_info_get_attribute_value (info, G_FILE_ATTRIBUTE_STANDARD_SYMLINK_TARGET);
   if (value)
     {
       if (!set_symlink (filename, value, error))
@@ -1865,8 +2028,8 @@ _g_local_file_info_set_attributes  (char                       *filename,
    * Change ownership before permissions, since ownership changes can
      change permissions (e.g. setuid)
    */
-  uid = g_file_info_get_attribute (info, G_FILE_ATTRIBUTE_UNIX_UID);
-  gid = g_file_info_get_attribute (info, G_FILE_ATTRIBUTE_UNIX_GID);
+  uid = _g_file_info_get_attribute_value (info, G_FILE_ATTRIBUTE_UNIX_UID);
+  gid = _g_file_info_get_attribute_value (info, G_FILE_ATTRIBUTE_UNIX_GID);
   
   if (uid || gid)
     {
@@ -1886,7 +2049,7 @@ _g_local_file_info_set_attributes  (char                       *filename,
     }
 #endif
   
-  value = g_file_info_get_attribute (info, G_FILE_ATTRIBUTE_UNIX_MODE);
+  value = _g_file_info_get_attribute_value (info, G_FILE_ATTRIBUTE_UNIX_MODE);
   if (value)
     {
       if (!set_unix_mode (filename, value, error))
@@ -1906,10 +2069,10 @@ _g_local_file_info_set_attributes  (char                       *filename,
    * Change times as the last thing to avoid it changing due to metadata changes
    */
   
-  mtime = g_file_info_get_attribute (info, G_FILE_ATTRIBUTE_TIME_MODIFIED);
-  mtime_usec = g_file_info_get_attribute (info, G_FILE_ATTRIBUTE_TIME_MODIFIED_USEC);
-  atime = g_file_info_get_attribute (info, G_FILE_ATTRIBUTE_TIME_ACCESS);
-  atime_usec = g_file_info_get_attribute (info, G_FILE_ATTRIBUTE_TIME_ACCESS_USEC);
+  mtime = _g_file_info_get_attribute_value (info, G_FILE_ATTRIBUTE_TIME_MODIFIED);
+  mtime_usec = _g_file_info_get_attribute_value (info, G_FILE_ATTRIBUTE_TIME_MODIFIED_USEC);
+  atime = _g_file_info_get_attribute_value (info, G_FILE_ATTRIBUTE_TIME_ACCESS);
+  atime_usec = _g_file_info_get_attribute_value (info, G_FILE_ATTRIBUTE_TIME_ACCESS_USEC);
 
   if (mtime || mtime_usec || atime || atime_usec)
     {
@@ -1938,279 +2101,3 @@ _g_local_file_info_set_attributes  (char                       *filename,
 
   return res;
 }
-
-
-/*
- * This code implements the MD5 message-digest algorithm.
- * The algorithm is due to Ron Rivest.  This code was
- * written by Colin Plumb in 1993, no copyright is claimed.
- * This code is in the public domain; do with it what you wish.
- *
- * Equivalent code is available from RSA Data Security, Inc.
- * This code has been tested against that, and is equivalent,
- * except that you don't need to include two pages of legalese
- * with every copy.
- *
- * To compute the message digest of a chunk of bytes, declare an
- * ThumbMD5Context structure, pass it to thumb_md5_init, call
- * thumb_md5_update as needed on buffers full of bytes, and then call
- * thumb_md5_final, which will fill a supplied 32-byte array with the
- * digest in ascii form. 
- *
- */
-
-static void thumb_md5_init      (struct ThumbMD5Context *context);
-static void thumb_md5_update    (struct ThumbMD5Context *context,
-                                unsigned char const    *buf,
-                                unsigned                len);
-static void thumb_md5_final     (unsigned char           digest[16],
-                                struct ThumbMD5Context *context);
-static void thumb_md5_transform (guint32                 buf[4],
-                                guint32 const           in[16]);
-
-
-static void
-thumb_md5 (const char *string, unsigned char digest[16])
-{
-  struct ThumbMD5Context md5_context;
-  
-  thumb_md5_init (&md5_context);
-  thumb_md5_update (&md5_context, (unsigned char *)string, strlen (string));
-  thumb_md5_final (digest, &md5_context);
-}
-
-#if G_BYTE_ORDER == G_LITTLE_ENDIAN
-#define byteReverse(buf, len)  /* Nothing */
-#else
-
-/*
- * Note: this code is harmless on little-endian machines.
- */
-static void
-byteReverse(unsigned char *buf, unsigned longs)
-{
-    guint32 t;
-    do {
-       t = (guint32) ((unsigned) buf[3] << 8 | buf[2]) << 16 |
-           ((unsigned) buf[1] << 8 | buf[0]);
-       *(guint32 *) buf = t;
-       buf += 4;
-    } while (--longs);
-}
-
-#endif
-
-/*
- * Start MD5 accumulation.  Set bit count to 0 and buffer to mysterious
- * initialization constants.
- */
-static void 
-thumb_md5_init (struct ThumbMD5Context *ctx)
-{
-    ctx->buf[0] = 0x67452301;
-    ctx->buf[1] = 0xefcdab89;
-    ctx->buf[2] = 0x98badcfe;
-    ctx->buf[3] = 0x10325476;
-
-    ctx->bits[0] = 0;
-    ctx->bits[1] = 0;
-}
-
-/*
- * Update context to reflect the concatenation of another buffer full
- * of bytes.
- */
-static void 
-thumb_md5_update (struct ThumbMD5Context *ctx,
-                 unsigned char const *buf,
-                 unsigned len)
-{
-    guint32 t;
-
-    /* Update bitcount */
-
-    t = ctx->bits[0];
-    if ((ctx->bits[0] = t + ((guint32) len << 3)) < t)
-       ctx->bits[1]++;         /* Carry from low to high */
-    ctx->bits[1] += len >> 29;
-
-    t = (t >> 3) & 0x3f;       /* Bytes already in shsInfo->data */
-
-    /* Handle any leading odd-sized chunks */
-
-    if (t) {
-       unsigned char *p = (unsigned char *) ctx->in + t;
-
-       t = 64 - t;
-       if (len < t) {
-           memcpy (p, buf, len);
-           return;
-       }
-       memcpy (p, buf, t);
-       byteReverse (ctx->in, 16);
-       thumb_md5_transform (ctx->buf, (guint32 *) ctx->in);
-       buf += t;
-       len -= t;
-    }
-
-    /* Process data in 64-byte chunks */
-
-    while (len >= 64) {
-       memcpy (ctx->in, buf, 64);
-       byteReverse (ctx->in, 16);
-       thumb_md5_transform (ctx->buf, (guint32 *) ctx->in);
-       buf += 64;
-       len -= 64;
-    }
-
-    /* Handle any remaining bytes of data. */
-
-    memcpy(ctx->in, buf, len);
-}
-
-/*
- * Final wrapup - pad to 64-byte boundary with the bit pattern 
- * 1 0* (64-bit count of bits processed, MSB-first)
- */
-static void 
-thumb_md5_final (unsigned char digest[16], struct ThumbMD5Context *ctx)
-{
-    unsigned count;
-    unsigned char *p;
-
-    /* Compute number of bytes mod 64 */
-    count = (ctx->bits[0] >> 3) & 0x3F;
-
-    /* Set the first char of padding to 0x80.  This is safe since there is
-       always at least one byte free */
-    p = ctx->in + count;
-    *p++ = 0x80;
-
-    /* Bytes of padding needed to make 64 bytes */
-    count = 64 - 1 - count;
-
-    /* Pad out to 56 mod 64 */
-    if (count < 8) {
-       /* Two lots of padding:  Pad the first block to 64 bytes */
-       memset (p, 0, count);
-       byteReverse (ctx->in, 16);
-       thumb_md5_transform (ctx->buf, (guint32 *) ctx->in);
-
-       /* Now fill the next block with 56 bytes */
-       memset(ctx->in, 0, 56);
-    } else {
-       /* Pad block to 56 bytes */
-       memset(p, 0, count - 8);
-    }
-    byteReverse(ctx->in, 14);
-
-    /* Append length in bits and transform */
-    ((guint32 *) ctx->in)[14] = ctx->bits[0];
-    ((guint32 *) ctx->in)[15] = ctx->bits[1];
-
-    thumb_md5_transform (ctx->buf, (guint32 *) ctx->in);
-    byteReverse ((unsigned char *) ctx->buf, 4);
-    memcpy (digest, ctx->buf, 16);
-    memset (ctx, 0, sizeof(ctx));      /* In case it's sensitive */
-}
-
-
-/* The four core functions - F1 is optimized somewhat */
-
-#define F1(x, y, z) (z ^ (x & (y ^ z)))
-#define F2(x, y, z) F1 (z, x, y)
-#define F3(x, y, z) (x ^ y ^ z)
-#define F4(x, y, z) (y ^ (x | ~z))
-
-/* This is the central step in the MD5 algorithm. */
-#define thumb_md5_step(f, w, x, y, z, data, s) \
-       ( w += f(x, y, z) + data,  w = w<<s | w>>(32-s),  w += x )
-
-/*
- * The core of the MD5 algorithm, this alters an existing MD5 hash to
- * reflect the addition of 16 longwords of new data.  ThumbMD5Update blocks
- * the data and converts bytes into longwords for this routine.
- */
-static void 
-thumb_md5_transform (guint32 buf[4], guint32 const in[16])
-{
-    register guint32 a, b, c, d;
-
-    a = buf[0];
-    b = buf[1];
-    c = buf[2];
-    d = buf[3];
-
-    thumb_md5_step(F1, a, b, c, d, in[0] + 0xd76aa478, 7);
-    thumb_md5_step(F1, d, a, b, c, in[1] + 0xe8c7b756, 12);
-    thumb_md5_step(F1, c, d, a, b, in[2] + 0x242070db, 17);
-    thumb_md5_step(F1, b, c, d, a, in[3] + 0xc1bdceee, 22);
-    thumb_md5_step(F1, a, b, c, d, in[4] + 0xf57c0faf, 7);
-    thumb_md5_step(F1, d, a, b, c, in[5] + 0x4787c62a, 12);
-    thumb_md5_step(F1, c, d, a, b, in[6] + 0xa8304613, 17);
-    thumb_md5_step(F1, b, c, d, a, in[7] + 0xfd469501, 22);
-    thumb_md5_step(F1, a, b, c, d, in[8] + 0x698098d8, 7);
-    thumb_md5_step(F1, d, a, b, c, in[9] + 0x8b44f7af, 12);
-    thumb_md5_step(F1, c, d, a, b, in[10] + 0xffff5bb1, 17);
-    thumb_md5_step(F1, b, c, d, a, in[11] + 0x895cd7be, 22);
-    thumb_md5_step(F1, a, b, c, d, in[12] + 0x6b901122, 7);
-    thumb_md5_step(F1, d, a, b, c, in[13] + 0xfd987193, 12);
-    thumb_md5_step(F1, c, d, a, b, in[14] + 0xa679438e, 17);
-    thumb_md5_step(F1, b, c, d, a, in[15] + 0x49b40821, 22);
-               
-    thumb_md5_step(F2, a, b, c, d, in[1] + 0xf61e2562, 5);
-    thumb_md5_step(F2, d, a, b, c, in[6] + 0xc040b340, 9);
-    thumb_md5_step(F2, c, d, a, b, in[11] + 0x265e5a51, 14);
-    thumb_md5_step(F2, b, c, d, a, in[0] + 0xe9b6c7aa, 20);
-    thumb_md5_step(F2, a, b, c, d, in[5] + 0xd62f105d, 5);
-    thumb_md5_step(F2, d, a, b, c, in[10] + 0x02441453, 9);
-    thumb_md5_step(F2, c, d, a, b, in[15] + 0xd8a1e681, 14);
-    thumb_md5_step(F2, b, c, d, a, in[4] + 0xe7d3fbc8, 20);
-    thumb_md5_step(F2, a, b, c, d, in[9] + 0x21e1cde6, 5);
-    thumb_md5_step(F2, d, a, b, c, in[14] + 0xc33707d6, 9);
-    thumb_md5_step(F2, c, d, a, b, in[3] + 0xf4d50d87, 14);
-    thumb_md5_step(F2, b, c, d, a, in[8] + 0x455a14ed, 20);
-    thumb_md5_step(F2, a, b, c, d, in[13] + 0xa9e3e905, 5);
-    thumb_md5_step(F2, d, a, b, c, in[2] + 0xfcefa3f8, 9);
-    thumb_md5_step(F2, c, d, a, b, in[7] + 0x676f02d9, 14);
-    thumb_md5_step(F2, b, c, d, a, in[12] + 0x8d2a4c8a, 20);
-               
-    thumb_md5_step(F3, a, b, c, d, in[5] + 0xfffa3942, 4);
-    thumb_md5_step(F3, d, a, b, c, in[8] + 0x8771f681, 11);
-    thumb_md5_step(F3, c, d, a, b, in[11] + 0x6d9d6122, 16);
-    thumb_md5_step(F3, b, c, d, a, in[14] + 0xfde5380c, 23);
-    thumb_md5_step(F3, a, b, c, d, in[1] + 0xa4beea44, 4);
-    thumb_md5_step(F3, d, a, b, c, in[4] + 0x4bdecfa9, 11);
-    thumb_md5_step(F3, c, d, a, b, in[7] + 0xf6bb4b60, 16);
-    thumb_md5_step(F3, b, c, d, a, in[10] + 0xbebfbc70, 23);
-    thumb_md5_step(F3, a, b, c, d, in[13] + 0x289b7ec6, 4);
-    thumb_md5_step(F3, d, a, b, c, in[0] + 0xeaa127fa, 11);
-    thumb_md5_step(F3, c, d, a, b, in[3] + 0xd4ef3085, 16);
-    thumb_md5_step(F3, b, c, d, a, in[6] + 0x04881d05, 23);
-    thumb_md5_step(F3, a, b, c, d, in[9] + 0xd9d4d039, 4);
-    thumb_md5_step(F3, d, a, b, c, in[12] + 0xe6db99e5, 11);
-    thumb_md5_step(F3, c, d, a, b, in[15] + 0x1fa27cf8, 16);
-    thumb_md5_step(F3, b, c, d, a, in[2] + 0xc4ac5665, 23);
-               
-    thumb_md5_step(F4, a, b, c, d, in[0] + 0xf4292244, 6);
-    thumb_md5_step(F4, d, a, b, c, in[7] + 0x432aff97, 10);
-    thumb_md5_step(F4, c, d, a, b, in[14] + 0xab9423a7, 15);
-    thumb_md5_step(F4, b, c, d, a, in[5] + 0xfc93a039, 21);
-    thumb_md5_step(F4, a, b, c, d, in[12] + 0x655b59c3, 6);
-    thumb_md5_step(F4, d, a, b, c, in[3] + 0x8f0ccc92, 10);
-    thumb_md5_step(F4, c, d, a, b, in[10] + 0xffeff47d, 15);
-    thumb_md5_step(F4, b, c, d, a, in[1] + 0x85845dd1, 21);
-    thumb_md5_step(F4, a, b, c, d, in[8] + 0x6fa87e4f, 6);
-    thumb_md5_step(F4, d, a, b, c, in[15] + 0xfe2ce6e0, 10);
-    thumb_md5_step(F4, c, d, a, b, in[6] + 0xa3014314, 15);
-    thumb_md5_step(F4, b, c, d, a, in[13] + 0x4e0811a1, 21);
-    thumb_md5_step(F4, a, b, c, d, in[4] + 0xf7537e82, 6);
-    thumb_md5_step(F4, d, a, b, c, in[11] + 0xbd3af235, 10);
-    thumb_md5_step(F4, c, d, a, b, in[2] + 0x2ad7d2bb, 15);
-    thumb_md5_step(F4, b, c, d, a, in[9] + 0xeb86d391, 21);
-
-    buf[0] += a;
-    buf[1] += b;
-    buf[2] += c;
-    buf[3] += d;
-}