diff options
-rw-r--r-- | debian/patches/series | 3 | ||||
-rw-r--r-- | debian/patches/xattr0001-ext2fs-add-xattr-support.patch | 1070 | ||||
-rw-r--r-- | debian/patches/xattr0002-ext2fs-using-xattr-to-store-translator-record.patch | 231 | ||||
-rw-r--r-- | debian/patches/xattr0003-Small-fixes.patch | 44 |
4 files changed, 0 insertions, 1348 deletions
diff --git a/debian/patches/series b/debian/patches/series index ee48c124..a8ae5e3b 100644 --- a/debian/patches/series +++ b/debian/patches/series @@ -43,6 +43,3 @@ nfs0001-nfs-fix-memory-leak.patch corefiles0001-trans-crash-xxx-core-file-templates.patch leaks0001-xxx-print-fail.patch -xattr0001-ext2fs-add-xattr-support.patch -xattr0002-ext2fs-using-xattr-to-store-translator-record.patch -xattr0003-Small-fixes.patch diff --git a/debian/patches/xattr0001-ext2fs-add-xattr-support.patch b/debian/patches/xattr0001-ext2fs-add-xattr-support.patch deleted file mode 100644 index ec6bd8be..00000000 --- a/debian/patches/xattr0001-ext2fs-add-xattr-support.patch +++ /dev/null @@ -1,1070 +0,0 @@ -From 7fec7f3357fbe6bce33a161b6b982feccf88d556 Mon Sep 17 00:00:00 2001 -From: Shengyu Zhang <lastavengers@outlook.com> -Date: Thu, 7 Jul 2016 23:47:39 +0200 -Subject: [PATCH hurd 1/3] ext2fs: add xattr support - -This patch is base on cascardo's previous work[1], -Only 2 namespaces ("user." and "gnu.") are supported, -as other namespaces are useless on hurd now. - -[1]: https://savannah.gnu.org/patch/?5126 - -* ext2fs/Makefile: Needs description. -* ext2fs/ext2_fs.h: Likewise. -* ext2fs/ext2fs.h: Likewise. -* ext2fs/ialloc.c: Likewise. -* ext2fs/xattr.c: New file. -* ext2fs/xattr.h: Likewise. ---- - ext2fs/Makefile | 3 +- - ext2fs/ext2_fs.h | 3 +- - ext2fs/ext2fs.h | 13 + - ext2fs/ialloc.c | 2 + - ext2fs/xattr.c | 866 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ - ext2fs/xattr.h | 85 ++++++ - 6 files changed, 970 insertions(+), 2 deletions(-) - create mode 100644 ext2fs/xattr.c - create mode 100644 ext2fs/xattr.h - -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.h b/ext2fs/ext2fs.h -index 070d5bd..bbf7a0c 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> -@@ -571,3 +574,13 @@ 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, int *len); -+error_t ext2_get_xattr (struct node *np, const char *name, char *value, int *len); -+error_t ext2_set_xattr (struct node *np, const char *name, const char *value, int len, int flags); -+error_t ext2_free_xattr_block (struct node *np); -+ -+#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/xattr.c b/ext2fs/xattr.c -new file mode 100644 -index 0000000..eea5ef6 ---- /dev/null -+++ b/ext2fs/xattr.c -@@ -0,0 +1,866 @@ -+ /* Ext2 support for extended attributes -+ -+ Copyright (C) 2006, 2016 Free Software Foundation, Inc. -+ -+ Written by Thadeu Lima de Souza Cascardo <cascardo@dcc.ufmg.br> -+ and Shengyu Zhang <lastavengers@outlook.com> -+ -+ 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, int *len) -+{ -+ -+ int i; -+ int 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 (char *block, struct ext2_xattr_entry *entry, -+ const char *full_name, char *value, int *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, -+ int len, int rest) -+{ -+ -+ int i; -+ int name_len; -+ off_t start; -+ off_t end; -+ int entry_size; -+ int 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 (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, int 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, int len, int rest) -+{ -+ -+ ssize_t old_size; -+ ssize_t new_size; -+ -+ old_size = EXT2_XATTR_ALIGN (position->e_value_size); -+ new_size = EXT2_XATTR_ALIGN (len); -+ -+ if (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, int *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; -+ -+ int 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, int *len) -+{ -+ -+ int size; -+ int err; -+ void *block; -+ struct ext2_inode *ei; -+ block_t blkno; -+ 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; -+ -+ size = *len; -+ -+ ei = dino_ref (np->cache_id); -+ blkno = ei->i_file_acl; -+ dino_deref (ei); -+ -+ if (blkno == 0) -+ { -+ return ENODATA; -+ } -+ -+ 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; -+ } -+ -+ err = ENODATA; -+ entry = EXT2_XATTR_ENTRY_FIRST (header); -+ -+ while (!EXT2_XATTR_ENTRY_LAST (entry)) -+ { -+ 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, int len, -+ int flags) -+{ -+ -+ int found; -+ int 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; -+ -+ 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); -+ block = disk_cache_block_ref (blkno); -+ -+ if (blkno == 0) -+ { -+ err = ENOSPC; -+ goto cleanup; -+ } -+ -+ 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)) -+ { -+ int 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 entry 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); -+ dino_deref (ei); -+ -+ return err; -+ -+} -diff --git a/ext2fs/xattr.h b/ext2fs/xattr.h -new file mode 100644 -index 0000000..d9b87e6 ---- /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 <cascardo@dcc.ufmg.br> -+ and Shengyu Zhang <lastavengers@outlook.com> -+ -+ 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 --- -2.1.4 - diff --git a/debian/patches/xattr0002-ext2fs-using-xattr-to-store-translator-record.patch b/debian/patches/xattr0002-ext2fs-using-xattr-to-store-translator-record.patch deleted file mode 100644 index 5b2d2632..00000000 --- a/debian/patches/xattr0002-ext2fs-using-xattr-to-store-translator-record.patch +++ /dev/null @@ -1,231 +0,0 @@ -From 8743e2f7c22c50bcc289c1a5ac093731f9d1638c Mon Sep 17 00:00:00 2001 -From: Shengyu Zhang <lastavengers@outlook.com> -Date: Fri, 8 Jul 2016 00:21:52 +0200 -Subject: [PATCH hurd 2/3] ext2fs: using xattr to store translator record - -The purpose we implement xattr is storing passive translator in a -more general way. Now passive translator record now can be stored -using extended attributes. The new diskfs_{get,set}_translator() -functions are also compatibility with the "legacy" passive translator -record. - -Thanks for antrik's suggestions. ---- - ext2fs/inode.c | 158 +++++++++++++++++++++++++++++---------------------------- - 1 file changed, 81 insertions(+), 77 deletions(-) - -diff --git a/ext2fs/inode.c b/ext2fs/inode.c -index ccc8d69..175bc26 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. */ -@@ -540,81 +541,62 @@ error_t - diskfs_set_translator (struct node *np, const char *name, unsigned namelen, - struct protid *cred) - { -- daddr_t blkno; -+ int len; - 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 a old translator record found, clear it */ -+ if (sblock->s_creator_os == EXT2_OS_HURD) - { -- /* 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; -- } -+ daddr_t blkno; -+ struct ext2_inode *di; - -- di->i_translator = blkno; -- diskfs_node_disknode (np)->info_i_translator = blkno; -- record_global_poke (di); -+ di = dino_ref (np->cache_id); -+ blkno = di->i_translator; - -- 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 (blkno) -+ { -+ ext2_warning("Old tranlator 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); - } -- else -- dino_deref (di); - -- if (namelen) -- { -- void *blkptr; -- -- buf[0] = namelen & 0xFF; -- buf[1] = (namelen >> 8) & 0xFF; -- memcpy (buf + 2, name, namelen); -+ /* Use xattr to store translator record, with key "gnu.translator" */ -+ err = ext2_get_xattr(np, "gnu.translator", NULL, &len); -+ if (err && err != ENODATA) -+ return err; - -- blkptr = disk_cache_block_ref (blkno); -- memcpy (blkptr, buf, block_size); -- record_global_poke (blkptr); -+ if (namelen && err == ENODATA) -+ { -+ err = ext2_set_xattr(np, "gnu.translator", name, namelen, XATTR_CREATE); - - np->dn_stat.st_mode |= S_IPTRANS; - np->dn_set_ctime = 1; - } -+ else if (!namelen && !err) -+ { -+ err = ext2_set_xattr(np, "gnu.translator", NULL, 0, 0); -+ } - - diskfs_end_catch_exception (); - return err; -+ - } - - /* Implement the diskfs_get_translator callback from the diskfs library. -@@ -623,37 +605,59 @@ error_t - diskfs_get_translator (struct node *np, char **namep, unsigned *namelen) - { - error_t err = 0; -- daddr_t blkno; -- unsigned datalen; -- void *transloc; -- struct ext2_inode *di; -- -- assert (sblock->s_creator_os == EXT2_OS_HURD); -+ int datalen; - - err = diskfs_catch_exception (); - if (err) - return err; - -- 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 a old translator record found, read it firstly */ -+ if (sblock->s_creator_os == EXT2_OS_HURD) - { -- *namep = malloc (datalen); -- if (!*namep) -- err = ENOMEM; -- else -- memcpy (*namep, transloc + 2, datalen); -+ daddr_t blkno; -+ void *transloc; -+ struct ext2_inode *di; -+ -+ di = dino_ref (np->cache_id); -+ blkno = di->i_translator; -+ dino_deref (di); -+ -+ if (blkno) -+ { -+ ext2_warning("This is a old translotor 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 -+ { -+ *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; --- -2.1.4 - diff --git a/debian/patches/xattr0003-Small-fixes.patch b/debian/patches/xattr0003-Small-fixes.patch deleted file mode 100644 index 5c9b7ea5..00000000 --- a/debian/patches/xattr0003-Small-fixes.patch +++ /dev/null @@ -1,44 +0,0 @@ -From 19f7a0af88ebd92223c89c7134d5ba15b781c8d9 Mon Sep 17 00:00:00 2001 -From: Justus Winter <justus@gnupg.org> -Date: Thu, 14 Jul 2016 23:53:28 +0200 -Subject: [PATCH hurd 3/3] Small fixes - ---- - ext2fs/inode.c | 15 +++++++-------- - 1 file changed, 7 insertions(+), 8 deletions(-) - -diff --git a/ext2fs/inode.c b/ext2fs/inode.c -index 175bc26..fd28295 100644 ---- a/ext2fs/inode.c -+++ b/ext2fs/inode.c -@@ -578,20 +578,19 @@ diskfs_set_translator (struct node *np, const char *name, unsigned namelen, - } - - /* Use xattr to store translator record, with key "gnu.translator" */ -- err = ext2_get_xattr(np, "gnu.translator", NULL, &len); -- if (err && err != ENODATA) -- return err; -- -- if (namelen && err == ENODATA) -+ if (namelen) - { -- err = ext2_set_xattr(np, "gnu.translator", name, namelen, XATTR_CREATE); -+ err = ext2_set_xattr (np, "gnu.translator", name, namelen, 0); - - np->dn_stat.st_mode |= S_IPTRANS; - np->dn_set_ctime = 1; - } -- else if (!namelen && !err) -+ else - { -- err = ext2_set_xattr(np, "gnu.translator", NULL, 0, 0); -+ err = ext2_set_xattr (np, "gnu.translator", NULL, 0, 0); -+ -+ np->dn_stat.st_mode &= ~S_IPTRANS; -+ np->dn_set_ctime = 1; - } - - diskfs_end_catch_exception (); --- -2.1.4 - |