save metadata to extended file attributes
authorStefan Tomanek <stefan.tomanek@wertarbyte.de>
Fri, 5 Nov 2010 11:39:46 +0000 (12:39 +0100)
committerDaniel Stenberg <daniel@haxx.se>
Fri, 5 Nov 2010 12:59:10 +0000 (13:59 +0100)
It is often convinient to track back the source of a once downloaded
file; this patch makes curl store the source URL and other metadata
alongside the retrieved file by using the extended attributes (if
supported by the file system and enabled by --xattr).

src/Makefile.inc
src/main.c
src/xattr.c [new file with mode: 0644]
src/xattr.h [new file with mode: 0644]

index 34dfd45..058c6d2 100644 (file)
@@ -15,11 +15,12 @@ CURLX_ONES = $(top_srcdir)/lib/strtoofft.c \
        $(top_srcdir)/lib/nonblock.c
 
 CURL_CFILES = main.c hugehelp.c urlglob.c writeout.c writeenv.c \
-       getpass.c homedir.c curlutil.c os-specific.c
+       getpass.c homedir.c curlutil.c os-specific.c xattr.c
 
 CURL_HFILES = hugehelp.h setup.h config-win32.h config-mac.h \
        config-riscos.h urlglob.h version.h os-specific.h \
-       writeout.h writeenv.h getpass.h homedir.h curlutil.h
+       writeout.h writeenv.h getpass.h homedir.h curlutil.h \
+       xattr.h
 
 curl_SOURCES = $(CURL_CFILES) $(CURLX_ONES) $(CURL_HFILES)
 
index 8a942de..5394bac 100644 (file)
@@ -51,6 +51,8 @@
 #endif
 #include "rawstr.h"
 
+#include "xattr.h"
+
 #define CURLseparator   "--_curl_--"
 
 #ifdef NETWARE
@@ -621,6 +623,7 @@ struct Configurable {
   int default_node_flags; /* default flags to seach for each 'node', which is
                              basically each given URL to transfer */
   struct OutStruct *outs;
+  bool xattr; /* store metadata in extended attributes */
 };
 
 #define WARN_PREFIX "Warning: "
@@ -906,6 +909,7 @@ static void help(void)
     "    --wdebug        Turn on Watt-32 debugging",
 #endif
     " -w/--write-out <format> What to output after completion",
+    " --xattr            Store metadata in extended file attributes",
     " -q                 If used as the first parameter disables .curlrc",
     NULL
   };
@@ -1953,6 +1957,7 @@ static ParameterError getparameter(char *flag, /* f or -long-flag */
     {"y", "speed-time", TRUE},
     {"z", "time-cond",   TRUE},
     {"#", "progress-bar",FALSE},
+    {"~", "xattr",FALSE},
   };
 
   if(('-' != flag[0]) ||
@@ -2445,6 +2450,9 @@ static ParameterError getparameter(char *flag, /* f or -long-flag */
       else
         config->progressmode = CURL_PROGRESS_STATS;
       break;
+    case '~': /* --xattr */
+      config->xattr = toggle;
+      break;
     case '0':
       /* HTTP version 1.0 */
       config->httpversion = CURL_HTTP_VERSION_1_0;
@@ -5639,6 +5647,15 @@ operate(struct Configurable *config, int argc, argv_item_t argv[])
           }
         }
 
+        if(config->xattr && outs.filename) {
+          char *url = NULL;
+          curl_easy_getinfo(curl, CURLINFO_EFFECTIVE_URL, &url);
+          int err = write_xattr( curl, outs.filename );
+          if (err) {
+            warnf( config, "Error setting extended attributes: %s\n", strerror(errno) );
+          }
+        }
+
 #ifdef HAVE_UTIME
         /* Important that we set the time _after_ the file has been
            closed, as is done above here */
diff --git a/src/xattr.c b/src/xattr.c
new file mode 100644 (file)
index 0000000..fbc09c2
--- /dev/null
@@ -0,0 +1,37 @@
+#include <sys/types.h>
+#include <sys/xattr.h> /* include header from libc, not from libattr */
+#include <string.h>
+#include <curl/curl.h>
+#include "xattr.h"
+
+/* mapping table of curl metadata to extended attribute names */
+static struct xattr_mapping {
+  char *attr; /* name of the xattr */
+  CURLINFO info;
+} mappings[] = {
+  /* mappings proposed by
+   * http://freedesktop.org/wiki/CommonExtendedAttributes
+   */
+  { "user.xdg.origin.url", CURLINFO_EFFECTIVE_URL },
+  { "user.mime_type", CURLINFO_CONTENT_TYPE },
+  { NULL, 0 } /* last element, abort loop here */
+};
+
+/* store metadata from the curl request alongside the downloaded
+ * file using extended attributes
+ */
+int write_xattr( CURL *curl, const char *filename )
+{
+  int i = 0;
+  int err = 0;
+  /* loop through all xattr-curlinfo pairs and abort on error */
+  while ( err == 0 && mappings[i].attr != NULL ) {
+    char *value = NULL;
+    curl_easy_getinfo(curl, mappings[i].info, &value);
+    if (value) {
+      err = setxattr( filename, mappings[i].attr, value, strlen(value), 0 );
+    }
+    i++;
+  }
+  return err;
+}
diff --git a/src/xattr.h b/src/xattr.h
new file mode 100644 (file)
index 0000000..3067397
--- /dev/null
@@ -0,0 +1 @@
+int write_xattr( CURL *curl, const char *filename );