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

[PATCH] extended attributes support



Hello, to all!

We have already discussed the support of extended attributes. I did not wait for "concrete plans and code." And try to make it by myself. xattrs manifest file in DEBIAN dir. you can dump xattr to this file by getfattr -d. When dpkg install deb packet it parse this file(if exist) and set
appropriate attr.
In the project I'm quite new, so I welcome your suggestions and kommentriev.

From ddfda13ff80d609b39d5845faa39a2fdfcf63476 Mon Sep 17 00:00:00 2001
From: Dmitry Falko <dfalko89@digiflak.com>
Date: Tue, 11 Nov 2014 13:40:20 +0300
Subject: [PATCH] Extended attributes support

add ability to set extended attributes to files when installing,
xattrs stored in xattr file in DEBIAN dir, file format is getfattr -d
text format
---
 configure.ac       |   1 +
 lib/dpkg/dpkg-db.h |  13 +++++
 lib/dpkg/dpkg.h    |   1 +
 m4/dpkg-libs.m4    |  14 +++++
 src/Makefile.am    |   4 +-
 src/archives.c     |  47 +++++++++++++++
 src/archives.h     |   1 +
src/unpack.c | 166 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 8 files changed, 245 insertions(+), 2 deletions(-)

diff --git a/configure.ac b/configure.ac
index ded48fd..72b5a6e 100644
--- a/configure.ac
+++ b/configure.ac
@@ -65,6 +65,7 @@ DPKG_LIB_ZLIB
 DPKG_LIB_BZ2
 DPKG_LIB_LZMA
 DPKG_LIB_SELINUX
+DPKG_LIB_XATTR
 if test "x$build_dselect" = "xyes"; then
    DPKG_LIB_CURSES
 fi
diff --git a/lib/dpkg/dpkg-db.h b/lib/dpkg/dpkg-db.h
index 2dfe264..d393820 100644
--- a/lib/dpkg/dpkg-db.h
+++ b/lib/dpkg/dpkg-db.h
@@ -92,6 +92,18 @@ struct filedetails {
   const char *md5sum;
 };

+struct extattrvalue {
+  struct extattrvalue *next;
+  char *name;
+  char *value;
+};
+
+struct extattr {
+  struct extattr *next;
+  char *filename;
+  struct extattrvalue *attrs;
+};
+
 enum pkgmultiarch {
     PKG_MULTIARCH_NO,
     PKG_MULTIARCH_SAME,
@@ -122,6 +134,7 @@ struct pkgbin {
   struct dpkg_version version;
   struct conffile *conffiles;
   struct arbitraryfield *arbs;
+  struct extattr *xattrs;
 };

 /**
diff --git a/lib/dpkg/dpkg.h b/lib/dpkg/dpkg.h
index 1dfef96..1ea2269 100644
--- a/lib/dpkg/dpkg.h
+++ b/lib/dpkg/dpkg.h
@@ -74,6 +74,7 @@ DPKG_BEGIN_DECLS
 #define PRERMFILE          "prerm"
 #define POSTRMFILE         "postrm"
 #define TRIGGERSCIFILE     "triggers"
+#define XATTRSFILE         "xattrs"

 #define STATUSFILE        "status"
 #define AVAILFILE         "available"
diff --git a/m4/dpkg-libs.m4 b/m4/dpkg-libs.m4
index 5c45b0f..caa5ccb 100644
--- a/m4/dpkg-libs.m4
+++ b/m4/dpkg-libs.m4
@@ -144,3 +144,17 @@ AC_DEFUN([DPKG_LIB_SSD],
AC_CHECK_LIB([ps], [proc_stat_list_create], [SSD_LIBS="${SSD_LIBS:+$SSD_LIBS }-lps"]) AC_CHECK_LIB([kvm], [kvm_openfiles], [SSD_LIBS="${SSD_LIBS:+$SSD_LIBS }-lkvm"])
 ])# DPKG_LIB_SSD
+
+# DPKG_LIB_XATTR
+# ------------
+# Check for start-stop-daemon libraries.
+AC_DEFUN([DPKG_LIB_XATTR],
+[AC_ARG_VAR([XATTR_LIBS], [linker flags for xattrs support])dnl
+AC_ARG_WITH(xattr,
+  AS_HELP_STRING([--with-xattr],
+           [use xattr library to set extended attributes]))
+if test "x$with_xattr" = "xyes"; then
+ AC_CHECK_LIB([attr], [attr_copy_action], [XATTR_LIBS="${XATTR_LIBS:+$XATTR_LIBS }-lattr"])
+  AC_DEFINE(WITH_XATTRS, 1, [define to support xattrs])
+fi
+])# DPKG_LIB_XATTR
diff --git a/src/Makefile.am b/src/Makefile.am
index 2382d75..7cce3b4 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -13,7 +13,6 @@ LDADD = \
     ../lib/dpkg/libdpkg.la \
     $(LIBINTL)

-
 EXTRA_DIST = \
     $(test_scripts) \
     $(nil)
@@ -59,7 +58,8 @@ dpkg_SOURCES = \

 dpkg_LDADD = \
     $(LDADD) \
-    $(SELINUX_LIBS)
+    $(SELINUX_LIBS) \
+    $(XATTR_LIBS)

 dpkg_divert_SOURCES = \
     filesdb.c \
diff --git a/src/archives.c b/src/archives.c
index 8f6b4cf..fc16a98 100644
--- a/src/archives.c
+++ b/src/archives.c
@@ -63,6 +63,11 @@
 #include <selinux/label.h>
 #endif

+#ifdef WITH_XATTRS
+#include <attr/xattr.h>
+#include <attr/attributes.h>
+#endif
+
 #include "filesdb.h"
 #include "main.h"
 #include "archives.h"
@@ -260,6 +265,42 @@ tarobject_skip_padding(struct tarcontext *tc, struct tar_entry *te)
 }

 static void
+tarobject_set_xattrs(struct tarcontext *tc, const char *path)
+{
+#ifdef WITH_XATTRS
+  struct extattr *attrs;
+  struct extattrvalue *values;
+  /*
+   * current filesystem can return ENOTSUP or, in that case user or packet
+   * should have information about what to do in than case
+   */
+  debug(dbg_general,"tarobject_set_xattrs file=%s", path);
+  if(tc->pkg->available.xattrs == NULL)
+    return;
+
+  attrs = tc->pkg->available.xattrs;
+
+  /*search filename in list*/
+  while(attrs != NULL) {
+ if(attrs->filename != NULL && memcmp(attrs->filename, path, strlen(attrs->filename)) == 0) {
+      break;
+    }
+    attrs = attrs->next;
+  }
+
+  if(attrs != NULL) { /*if finded */
+    values = attrs->attrs;
+
+    while(values != NULL) {
+ setxattr(path, values->name, values->value, strlen(values->value), 0); + debug(dbg_general,"setting '%.255s'='%.255s' for '%.255s'", values->name, values->value, path);
+      values = values->next;
+    }
+  }
+#endif
+}
+
+static void
 tarobject_skip_entry(struct tarcontext *tc, struct tar_entry *ti)
 {
   /* We need to advance the tar file to the next object, so read the
@@ -350,6 +391,12 @@ tarobject_extract(struct tarcontext *tc, struct tar_entry *te,
     namenode->newhash = newhash;
debug(dbg_eachfiledetail, "tarobject file hash=%s", namenode->newhash);

+    /*
+ * Setting xattrs here, because xattrs must be set before data will be synced.
+     * fd_weiteback_init will sync data to disk
+     */
+    tarobject_set_xattrs(tc, path);
+
     tarobject_skip_padding(tc, te);

     fd_writeback_init(fd);
diff --git a/src/archives.h b/src/archives.h
index 07e74af..30c7f46 100644
--- a/src/archives.h
+++ b/src/archives.h
@@ -73,6 +73,7 @@ int secure_remove(const char *filename);
 int tarobject(void *ctx, struct tar_entry *ti);
 int tarfileread(void *ud, char *buf, int len);
 void tar_deferred_extract(struct fileinlist *files, struct pkginfo *pkg);
+void parse_xattrs(const char *filename, struct pkginfo *pkgp);

 bool filesavespackage(struct fileinlist *, struct pkginfo *,
                       struct pkginfo *pkgbeinginstalled);
diff --git a/src/unpack.c b/src/unpack.c
index a44f478..59abcef 100644
--- a/src/unpack.c
+++ b/src/unpack.c
@@ -53,6 +53,7 @@
 #include <dpkg/tarfn.h>
 #include <dpkg/options.h>
 #include <dpkg/triglib.h>
+#include <dpkg/fdio.h>

 #include "filesdb.h"
 #include "file-match.h"
@@ -494,6 +495,165 @@ pkgset_getting_in_sync(struct pkginfo *pkg)
   return true;
 }

+static char *
+unquote(char *str)
+{
+    unsigned char *s, *t;
+
+    if (!str)
+        return str;
+
+    for (s = (unsigned char *)str; *s != '\0'; s++)
+        if (*s == '\\')
+            break;
+    if (*s == '\0')
+        return str;
+
+#define isoctal(c) \
+    ((c) >= '0' && (c) <= '7')
+
+    t = s;
+    do {
+        if (*s == '\\' &&
+            isoctal(*(s+1)) && isoctal(*(s+2)) && isoctal(*(s+3))) {
+            *t++ = ((*(s+1) - '0') << 6) +
+                   ((*(s+2) - '0') << 3) +
+                   ((*(s+3) - '0')     );
+            s += 3;
+        } else
+            *t++ = *s;
+    } while (*s++ != '\0');
+
+    return str;
+}
+
+void
+parse_xattrs(const char *filename, struct pkginfo *pkgp)
+{
+#define STRING_LEN 8
+  int fd;
+  struct stat st;
+  char *data, *dataend, *dataptr;
+  char *linestart, *fieldname, *fieldvalue;
+  int linelen, fieldlen;
+  struct extattr *attrs;
+  struct extattrvalue *values;
+
+  fd = open(filename, O_RDONLY);
+  if(fd == -1) {
+    /*
+     * No file, no problem
+     */
+      debug(dbg_general,"xattrs manifest file doesn't exist");
+      return;
+  }
+
+  if (fstat(fd, &st) == -1)
+    ohshite(_("can't stat xattrs manifest file `%.255s'"), filename);
+
+  data = m_malloc(st.st_size);
+  if (fd_read(fd, data, st.st_size) < 0)
+    ohshite(_("reading xattrs manifest file '%.255s'"), filename);
+
+  push_cleanup(cu_closefd, ~ehflag_normaltidy, NULL, 0, 1, &fd);
+
+  linestart = dataptr = data;
+  dataend = data + st.st_size;
+
+  pkgp->available.xattrs = NULL;
+
+  while(linestart != dataend) {
+    /*pass empty lines*/
+    if(*linestart == '\n' || isspace(*linestart)) {
+      linestart++;
+      continue;
+    }
+    if(dataptr == dataend) {
+      /* end of file */
+      break;
+    }
+    /*read line*/
+    dataptr = linestart;
+    while(dataptr != dataend && *dataptr != '\n')
+      dataptr++;
+    linelen = dataptr - linestart;
+    if(linelen <= 8) {
+      continue; /* if line too short */
+    }
+
+    if(strncmp(linestart, "# file: ", STRING_LEN) != 0) {
+      continue; /* not our line */
+    }
+    linestart += STRING_LEN; /*TODO: change to define*/
+
+    if(pkgp->available.xattrs == NULL) {
+      pkgp->available.xattrs = m_malloc(sizeof(struct extattr));
+      attrs = pkgp->available.xattrs;
+    } else {
+      attrs->next = m_malloc(sizeof(struct extattr));
+      attrs = attrs->next;
+    }
+    memset(attrs, 0, sizeof(struct extattr));
+
+    linelen -= STRING_LEN; /*TODO: change to define*/
+    /* size bigger because we need add '/' to begining
+     * and '\0' to end */
+    attrs->filename = m_malloc(linelen + 2);
+    memset(attrs->filename, '\0', linelen + 2);
+    memcpy(attrs->filename + 1, linestart, linelen);
+    *(attrs->filename) = '/';
+    attrs->filename = unquote(attrs->filename);
+    dataptr++;
+
+    while(1) {
+      /*parse attrs*/
+        fieldname = dataptr;
+
+        if(*dataptr == '\n' || dataptr == dataend) {
+          /* go out */
+          break;
+        }
+
+        if(attrs->attrs == NULL) {
+          attrs->attrs = m_malloc(sizeof(struct extattrvalue));
+          values = attrs->attrs;
+        } else {
+          values->next = m_malloc(sizeof(struct extattrvalue));
+          values = values->next;
+          values->next = NULL;
+        }
+        memset(values, 0, sizeof(struct extattrvalue));
+
+        /*read fieldname*/
+        while(dataptr != dataend && *dataptr != '=')
+          dataptr++;
+        fieldlen = dataptr - fieldname;
+
+        values->name = m_malloc(fieldlen + 1);
+        memset(values->name, '\0', fieldlen + 1);
+        memcpy(values->name, fieldname, fieldlen);
+        values->name = unquote(values->name);
+
+        dataptr++;
+        fieldvalue = dataptr;
+        while(dataptr != dataend && *dataptr != '\n')
+          dataptr++;
+
+        fieldlen = dataptr - fieldvalue;
+        /*size is smaller because we delete quotes*/
+        values->value = m_malloc(fieldlen - 1);
+        memset(values->value, '\0', fieldlen - 1);
+        memcpy(values->value, fieldvalue + 1, fieldlen - 2);
+        values->value = unquote(values->value);
+
+        dataptr++;
+      }
+    linestart = dataptr;
+
+  }
+  free(data);
+}
+
 void process_archive(const char *filename) {
   static const struct tar_operations tf = {
     .read = tarfileread,
@@ -860,6 +1020,12 @@ void process_archive(const char *filename) {
                     NULL);
   }

+  /*
+   * Parse xattrs manifest
+   */
+  strcpy(cidirrest, XATTRSFILE);
+  parse_xattrs(cidir, pkg);
+
   if (oldversionstatus == PKG_STAT_NOTINSTALLED ||
       oldversionstatus == PKG_STAT_CONFIGFILES) {
     printf(_("Unpacking %s (%s) ...\n"),
--
1.9.1


Reply to: