commit-hurd
[Top][All Lists]
Advanced

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

[hurd] 01/01: New upstream snapshot


From: Samuel Thibault
Subject: [hurd] 01/01: New upstream snapshot
Date: Sat, 04 Mar 2017 21:11:00 +0000

This is an automated email from the git hooks/post-receive script.

sthibault pushed a commit to branch upstream-merged
in repository hurd.

commit f14ad810d46c9ac05e8189d8997566e4ae0cd027
Author: Samuel Thibault <address@hidden>
Date:   Sat Mar 4 19:29:08 2017 +0000

    New upstream snapshot
---
 boot/Makefile                        |   3 +-
 boot/boot.c                          |  24 +-
 boot/private.h                       |  25 +
 boot/userland-boot.c                 |  15 +-
 configure.ac                         |   6 +-
 ext2fs/Makefile                      |   3 +-
 ext2fs/ext2_fs.h                     |   3 +-
 ext2fs/ext2fs.c                      |  14 +
 ext2fs/ext2fs.h                      |  23 +
 ext2fs/ialloc.c                      |   2 +
 ext2fs/inode.c                       | 222 ++++++---
 ext2fs/xattr.c                       | 876 +++++++++++++++++++++++++++++++++++
 ext2fs/xattr.h                       |  85 ++++
 libports/interrupt-rpcs.c            |   8 +-
 libshouldbeinlibc/assert-backtrace.h |   2 +-
 15 files changed, 1235 insertions(+), 76 deletions(-)

diff --git a/boot/Makefile b/boot/Makefile
index ac40044..e2eeb20 100644
--- a/boot/Makefile
+++ b/boot/Makefile
@@ -18,8 +18,7 @@
 dir := boot
 makemode := utility
 
-SRCS = mach-crt0.c boot.c ux.c sigvec.S syscall.S \
-       boot_script.c userland-boot.c
+SRCS = boot.c boot_script.c userland-boot.c
 COMMON-OBJS = notifyServer.o deviceServer.o \
        ioServer.o io_replyUser.o device_replyUser.o \
        termServer.o boot_script.o userland-boot.o
diff --git a/boot/boot.c b/boot/boot.c
index 2fe1688..9c2a021 100644
--- a/boot/boot.c
+++ b/boot/boot.c
@@ -68,6 +68,8 @@
 #include <hurd.h>
 #include <assert.h>
 
+#include "private.h"
+
 /* We support two modes of operation.  Traditionally, Subhurds were
    privileged, i.e. they had the privileged kernel ports.  This has a
    few drawbacks.  Privileged subhurds can manipulate all tasks on the
@@ -113,6 +115,8 @@ host_exit (int status)
   exit (status);
 }
 
+int verbose;
+
 mach_port_t privileged_host_port, master_device_port;
 mach_port_t pseudo_privileged_host_port;
 mach_port_t pseudo_master_device_port;
@@ -230,6 +234,8 @@ static struct argp_option options[] =
     "Boot in single user mode" },
   { "kernel-command-line", 'c', "COMMAND LINE", 0,
     "Simulated multiboot command line to supply" },
+  { "verbose",     'v', 0, 0,
+    "Be verbose" },
   { "pause" ,      'd', 0, 0,
     "Pause for user confirmation at various times during booting" },
   { "isig",      'I', 0, 0,
@@ -305,6 +311,10 @@ parse_opt (int key, char *arg, struct argp_state *state)
 
     case 'I':  isig = 1; break;
 
+    case 'v':
+      verbose += 1;
+      break;
+
     case 's': case 'd':
       len = strlen (bootstrap_args);
       if (len >= sizeof bootstrap_args - 1)
@@ -883,6 +893,9 @@ ds_device_open (mach_port_t master_port,
   if (master_port != pseudo_master_device_port)
     return D_INVALID_OPERATION;
 
+  if (verbose > 1)
+    fprintf (stderr, "Device '%s' being opened.\r\n", name);
+
   if (!strcmp (name, "console"))
     {
 #if 0
@@ -925,6 +938,9 @@ ds_device_open (mach_port_t master_port,
       return err;
     }
 
+  if (! privileged)
+    return D_NO_SUCH_DEVICE;
+
   *devicetype = MACH_MSG_TYPE_MOVE_SEND;
   return device_open (master_device_port, mode, name, device);
 }
@@ -1886,7 +1902,7 @@ kern_return_t
 S_host_reboot (mach_port_t host_priv,
                int flags)
 {
-  fprintf (stderr, "Would %s the system.  Bye.\n",
+  fprintf (stderr, "Would %s the system.  Bye.\r\n",
            flags & RB_HALT? "halt": "reboot");
   host_exit (0);
 }
@@ -1940,6 +1956,9 @@ static struct hurd_ihash task_ihash =
 static void
 task_died (mach_port_t name)
 {
+  if (verbose > 1)
+    fprintf (stderr, "Task '%u' died.\r\n", name);
+
   hurd_ihash_remove (&task_ihash, (hurd_ihash_key_t) name);
 }
 
@@ -1955,6 +1974,9 @@ S_mach_notify_new_task (mach_port_t notify,
   if (notify != task_notification_port)
     return EOPNOTSUPP;
 
+  if (verbose > 1)
+    fprintf (stderr, "Task '%u' created by task '%u'.\r\n", task, parent);
+
   err = mach_port_request_notification (mach_task_self (), task,
                                         MACH_NOTIFY_DEAD_NAME, 0,
                                         dead_task_notification_port,
diff --git a/boot/private.h b/boot/private.h
new file mode 100644
index 0000000..4636252
--- /dev/null
+++ b/boot/private.h
@@ -0,0 +1,25 @@
+/* Boot boots Subhurds.
+
+   Copyright (C) 2017 Free Software Foundation, Inc.
+
+   This file is part of the GNU Hurd.
+
+   The GNU Hurd is free software; you can redistribute it and/or
+   modify it under the terms of the GNU General Public License as
+   published by the Free Software Foundation; either version 2, or (at
+   your option) any later version.
+
+   The GNU Hurd is distributed in the hope that it will be useful, but
+   WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.         See the GNU
+   General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with the GNU Hurd.  If not, see <http://www.gnu.org/licenses/>.  */
+
+#ifndef BOOT_PRIVATE_H
+#define BOOT_PRIVATE_H
+
+int verbose;
+
+#endif /* BOOT_PRIVATE_H */
diff --git a/boot/userland-boot.c b/boot/userland-boot.c
index 583078f..2f9bd8c 100644
--- a/boot/userland-boot.c
+++ b/boot/userland-boot.c
@@ -31,6 +31,7 @@
 #include <error.h>
 
 #include "boot_script.h"
+#include "private.h"
 
 void *
 boot_script_malloc (unsigned int size)
@@ -48,7 +49,12 @@ boot_script_free (void *ptr, unsigned int size)
 int
 boot_script_task_create (struct cmd *cmd)
 {
-  error_t err = task_create (mach_task_self (), 0, &cmd->task);
+  error_t err;
+
+  if (verbose)
+    fprintf (stderr, "Creating task '%s'.\r\n", cmd->path);
+
+  err = task_create (mach_task_self (), 0, &cmd->task);
   if (err)
     {
       error (0, err, "%s: task_create", cmd->path);
@@ -66,7 +72,12 @@ boot_script_task_create (struct cmd *cmd)
 int
 boot_script_task_resume (struct cmd *cmd)
 {
-  error_t err = task_resume (cmd->task);
+  error_t err;
+
+  if (verbose)
+    fprintf (stderr, "Resuming task '%s'.\r\n", cmd->path);
+
+  err = task_resume (cmd->task);
   if (err)
     {
       error (0, err, "%s: task_resume", cmd->path);
diff --git a/configure.ac b/configure.ac
index 5cbbea8..30a1367 100644
--- a/configure.ac
+++ b/configure.ac
@@ -105,9 +105,9 @@ AC_CHECK_TOOL(MIG, mig)
 if test x${MIG} = x; then
   AC_MSG_ERROR([
 *** You need GNU MiG to compile the GNU Hurd, please see
-*** http://www.gnu.org/software/hurd/mig.html for further details, or
-*** download it directly from the main GNU server (ftp.gnu.org) or any
-*** GNU mirror.])
+*** http://www.gnu.org/software/hurd/microkernel/mach/mig/gnu_mig.html
+*** for further details, or download it directly from the main GNU server
+*** (ftp.gnu.org) or any GNU mirror.])
 fi
 
 dnl Let these propagate from the environment.
diff --git a/ext2fs/Makefile b/ext2fs/Makefile
index 88f8f46..0c2f4a2 100644
--- a/ext2fs/Makefile
+++ b/ext2fs/Makefile
@@ -21,7 +21,8 @@ makemode := server
 
 target = ext2fs
 SRCS = balloc.c dir.c ext2fs.c getblk.c hyper.c ialloc.c \
-       inode.c pager.c pokel.c truncate.c storeinfo.c msg.c xinl.c
+       inode.c pager.c pokel.c truncate.c storeinfo.c msg.c xinl.c \
+       xattr.c
 OBJS = $(SRCS:.c=.o)
 HURDLIBS = diskfs pager iohelp fshelp store ports ihash shouldbeinlibc
 LDLIBS = -lpthread $(and $(HAVE_LIBBZ2),-lbz2) $(and $(HAVE_LIBZ),-lz)
diff --git a/ext2fs/ext2_fs.h b/ext2fs/ext2_fs.h
index b1caeef..019ba15 100644
--- a/ext2fs/ext2_fs.h
+++ b/ext2fs/ext2_fs.h
@@ -462,6 +462,7 @@ struct ext2_super_block {
        ( EXT2_SB(sb)->s_feature_incompat & (mask) )
 
 #define EXT2_FEATURE_COMPAT_DIR_PREALLOC       0x0001
+#define EXT2_FEATURE_COMPAT_EXT_ATTR           0x0008
 
 #define EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER    0x0001
 #define EXT2_FEATURE_RO_COMPAT_LARGE_FILE      0x0002
@@ -470,7 +471,7 @@ struct ext2_super_block {
 #define EXT2_FEATURE_INCOMPAT_COMPRESSION      0x0001
 #define EXT2_FEATURE_INCOMPAT_FILETYPE         0x0002
 
-#define EXT2_FEATURE_COMPAT_SUPP       0
+#define EXT2_FEATURE_COMPAT_SUPP       EXT2_FEATURE_COMPAT_EXT_ATTR
 #define EXT2_FEATURE_INCOMPAT_SUPP     EXT2_FEATURE_INCOMPAT_FILETYPE
 #define EXT2_FEATURE_RO_COMPAT_SUPP    (EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER| \
                                         EXT2_FEATURE_RO_COMPAT_LARGE_FILE| \
diff --git a/ext2fs/ext2fs.c b/ext2fs/ext2fs.c
index 4f38c92..b4c865c 100644
--- a/ext2fs/ext2fs.c
+++ b/ext2fs/ext2fs.c
@@ -63,6 +63,10 @@ pthread_spinlock_t modified_global_blocks_lock = 
PTHREAD_SPINLOCK_INITIALIZER;
 int ext2_debug_flag;
 #endif
 
+/* Use extended attribute-based translator records.  */
+int use_xattr_translator_records;
+#define X_XATTR_TRANSLATOR_RECORDS     -1
+
 /* Ext2fs-specific options.  */
 static const struct argp_option
 options[] =
@@ -72,6 +76,8 @@ options[] =
    " (not compiled in)"
 #endif
   },
+  {"x-xattr-translator-records", X_XATTR_TRANSLATOR_RECORDS, 0, 0,
+   "Store translator records in extended attributes (experimental)"},
 #ifdef ALTERNATE_SBLOCK
   /* XXX This is not implemented.  */
   {"sblock", 'S', "BLOCKNO", 0,
@@ -89,6 +95,7 @@ parse_opt (int key, char *arg, struct argp_state *state)
   struct
   {
     int debug_flag;
+    int use_xattr_translator_records;
 #ifdef ALTERNATE_SBLOCK
     unsigned int sb_block;
 #endif
@@ -99,6 +106,9 @@ parse_opt (int key, char *arg, struct argp_state *state)
     case 'D':
       values->debug_flag = 1;
       break;
+    case X_XATTR_TRANSLATOR_RECORDS:
+      values->use_xattr_translator_records = 1;
+      break;
 #ifdef ALTERNATE_SBLOCK
     case 'S':
       values->sb_block = strtoul (arg, &arg, 0);
@@ -134,6 +144,7 @@ parse_opt (int key, char *arg, struct argp_state *state)
 #endif
        }
 
+      use_xattr_translator_records = values->use_xattr_translator_records;
       break;
 
     default:
@@ -151,6 +162,9 @@ diskfs_append_args (char **argz, size_t *argz_len)
   /* Get the standard things.  */
   err = diskfs_append_std_options (argz, argz_len);
 
+  if (!err && use_xattr_translator_records)
+    err = argz_add (argz, argz_len, "--x-xattr-translator-records");
+
 #ifdef EXT2FS_DEBUG
   if (!err && ext2_debug_flag)
     err = argz_add (argz, argz_len, "--debug");
diff --git a/ext2fs/ext2fs.h b/ext2fs/ext2fs.h
index a3d22b2..2104dba 100644
--- a/ext2fs/ext2fs.h
+++ b/ext2fs/ext2fs.h
@@ -17,6 +17,9 @@
    along with this program; if not, write to the Free Software
    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
 
+#ifndef _EXT2FS_H
+#define _EXT2FS_H
+
 #include <mach.h>
 #include <hurd.h>
 #include <hurd/ports.h>
@@ -575,3 +578,23 @@ extern void _ext2_panic (const char *, const char *, ...)
 
 extern void ext2_warning (const char *, ...)
      __attribute__ ((format (printf, 1, 2)));
+
+/* ---------------------------------------------------------------- */
+/* xattr.c */
+
+error_t ext2_list_xattr (struct node *np, char *buffer, size_t *len);
+error_t ext2_get_xattr (struct node *np, const char *name, char *value, size_t 
*len);
+error_t ext2_set_xattr (struct node *np, const char *name, const char *value, 
size_t len, int flags);
+error_t ext2_free_xattr_block (struct node *np);
+
+/* Use extended attribute-based translator records.
+ *
+ * This flag allows users to opt-in to the use of extended attributes
+ * for storing translator records.  We will make this the default once
+ * we feel confident that the implementation is fine.
+ *
+ * XXX: Remove this in Hurd 1.0 (or 0.10, or whatever follows 0.9).
+ */
+int use_xattr_translator_records;
+
+#endif
diff --git a/ext2fs/ialloc.c b/ext2fs/ialloc.c
index 2809371..71bfb8c 100644
--- a/ext2fs/ialloc.c
+++ b/ext2fs/ialloc.c
@@ -62,6 +62,8 @@ diskfs_free_node (struct node *np, mode_t old_mode)
 
   ext2_debug ("freeing inode %u", inum);
 
+  ext2_free_xattr_block (np);
+
   pthread_spin_lock (&global_lock);
 
   if (inum < EXT2_FIRST_INO (sblock) || inum > sblock->s_inodes_count)
diff --git a/ext2fs/inode.c b/ext2fs/inode.c
index ccc8d69..17dded6 100644
--- a/ext2fs/inode.c
+++ b/ext2fs/inode.c
@@ -26,6 +26,7 @@
 #include <sys/stat.h>
 #include <sys/statfs.h>
 #include <sys/statvfs.h>
+#include <sys/xattr.h>
 
 /* these flags aren't actually defined by a header file yet, so temporarily
    disable them if necessary.  */
@@ -166,8 +167,16 @@ diskfs_user_read_node (struct node *np, struct 
lookup_context *ctx)
     {
       st->st_mode = di->i_mode | (di->i_mode_high << 16);
       st->st_mode &= ~S_ITRANS;
+
       if (di->i_translator)
        st->st_mode |= S_IPTRANS;
+      else
+       {
+         size_t datalen = 0;
+         err = ext2_get_xattr (np, "gnu.translator", NULL, &datalen);
+         if (! err && datalen > 0)
+           st->st_mode |= S_IPTRANS;
+       }
 
       st->st_uid = di->i_uid | (di->i_uid_high << 16);
       st->st_gid = di->i_gid | (di->i_gid_high << 16);
@@ -540,81 +549,144 @@ error_t
 diskfs_set_translator (struct node *np, const char *name, unsigned namelen,
                       struct protid *cred)
 {
-  daddr_t blkno;
   error_t err;
-  char buf[block_size];
-  struct ext2_inode *di;
 
   assert (!diskfs_readonly);
 
   if (sblock->s_creator_os != EXT2_OS_HURD)
     return EOPNOTSUPP;
 
-  if (namelen + 2 > block_size)
-    return ENAMETOOLONG;
-
   err = diskfs_catch_exception ();
   if (err)
     return err;
 
-  di = dino_ref (np->cache_id);
-  blkno = di->i_translator;
-
-  if (namelen && !blkno)
+  /* If xattr is supported for this filesystem, use xattr to store translator
+     record, otherwise, use legacy translator record */
+  if (EXT2_HAS_COMPAT_FEATURE (sblock, EXT2_FEATURE_COMPAT_EXT_ATTR)
+      && use_xattr_translator_records)
     {
-      /* Allocate block for translator */
-      blkno =
-       ext2_new_block ((diskfs_node_disknode (np)->info.i_block_group
-                        * EXT2_BLOCKS_PER_GROUP (sblock))
-                       + sblock->s_first_data_block,
-                       0, 0, 0);
-      if (blkno == 0)
+      daddr_t blkno;
+      struct ext2_inode *di;
+
+      di = dino_ref (np->cache_id);
+      blkno = di->i_translator;
+
+      /* If a legacy translator record found, clear it */
+      if (blkno)
+       {
+         ext2_debug ("Old translator record found, clear it");
+
+         /* Clear block for translator going away. */
+         di->i_translator = 0;
+         diskfs_node_disknode (np)->info_i_translator = 0;
+         record_global_poke (di);
+         ext2_free_blocks (blkno, 1);
+
+         np->dn_stat.st_blocks -= 1 << log2_stat_blocks_per_fs_block;
+         np->dn_stat.st_mode &= ~S_IPTRANS;
+         np->dn_set_ctime = 1;
+       }
+      else
+       dino_deref (di);
+
+      /* Use xattr to store translator record, with key "gnu.translator" */
+      if (namelen)
        {
-         dino_deref (di);
-         diskfs_end_catch_exception ();
-         return ENOSPC;
+         err = ext2_set_xattr (np, "gnu.translator", name, namelen, 0);
+
+         if (!err)
+           {
+             np->dn_stat.st_mode |= S_IPTRANS;
+             np->dn_set_ctime = 1;
+           }
        }
+      else
+       {
+         /* Removing the translator.  */
+         err = ext2_set_xattr (np, "gnu.translator", NULL, 0, 0);
 
-      di->i_translator = blkno;
-      diskfs_node_disknode (np)->info_i_translator = blkno;
-      record_global_poke (di);
+         if (err == ENODATA)
+           /* Happens if the key did not exist in the first place.  */
+           err = 0;
 
-      np->dn_stat.st_blocks += 1 << log2_stat_blocks_per_fs_block;
-      np->dn_set_ctime = 1;
-    }
-  else if (!namelen && blkno)
-    {
-      /* Clear block for translator going away. */
-      di->i_translator = 0;
-      diskfs_node_disknode (np)->info_i_translator = 0;
-      record_global_poke (di);
-      ext2_free_blocks (blkno, 1);
-
-      np->dn_stat.st_blocks -= 1 << log2_stat_blocks_per_fs_block;
-      np->dn_stat.st_mode &= ~S_IPTRANS;
-      np->dn_set_ctime = 1;
+         if (!err)
+           {
+             /* Do not use hurd extensions on non-hurd created filesystem */
+             np->dn_stat.st_mode &= ~S_IPTRANS;
+             np->dn_set_ctime = 1;
+           }
+       }
     }
   else
-    dino_deref (di);
-
-  if (namelen)
     {
-      void *blkptr;
+      /* Use legacy translator record when xattr is not supported */
+      daddr_t blkno;
+      struct ext2_inode *di;
+      char buf[block_size];
 
-      buf[0] = namelen & 0xFF;
-      buf[1] = (namelen >> 8) & 0xFF;
-      memcpy (buf + 2, name, namelen);
+      if (namelen + 2 > block_size)
+       return ENAMETOOLONG;
 
-      blkptr = disk_cache_block_ref (blkno);
-      memcpy (blkptr, buf, block_size);
-      record_global_poke (blkptr);
+      di = dino_ref (np->cache_id);
+      blkno = di->i_translator;
 
-      np->dn_stat.st_mode |= S_IPTRANS;
-      np->dn_set_ctime = 1;
+      if (namelen && !blkno)
+       {
+         /* Allocate block for translator */
+         blkno =
+           ext2_new_block ((diskfs_node_disknode (np)->info.i_block_group
+                           * EXT2_BLOCKS_PER_GROUP (sblock))
+                           + sblock->s_first_data_block,
+                           0, 0, 0);
+         if (blkno == 0)
+           {
+             dino_deref (di);
+             diskfs_end_catch_exception ();
+             return ENOSPC;
+           }
+
+         di->i_translator = blkno;
+         diskfs_node_disknode (np)->info_i_translator = blkno;
+         record_global_poke (di);
+
+         np->dn_stat.st_blocks += 1 << log2_stat_blocks_per_fs_block;
+         np->dn_set_ctime = 1;
+       }
+      else if (!namelen && blkno)
+       {
+         /* Clear block for translator going away. */
+         di->i_translator = 0;
+         diskfs_node_disknode (np)->info_i_translator = 0;
+         record_global_poke (di);
+         ext2_free_blocks (blkno, 1);
+
+         np->dn_stat.st_blocks -= 1 << log2_stat_blocks_per_fs_block;
+         np->dn_stat.st_mode &= ~S_IPTRANS;
+         np->dn_set_ctime = 1;
+       }
+      else
+       dino_deref (di);
+
+      if (namelen)
+       {
+         void *blkptr;
+
+         buf[0] = namelen & 0xFF;
+         buf[1] = (namelen >> 8) & 0xFF;
+         memcpy (buf + 2, name, namelen);
+
+         blkptr = disk_cache_block_ref (blkno);
+         memcpy (blkptr, buf, block_size);
+         record_global_poke (blkptr);
+
+         np->dn_stat.st_mode |= S_IPTRANS;
+         np->dn_set_ctime = 1;
+       }
     }
 
   diskfs_end_catch_exception ();
   return err;
+
 }
 
 /* Implement the diskfs_get_translator callback from the diskfs library.
@@ -624,11 +696,12 @@ diskfs_get_translator (struct node *np, char **namep, 
unsigned *namelen)
 {
   error_t err = 0;
   daddr_t blkno;
-  unsigned datalen;
+  size_t datalen;
   void *transloc;
   struct ext2_inode *di;
 
-  assert (sblock->s_creator_os == EXT2_OS_HURD);
+  if (sblock->s_creator_os != EXT2_OS_HURD)
+    return EOPNOTSUPP;
 
   err = diskfs_catch_exception ();
   if (err)
@@ -637,23 +710,46 @@ diskfs_get_translator (struct node *np, char **namep, 
unsigned *namelen)
   di = dino_ref (np->cache_id);
   blkno = di->i_translator;
   dino_deref (di);
-  assert (blkno);
-  transloc = disk_cache_block_ref (blkno);
 
-  datalen =
-    ((unsigned char *)transloc)[0] + (((unsigned char *)transloc)[1] << 8);
-  if (datalen > block_size - 2)
-    err = EFTYPE;              /* ? */
-  else
+  /* If an old translator record found, read it firstly */
+  if (blkno)
     {
-      *namep = malloc (datalen);
-      if (!*namep)
-       err = ENOMEM;
+      /* If xattr is no supported by this filesystem, don't report a warning */
+      if (EXT2_HAS_COMPAT_FEATURE (sblock, EXT2_FEATURE_COMPAT_EXT_ATTR)
+         && use_xattr_translator_records)
+       ext2_debug ("This is an old translator record, please update it");
+
+      transloc = disk_cache_block_ref (blkno);
+      datalen =
+       ((unsigned char *)transloc)[0] + (((unsigned char *)transloc)[1] << 8);
+      if (datalen > block_size - 2)
+       err = EFTYPE;  /* ? */
       else
-       memcpy (*namep, transloc + 2, datalen);
+       {
+         *namep = malloc (datalen);
+         if (!*namep)
+           err = ENOMEM;
+         else
+           memcpy (*namep, transloc + 2, datalen);
+       }
+
+      disk_cache_block_deref (transloc);
+      diskfs_end_catch_exception ();
+
+      *namelen = datalen;
+      return err;
     }
 
-  disk_cache_block_deref (transloc);
+  err = ext2_get_xattr (np, "gnu.translator", NULL, &datalen);
+  if (err)
+    return err;
+
+  *namep = malloc (datalen);
+  if (!*namep)
+    err = ENOMEM;
+  else
+    err = ext2_get_xattr (np, "gnu.translator", *namep, &datalen);
+
   diskfs_end_catch_exception ();
 
   *namelen = datalen;
diff --git a/ext2fs/xattr.c b/ext2fs/xattr.c
new file mode 100644
index 0000000..5ce84ce
--- /dev/null
+++ b/ext2fs/xattr.c
@@ -0,0 +1,876 @@
+ /* Ext2 support for extended attributes
+
+   Copyright (C) 2006, 2016 Free Software Foundation, Inc.
+
+   Written by Thadeu Lima de Souza Cascardo <address@hidden>
+   and Shengyu Zhang <address@hidden>
+
+   This program is free software; you can redistribute it and/or
+   modify it under the terms of the GNU General Public License as
+   published by the Free Software Foundation; either version 2, or (at
+   your option) any later version.
+
+   This program is distributed in the hope that it will be useful, but
+   WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "ext2fs.h"
+#include "xattr.h"
+#include <stdlib.h>
+#include <string.h>
+#include <sys/xattr.h>
+
+struct _xattr_prefix
+{
+  int index;
+  char *prefix;
+  ssize_t size;
+};
+
+/* Prefixes are represented as numbers when stored in ext2 filesystems. */
+struct _xattr_prefix
+xattr_prefixes[] =
+{
+  {
+  1, "user.", sizeof "user." - 1},
+  {
+  7, "gnu.", sizeof "gnu." - 1},
+  {
+  0, NULL, 0}
+};
+
+/*
+ * Given an attribute name in full_name, the ext2 number (index) and
+ * suffix name (name) are given.  Returns the index in the array
+ * indicating whether a corresponding prefix was found or not.
+ */
+static int
+xattr_name_prefix (const char *full_name, int *index, const char **name)
+{
+  int i;
+
+  for (i = 0; xattr_prefixes[i].prefix != NULL; i++)
+    {
+      if (!strncmp (xattr_prefixes[i].prefix, full_name,
+                   xattr_prefixes[i].size))
+       {
+         *name = full_name + xattr_prefixes[i].size;
+         *index = xattr_prefixes[i].index;
+         break;
+       }
+    }
+  return i;
+}
+
+#define NAME_HASH_SHIFT 5
+#define VALUE_HASH_SHIFT 16
+
+/* Given a xattr block header and a entry, compute the hash of this
+ * entry.
+ */
+static void
+xattr_entry_hash (struct ext2_xattr_header *header,
+                 struct ext2_xattr_entry *entry)
+{
+
+  __u32 hash = 0;
+  char *name = entry->e_name;
+  int n;
+
+  for (n = 0; n < entry->e_name_len; n++)
+    {
+      hash = (hash << NAME_HASH_SHIFT)
+        ^ (hash >> (8 * sizeof (hash) - NAME_HASH_SHIFT))
+           ^ *name++;
+    }
+
+  if (entry->e_value_block == 0 && entry->e_value_size != 0)
+    {
+      __u32 *value = (__u32 *) ((char *) header + entry->e_value_offs);
+      for (n = (entry->e_value_size + EXT2_XATTR_ROUND) >>
+             EXT2_XATTR_PAD_BITS; n; n--)
+       {
+         hash = (hash << VALUE_HASH_SHIFT)
+             ^ (hash >> (8 * sizeof (hash) - VALUE_HASH_SHIFT))
+             ^ *value++;
+       }
+    }
+
+  entry->e_hash = hash;
+
+}
+
+#undef NAME_HASH_SHIFT
+#undef VALUE_HASH_SHIFT
+
+#define BLOCK_HASH_SHIFT 16
+
+/* Given a xattr block header and a entry, re-compute the
+ * hash of the entry after it has changed, and computer the hash
+ * of the header.
+ */
+static void
+xattr_entry_rehash (struct ext2_xattr_header *header,
+                   struct ext2_xattr_entry *entry)
+{
+
+  __u32 hash = 0;
+  struct ext2_xattr_entry *position;
+
+  xattr_entry_hash (header, entry);
+
+  position = EXT2_XATTR_ENTRY_FIRST (header);
+  while (!EXT2_XATTR_ENTRY_LAST (position))
+    {
+      if (position->e_hash == 0)
+       {
+         /* Block is not shared if an entry's hash value == 0 */
+         hash = 0;
+         break;
+       }
+
+      hash = (hash << BLOCK_HASH_SHIFT)
+         ^ (hash >> (8 * sizeof (hash) - BLOCK_HASH_SHIFT))
+         ^ position->e_hash;
+
+      position = EXT2_XATTR_ENTRY_NEXT (position);
+    }
+
+  header->h_hash = hash;
+
+}
+
+#undef BLOCK_HASH_SHIFT
+
+/*
+ * Given an entry, appends its name to a buffer.  The provided buffer
+ * length is reduced by the name size, even if the buffer is NULL (for
+ * computing the list size).  Returns EOPNOTSUPP (operation not
+ * supported) if the entry index cannot be found on the array of
+ * supported prefixes.  If a buffer is provided (not NULL) and its
+ * length is not enough for name, ERANGE is returned.
+ */
+static error_t
+xattr_entry_list (struct ext2_xattr_entry *entry, char *buffer, size_t *len)
+{
+
+  int i;
+  size_t size;
+
+  for (i = 0; xattr_prefixes[i].prefix != NULL; i++)
+    {
+      if (entry->e_name_index == xattr_prefixes[i].index)
+       break;
+    }
+
+  if (xattr_prefixes[i].prefix == NULL)
+    return EOPNOTSUPP;
+
+  size = xattr_prefixes[i].size + entry->e_name_len + 1;
+
+  if (buffer)
+    {
+      if (size <= *len)
+       {
+         memcpy (buffer, xattr_prefixes[i].prefix, xattr_prefixes[i].size);
+         buffer += xattr_prefixes[i].size;
+         memcpy (buffer, entry->e_name, entry->e_name_len);
+         buffer += entry->e_name_len;
+         *buffer++ = 0;
+       }
+      else
+       {
+         return ERANGE;
+       }
+    }
+
+  *len -= size;
+  return 0;
+
+}
+
+/*
+ * Given the xattr block, an entry and a attribute name, retrieves its
+ * value. The value length is also returned through parameter len.  In
+ * case the name prefix cannot be found in the prefix array,
+ * EOPNOTSUPP is returned, indicating the prefix is not supported.  In
+ * case there is not enough space in the buffer provided, ERANGE is
+ * returned.  If the value buffer was NULL, the length is returned
+ * through len parameter and the function is successfull (returns 0).
+ * If the entry does not match the name, ENODATA is returned, and
+ * parameter cmp is set to the comparison value (less than 0 if a
+ * entry with name full_name should be before the current entry,
+ * more than 0 otherwise.
+ */
+static error_t
+xattr_entry_get (void *block, struct ext2_xattr_entry *entry,
+                const char *full_name, char *value, size_t *len, int *cmp)
+{
+
+  int i;
+  int index;
+  int tmp_cmp;
+  const char *name;
+
+  i = xattr_name_prefix (full_name, &index, &name);
+
+  if (xattr_prefixes[i].prefix == NULL)
+    return EOPNOTSUPP;
+
+  tmp_cmp = index - entry->e_name_index;
+  if (!tmp_cmp)
+    tmp_cmp = strlen (name) - entry->e_name_len;
+  if (!tmp_cmp)
+    tmp_cmp = strncmp (name, entry->e_name, entry->e_name_len);
+
+  if (tmp_cmp)
+    {
+      if (cmp)
+       *cmp = tmp_cmp;
+      return ENODATA;
+    }
+
+  if (value)
+    {
+      if (*len < entry->e_value_size)
+       {
+         return ERANGE;
+       }
+      memcpy (value, block + entry->e_value_offs, entry->e_value_size);
+    }
+
+  *len = entry->e_value_size;
+  return 0;
+
+}
+
+/*
+ * Creates an entry in the xattr block, giving its header, the last
+ * entry, the position where this new one should be inserted, the name
+ * of the attribute, its value and the value length, and, the
+ * remaining space in the block (parameter rest).  If no space is
+ * available for the required size of the entry, ERANGE is returned.
+ */
+static error_t
+xattr_entry_create (struct ext2_xattr_header *header,
+                   struct ext2_xattr_entry *last,
+                   struct ext2_xattr_entry *position,
+                   const char *full_name, const char *value,
+                   size_t len, size_t rest)
+{
+
+  int i;
+  size_t name_len;
+  off_t start;
+  off_t end;
+  size_t entry_size;
+  size_t value_size;
+  int index;
+  const char *name;
+
+  i = xattr_name_prefix (full_name, &index, &name);
+
+  if (xattr_prefixes[i].prefix == NULL)
+    return EOPNOTSUPP;
+
+  name_len = strlen (name);
+  entry_size = EXT2_XATTR_ENTRY_SIZE (name_len);
+  value_size = EXT2_XATTR_ALIGN (len);
+
+  if (rest < 4 || entry_size + value_size > rest - 4)
+    {
+      return ERANGE;
+    }
+
+  start = EXT2_XATTR_ENTRY_OFFSET (header, position);
+  end = EXT2_XATTR_ENTRY_OFFSET (header, last);
+
+  /* Leave room for new entry */
+  memmove ((char *) position + entry_size, position, end - start);
+
+  position->e_name_len = name_len;
+  position->e_name_index = index;
+  position->e_value_offs = end + rest - value_size;
+  position->e_value_block = 0;
+  position->e_value_size = len;
+  strncpy (position->e_name, name, name_len);
+
+  memcpy ((char *) header + position->e_value_offs, value, len);
+  memset ((char *) header + position->e_value_offs + len, 0,
+         value_size - len);
+
+  return 0;
+
+}
+
+/*
+ * Removes an entry from the xattr block, giving a pointer to the
+ * block header, the last attribute entry, the position of the entry
+ * to be removed and the remaining space in the block.
+ */
+static error_t
+xattr_entry_remove (struct ext2_xattr_header *header,
+                   struct ext2_xattr_entry *last,
+                   struct ext2_xattr_entry *position, size_t rest)
+{
+
+  size_t size;
+  off_t start;
+  off_t end;
+  struct ext2_xattr_entry *entry;
+
+  /* Remove the value */
+  size = EXT2_XATTR_ALIGN (position->e_value_size);
+  start = EXT2_XATTR_ENTRY_OFFSET (header, last) + rest;
+  end = position->e_value_offs;
+
+  memmove ((char *) header + start + size, (char *) header + start,
+          end - start);
+  memset ((char *) header + start, 0, size);
+
+  /* Adjust all value offsets */
+  entry = EXT2_XATTR_ENTRY_FIRST (header);
+  while (!EXT2_XATTR_ENTRY_LAST (entry))
+    {
+      if (entry->e_value_offs < end)
+       entry->e_value_offs += size;
+      entry = EXT2_XATTR_ENTRY_NEXT (entry);
+    }
+
+  /* Remove the name */
+  size = EXT2_XATTR_ENTRY_SIZE (position->e_name_len);
+  start = EXT2_XATTR_ENTRY_OFFSET (header, position);
+  end = EXT2_XATTR_ENTRY_OFFSET (header, last);
+
+  memmove ((char *) header + start , (char *) header + start + size,
+          end - (start + size));
+  memset ((char *) header + end - size, 0, size);
+
+  return 0;
+
+}
+
+/*
+ * Replaces the value of an existing attribute entry, given the block
+ * header, the last entry, the entry whose value should be replaced,
+ * the new value, its length, and the remaining space in the block.
+ * Returns ERANGE if there is not enough space (when the new value is
+ * bigger than the old one).
+ */
+static error_t
+xattr_entry_replace (struct ext2_xattr_header *header,
+                    struct ext2_xattr_entry *last,
+                    struct ext2_xattr_entry *position,
+                    const char *value, size_t len, size_t rest)
+{
+
+  size_t old_size;
+  size_t new_size;
+
+  old_size = EXT2_XATTR_ALIGN (position->e_value_size);
+  new_size = EXT2_XATTR_ALIGN (len);
+
+  if (rest < 4 || new_size - old_size > rest - 4)
+    return ERANGE;
+
+  if (new_size != old_size)
+    {
+      off_t start;
+      off_t end;
+      struct ext2_xattr_entry *entry;
+
+      start = EXT2_XATTR_ENTRY_OFFSET (header, last) + rest;
+      end = position->e_value_offs;
+
+      /* Remove the old value */
+      memmove ((char *) header + start + old_size, (char *) header + start,
+              end - start);
+
+      /* Adjust all value offsets */
+      entry = EXT2_XATTR_ENTRY_FIRST (header);
+      while (!EXT2_XATTR_ENTRY_LAST (entry))
+       {
+         if (entry->e_value_offs < end)
+           entry->e_value_offs += old_size;
+         entry = EXT2_XATTR_ENTRY_NEXT (entry);
+       }
+
+      position->e_value_offs = start - (new_size - old_size);
+    }
+
+  position->e_value_size = len;
+
+  /* Write the new value */
+  memcpy ((char *) header + position->e_value_offs, value, len);
+  memset ((char *) header + position->e_value_offs + len, 0, new_size - len);
+
+  return 0;
+
+}
+
+
+/*
+ * Given a node, free extended attributes block associated with
+ * this node.
+ */
+error_t
+ext2_free_xattr_block (struct node *np)
+{
+  error_t err;
+  block_t blkno;
+  void *block;
+  struct ext2_inode *ei;
+  struct ext2_xattr_header *header;
+
+  if (!EXT2_HAS_COMPAT_FEATURE (sblock, EXT2_FEATURE_COMPAT_EXT_ATTR))
+    {
+      ext2_warning ("Filesystem has no support for extended attributes.");
+      return EOPNOTSUPP;
+    }
+
+  err = 0;
+  block = NULL;
+
+  ei = dino_ref (np->cache_id);
+  blkno = ei->i_file_acl;
+
+  if (blkno == 0)
+    {
+      err = 0;
+      goto cleanup;
+    }
+
+  assert (!diskfs_readonly);
+
+  block = disk_cache_block_ref (blkno);
+  header = EXT2_XATTR_HEADER (block);
+
+  if (header->h_magic != EXT2_XATTR_BLOCK_MAGIC || header->h_blocks != 1)
+    {
+      ext2_warning ("Invalid extended attribute block.");
+      err = EIO;
+      goto cleanup;
+    }
+
+  if (header->h_refcount == 1)
+    {
+       ext2_debug("free block %d", blkno);
+
+       disk_cache_block_deref (block);
+       ext2_free_blocks(blkno, 1);
+
+       np->dn_stat.st_blocks -= 1 << log2_stat_blocks_per_fs_block;
+       np->dn_stat.st_mode &= ~S_IPTRANS;
+       np->dn_set_ctime = 1;
+    }
+  else
+    {
+       ext2_debug("h_refcount: %d", header->h_refcount);
+
+       header->h_refcount--;
+       record_global_poke (block);
+    }
+
+
+  ei->i_file_acl = 0;
+  record_global_poke (ei);
+
+  return err;
+
+cleanup:
+  if (block)
+    disk_cache_block_deref (block);
+
+  dino_deref (ei);
+
+  return err;
+
+}
+
+/*
+ * Given a node, return its list of attribute names in a buffer.
+ * The size of used/required buffer will returned through parameter
+ * len, even if the buffer is NULL.  Returns EOPNOTSUPP if underlying
+ * filesystem has no extended attributes support.  Returns EIO if
+ * xattr block is invalid (has no valid h_magic number).
+ */
+error_t
+ext2_list_xattr (struct node *np, char *buffer, size_t *len)
+{
+
+  error_t err;
+  block_t blkno;
+  void *block;
+  struct ext2_inode *ei;
+  struct ext2_xattr_header *header;
+  struct ext2_xattr_entry *entry;
+
+  if (!EXT2_HAS_COMPAT_FEATURE (sblock, EXT2_FEATURE_COMPAT_EXT_ATTR))
+    {
+      ext2_warning ("Filesystem has no support for extended attributes.");
+      return EOPNOTSUPP;
+    }
+
+  if (!len)
+    return EINVAL;
+
+  size_t size = *len;
+
+  ei = dino_ref (np->cache_id);
+  blkno = ei->i_file_acl;
+  dino_deref (ei);
+
+  if (blkno == 0)
+    {
+      *len = 0;
+      return 0;
+    }
+
+  err = EIO;
+  block = disk_cache_block_ref (blkno);
+
+  header = EXT2_XATTR_HEADER (block);
+  if (header->h_magic != EXT2_XATTR_BLOCK_MAGIC || header->h_blocks != 1)
+    {
+      ext2_warning ("Invalid extended attribute block.");
+      err = EIO;
+      goto cleanup;
+    }
+
+  entry = EXT2_XATTR_ENTRY_FIRST (header);
+
+  while (!EXT2_XATTR_ENTRY_LAST (entry))
+    {
+      err = xattr_entry_list (entry, buffer, &size);
+      if (err)
+       goto cleanup;
+      if (buffer)
+        buffer += strlen (buffer) + 1;
+      entry = EXT2_XATTR_ENTRY_NEXT (entry);
+    }
+
+  *len = *len - size;
+
+cleanup:
+  disk_cache_block_deref (block);
+
+  return err;
+
+}
+
+
+/*
+ * Given a node and an attribute name, returns the value and its
+ * length in a buffer. The length is returned through parameter len
+ * even if the value is NULL.  May return EOPNOTSUPP if underlying
+ * filesystem does not support extended attributes or the given name
+ * prefix.  If there is no sufficient space in value buffer or
+ * attribute name is too long, returns ERANGE.  Returns EIO if xattr
+ * block is invalid and ENODATA if there is no such block or no entry
+ * in the block matching the name.
+ */
+error_t
+ext2_get_xattr (struct node *np, const char *name, char *value, size_t *len)
+{
+
+  size_t size;
+  int err;
+  void *block;
+  struct ext2_inode *ei;
+  struct ext2_xattr_header *header;
+  struct ext2_xattr_entry *entry;
+
+  if (!EXT2_HAS_COMPAT_FEATURE (sblock, EXT2_FEATURE_COMPAT_EXT_ATTR))
+    {
+      ext2_warning ("Filesystem has no support for extended attributes.");
+      return EOPNOTSUPP;
+    }
+
+  if (!name || !len)
+    return EINVAL;
+
+  if (strlen(name) > 255)
+    return ERANGE;
+
+  ei = dino_ref (np->cache_id);
+
+  if (ei->i_file_acl == 0)
+    {
+      dino_deref (ei);
+      return ENODATA;
+    }
+
+  block = disk_cache_block_ref (ei->i_file_acl);
+  dino_deref (ei);
+
+  header = EXT2_XATTR_HEADER (block);
+  if (header->h_magic != EXT2_XATTR_BLOCK_MAGIC || header->h_blocks != 1)
+    {
+      ext2_warning ("Invalid extended attribute block.");
+      err = EIO;
+      goto cleanup;
+    }
+
+  err = ENODATA;
+  entry = EXT2_XATTR_ENTRY_FIRST (header);
+
+  while (!EXT2_XATTR_ENTRY_LAST (entry))
+    {
+      size = *len;
+      err = xattr_entry_get (block, entry, name, value, &size, NULL);
+      if (err!= ENODATA)
+       break;
+      entry = EXT2_XATTR_ENTRY_NEXT (entry);
+    }
+
+  if (!err)
+    *len = size;
+
+cleanup:
+  disk_cache_block_deref (block);
+
+  return err;
+
+}
+
+/*
+ * Set the value of an attribute giving the node, the attribute name,
+ * value, the value length and flags. If name or value is too long,
+ * ERANGE is returned.  If flags is XATTR_CREATE, the
+ * attribute is created if no existing matching entry is found.
+ * Otherwise, EEXIST is returned.  If flags is XATTR_REPLACE, the
+ * attribute value is replaced if an entry is found and ENODATA is
+ * returned otherwise.  If no flags are used, the entry is properly
+ * created or replaced.  The entry is removed if value is NULL and no
+ * flags are used.  In this case, if any flags are used, EINVAL is
+ * returned.  If no matching entry is found, ENODATA is returned.
+ * EOPNOTSUPP is returned in case extended attributes or the name
+ * prefix are not supported.  If there is no space available in the
+ * block, ERANGE is returned.  If there is no any entry after removing
+ * the specified entry, free the xattr block.
+ */
+error_t
+ext2_set_xattr (struct node *np, const char *name, const char *value,
+               size_t len, int flags)
+{
+
+  int found;
+  size_t rest;
+  error_t err;
+  block_t blkno;
+  void *block;
+  struct ext2_inode *ei;
+  struct ext2_xattr_header *header;
+  struct ext2_xattr_entry *entry;
+  struct ext2_xattr_entry *location;
+
+  if (!EXT2_HAS_COMPAT_FEATURE (sblock, EXT2_FEATURE_COMPAT_EXT_ATTR))
+    {
+      ext2_warning ("Filesystem has no support for extended attributes.");
+      return EOPNOTSUPP;
+    }
+
+  if (!name)
+    return EINVAL;
+
+  if (strlen(name) > 255 || len > block_size)
+    return ERANGE;
+
+  ei = dino_ref (np->cache_id);
+  blkno = ei->i_file_acl;
+
+  /* Avoid allocating a block if this is a request to delete data.  */
+  if (blkno == 0 && value == NULL)
+    {
+      block = NULL;
+      err = ENODATA;
+      goto cleanup;
+    }
+
+  if (blkno == 0)
+    {
+      /* Allocate and initialize new block */
+      block_t goal;
+
+      assert (!diskfs_readonly);
+
+      goal = sblock->s_first_data_block + np->dn->info.i_block_group *
+       EXT2_BLOCKS_PER_GROUP (sblock);
+      blkno = ext2_new_block (goal, 0, 0, 0);
+
+      if (blkno == 0)
+       {
+         err = ENOSPC;
+         goto cleanup;
+       }
+
+      block = disk_cache_block_ref (blkno);
+      memset (block, 0, block_size);
+
+      header = EXT2_XATTR_HEADER (block);
+      header->h_magic = EXT2_XATTR_BLOCK_MAGIC;
+      header->h_blocks = 1;
+      header->h_refcount = 1;
+    }
+  else
+    {
+      block = disk_cache_block_ref (blkno);
+      header = EXT2_XATTR_HEADER (block);
+      if (header->h_magic != EXT2_XATTR_BLOCK_MAGIC || header->h_blocks != 1)
+       {
+         ext2_warning ("Invalid extended attribute block.");
+         err = EIO;
+         goto cleanup;
+       }
+    }
+
+  entry = EXT2_XATTR_ENTRY_FIRST (header);
+  location = NULL;
+
+  rest = block_size;
+  err = ENODATA;
+  found = FALSE;
+
+  while (!EXT2_XATTR_ENTRY_LAST (entry))
+    {
+      size_t size;
+      int cmp;
+
+      err = xattr_entry_get (NULL, entry, name, NULL, &size, &cmp);
+      if (err == 0)
+       {
+         location = entry;
+         found = TRUE;
+       }
+      else if (err == ENODATA)
+       {
+         /* The xattr entries are sorted by attribute name */
+         if (cmp < 0 && !found)
+           {
+             location = entry;
+             found = FALSE;
+           }
+       }
+      else
+       {
+         break;
+       }
+
+      rest -= EXT2_XATTR_ALIGN (entry->e_value_size);
+      entry = EXT2_XATTR_ENTRY_NEXT (entry);
+    }
+
+  if (err != 0 && err != ENODATA)
+    {
+      goto cleanup;
+    }
+
+  if (location == NULL)
+    location = entry;
+
+  rest = rest - EXT2_XATTR_ENTRY_OFFSET (header, entry);
+  ext2_debug("space rest: %d", rest);
+
+  /* 4 null bytes after xattr entry */
+  if (rest < 4)
+    {
+      err = EIO;
+      goto cleanup;
+    }
+
+  if (value && flags & XATTR_CREATE)
+    {
+      if (found)
+       {
+         err = EEXIST;
+         goto cleanup;
+       }
+      else
+       err = xattr_entry_create (header, entry, location, name, value, len,
+         rest);
+    }
+  else if (value && flags & XATTR_REPLACE)
+    {
+      if (!found)
+       {
+         err = ENODATA;
+         goto cleanup;
+       }
+      else
+       err = xattr_entry_replace (header, entry, location, value, len, rest);
+    }
+  else if (value)
+    {
+      if (found)
+       err = xattr_entry_replace (header, entry, location, value, len, rest);
+      else
+       err = xattr_entry_create (header, entry, location, name, value, len,
+               rest);
+    }
+  else
+    {
+      if (flags & XATTR_REPLACE || flags & XATTR_CREATE)
+       {
+         err = EINVAL;
+         goto cleanup;
+       }
+      else if (!found)
+       {
+         err = ENODATA;
+         goto cleanup;
+       }
+      else
+       err = xattr_entry_remove (header, entry, location, rest);
+    }
+
+  /* Check if the xattr block is empty */
+  entry = EXT2_XATTR_ENTRY_FIRST (header);
+  int empty = EXT2_XATTR_ENTRY_LAST (entry);
+
+  if (err == 0)
+    {
+      if (empty)
+       {
+         disk_cache_block_deref (block);
+         dino_deref (ei);
+
+         return ext2_free_xattr_block (np);
+       }
+      else
+       {
+         xattr_entry_rehash (header, location);
+
+         record_global_poke (block);
+
+         if (ei->i_file_acl == 0)
+           {
+             np->dn_stat.st_blocks += 1 << log2_stat_blocks_per_fs_block;
+             np->dn_set_ctime = 1;
+
+             ei->i_file_acl = blkno;
+             record_global_poke (ei);
+           }
+         else
+             dino_deref (ei);
+
+         return 0;
+       }
+    }
+
+cleanup:
+  if (block)
+    disk_cache_block_deref (block);
+  if (ei->i_file_acl == 0 && blkno != 0)
+    /* We allocated a block, but for some reason we did not register
+       it.  */
+    ext2_free_blocks (blkno, 1);
+  dino_deref (ei);
+
+  return err;
+
+}
diff --git a/ext2fs/xattr.h b/ext2fs/xattr.h
new file mode 100644
index 0000000..245f896
--- /dev/null
+++ b/ext2fs/xattr.h
@@ -0,0 +1,85 @@
+ /* Ext2 support for extended attributes
+
+   Copyright (C) 2006, 2016 Free Software Foundation, Inc.
+
+   Written by Thadeu Lima de Souza Cascardo <address@hidden>
+   and Shengyu Zhang <address@hidden>
+
+   This program is free software; you can redistribute it and/or
+   modify it under the terms of the GNU General Public License as
+   published by the Free Software Foundation; either version 2, or (at
+   your option) any later version.
+
+   This program is distributed in the hope that it will be useful, but
+   WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#ifndef EXT2_XATTR_H
+#define EXT2_XATTR_H
+
+#include "ext2fs.h"
+
+/* Identifies whether a block is a proper xattr block. */
+#define EXT2_XATTR_BLOCK_MAGIC 0xEA020000
+
+/* xattr block header. */
+struct ext2_xattr_header
+{
+  __u32 h_magic;       /* h_magic number for identification */
+  __u32 h_refcount;    /* reference count */
+  __u32 h_blocks;      /* number of disk blocks used */
+  __u32 h_hash;        /* hash value of all attributes */
+  __u32 h_reserved[4]; /* zero right now */
+};
+
+/* xattr entry in xattr block. */
+struct ext2_xattr_entry
+{
+  __u8 e_name_len;     /* length of name */
+  __u8 e_name_index;   /* attribute name index */
+  __u16 e_value_offs;  /* offset in disk block of value */
+  __u32 e_value_block; /* disk block attribute is stored on (n/i) */
+  __u32 e_value_size;  /* size of attribute value */
+  __u32 e_hash;                /* hash value of name and value */
+  char e_name[0];      /* attribute name */
+};
+
+#define EXT2_XATTR_PAD_BITS 2
+#define EXT2_XATTR_PAD (1 << EXT2_XATTR_PAD_BITS)
+#define EXT2_XATTR_ROUND (EXT2_XATTR_PAD - 1)
+
+/* Entry alignment in xattr block. */
+#define EXT2_XATTR_ALIGN(x) (((unsigned long) (x) + \
+                             EXT2_XATTR_ROUND) & \
+                            (~EXT2_XATTR_ROUND))
+
+/* Given a fs block, return the xattr header. */
+#define EXT2_XATTR_HEADER(block) ((struct ext2_xattr_header *) block)
+
+/* Aligned size of entry, including the name length. */
+#define EXT2_XATTR_ENTRY_SIZE(len) EXT2_XATTR_ALIGN ((sizeof \
+                                                     (struct ext2_xattr_entry) 
+ \
+                                                     len))
+
+/* Offset of entry, given the block header. */
+#define EXT2_XATTR_ENTRY_OFFSET(header, entry) ((off_t) ((char *) entry - \
+                                                        (char *) header))
+
+/* First entry of xattr block, given its header. */
+#define EXT2_XATTR_ENTRY_FIRST(header) ((struct ext2_xattr_entry *) (header + 
1))
+
+/* Next entry, giving an entry. */
+#define EXT2_XATTR_ENTRY_NEXT(entry) ((struct ext2_xattr_entry *) \
+                                     ((char *) entry + \
+                                      EXT2_XATTR_ENTRY_SIZE \
+                                      (entry->e_name_len)))
+
+/* Checks if this entry is the last (not valid) one. */
+#define EXT2_XATTR_ENTRY_LAST(entry) (*(unsigned long *) entry == 0UL)
+
+#endif
diff --git a/libports/interrupt-rpcs.c b/libports/interrupt-rpcs.c
index 42f51a5..7017548 100644
--- a/libports/interrupt-rpcs.c
+++ b/libports/interrupt-rpcs.c
@@ -26,13 +26,17 @@ ports_interrupt_rpcs (void *portstruct)
 {
   struct port_info *pi = portstruct;
   struct rpc_info *rpc;
+  thread_t self = hurd_thread_self ();
 
   pthread_mutex_lock (&_ports_lock);
   
   for (rpc = pi->current_rpcs; rpc; rpc = rpc->next)
     {
-      hurd_thread_cancel (rpc->thread);
-      _ports_record_interruption (rpc);
+      if (rpc->thread != self)
+       {
+         hurd_thread_cancel (rpc->thread);
+         _ports_record_interruption (rpc);
+       }
     }
 
   pthread_mutex_unlock (&_ports_lock);
diff --git a/libshouldbeinlibc/assert-backtrace.h 
b/libshouldbeinlibc/assert-backtrace.h
index c54b810..af1d590 100644
--- a/libshouldbeinlibc/assert-backtrace.h
+++ b/libshouldbeinlibc/assert-backtrace.h
@@ -23,7 +23,7 @@
 #ifdef NDEBUG
 
 #define assert_backtrace(expr)         ((void) 0)
-#define assert_backtrace_perror(errnum)        ((void) 0)
+#define assert_perror_backtrace(errnum)        ((void) 0)
 
 #else /* NDEBUG */
 

-- 
Alioth's /usr/local/bin/git-commit-notice on 
/srv/git.debian.org/git/pkg-hurd/hurd.git



reply via email to

[Prev in Thread] Current Thread [Next in Thread]