Re: New --set-content-location functionality...

Anjan Samanta <[email protected]> Thu, 25 Aug 2005 02:30:44 +0100
Newsgroups gmane.comp.web.wget.patches
Message-ID <[email protected]>
Not much response on this patch so far; so I'm wondering whether it fell into
a hole... Is this kind of feature in principle a thumbs-up, a thumbs-down, or
a needs-thinking-about? I can repost to the general mailing list, if that
would be better...
--anjansamanta

On Saturday 13 August 2005 16:31, Anjan Samanta wrote:
# I got tired of not knowing where all my files came from,
# I thought that my shell experience could be a little richer,
# and so I wrote this patch to do some information capture for me.
# 
# When you use --set-content-location, wget will add an extended attribute
# onto all of your downloaded files telling you where the file came from.
# The extended attribute is called user.Content-Location, and it will
# naturally only be created on file-systems that support extended attributes.
# 
# This patch can be broken down into 4 parts:
#  - `./configure --enable-xattr' option:  configure.in INSTALL NEWS
#  - `wget --set-content-location' option: options.h init.c main.c
#  - core functionality:                   http.c ftp.c ftp-ls.c convert.c
#  - documentation:                        wget.texi sample.wgetrc
# 
# I think that the ChangeLog entries should look something like this:
# 
# 2005-08-13  Anjan Samanta  <[email protected]>
# 	New --set-content-location functionality.
# 	* NEWS: New --set-content-location flag.
# 	* INSTALL: New --enable-xattr option to ./configure.
# 	* configure.in: New --enable-xattr option checks for extended file
# 	attribute functionality.
# 
# 2005-08-13  Anjan Samanta  <[email protected]>
# 	New --set-content-location functionality.
# 	* options.h (struct options): New flag opt.content_location_xattr.
# 	* init.c (commands): Added setcontentlocation.
# 	* main.c (option_data): Added set-content-location/setcontentlocation.
# 	(print_help): Added --set-content-location flag.
# 	(main) Now unlink()-s opt.output_document if we were going to truncate
# 	it anyway, in order to have a nice clean file to set xattrs on.
# 
# 	New --set-content-location functionality.
# 	* http.c (gethttp): Compute and set user.Content-Location xattr.
# 	* ftp.c (getftp, ftp_retrieve_list): Set user.Content-Location xattr.
# 	* ftp-ls (ftp_index): Set user.Content-Location xattr on symlink.
# 	* convert.c (convert_links): Transfer user.Content-Location xattr
# 	from the unlink()-d file to the file that replaces it.
# 
# 2005-08-13  Anjan Samanta  <[email protected]>
# 	New --set-content-location functionality.
# 	* wget.texi (Download Options): Added --set-content-location flag.
# 	* sample.wgetrc: Added set-content-location flag.
# 
# Here's the patch (the output of: svn diff):
# 
# Index: configure.in
# ===================================================================
# --- configure.in	(revision 2052)
# +++ configure.in	(working copy)
# @@ -447,6 +447,30 @@
#  dnl internationalization macros
#  WGET_WITH_NLS
#  
# +
# +AC_ARG_ENABLE(xattr,
# +[  --disable-xattr         disable support for extended attributes on files],
# +ENABLE_XATTR=$enableval, ENABLE_XATTR=yes)
# +if test x"${ENABLE_XATTR}" = xyes; then
# +  AC_CHECK_HEADER([sys/xattr.h], [], [
# +    AC_MSG_NOTICE([Disabling xattr support; your system does not provide sys/xattr.h])
# +    ENABLE_XATTR=no
# +  ])
# +else
# +  AC_MSG_NOTICE([Skipping support for xattr])
# +fi
# +if test x"${ENABLE_XATTR}" = xyes; then
# +  AC_CHECK_FUNCS(fsetxattr lsetxattr getxattr, [], [
# +    AC_MSG_NOTICE([Disabling xattr support; cannot find getxattr/setxattr(2) implementation])
# +    ENABLE_XATTR=no
# +  ])
# +fi
# +if test x"${ENABLE_XATTR}" = xyes; then
# +  AC_DEFINE([ENABLE_XATTR], 1, [Define if you want to enable xattr functionality.])
# +  AC_MSG_NOTICE([Enabling support for xattr])
# +fi
# +
# +
#  dnl
#  dnl Find makeinfo.  We used to provide support for Emacs processing
#  dnl Texinfo using `emacs -batch -eval ...' where makeinfo is
# Index: src/options.h
# ===================================================================
# --- src/options.h	(revision 2052)
# +++ src/options.h	(working copy)
# @@ -220,6 +220,12 @@
#      prefer_none
#    } prefer_family;		/* preferred address family when more
#  				   than one type is available */
# +
# +#ifdef ENABLE_XATTR
# +  bool content_location_xattr;  /* whether to try to set an extended file
# +				   attribute, user.Content-Type, on the files
# +				   downloaded.  */
# +#endif
#  };
#  
#  extern struct options opt;
# Index: src/init.c
# ===================================================================
# --- src/init.c	(revision 2052)
# +++ src/init.c	(working copy)
# @@ -224,6 +224,9 @@
#    { "secureprotocol",	&opt.secure_protocol,	cmd_spec_secure_protocol },
#  #endif
#    { "serverresponse",	&opt.server_response,	cmd_boolean },
# +#ifdef ENABLE_XATTR
# +  { "setcontentlocation", &opt.content_location_xattr, cmd_boolean },
# +#endif
#    { "spanhosts",	&opt.spanhost,		cmd_boolean },
#    { "spider",		&opt.spider,		cmd_boolean },
#    { "strictcomments",	&opt.strict_comments,	cmd_boolean },
# Index: src/http.c
# ===================================================================
# --- src/http.c	(revision 2052)
# +++ src/http.c	(working copy)
# @@ -39,6 +39,9 @@
#  #include <errno.h>
#  #include <time.h>
#  #include <locale.h>
# +#ifdef ENABLE_XATTR
# +# include <sys/xattr.h>
# +#endif
#  
#  #include "wget.h"
#  #include "http.h"
# @@ -1141,6 +1144,7 @@
#    struct request *req;
#  
#    char *type;
# +  char *content_location = 0;
#    char *user, *passwd;
#    char *proxyauth;
#    int statcode;
# @@ -1717,6 +1721,15 @@
#  	  *tmp = '\0';
#  	}
#      }
# +  content_location = resp_header_strdup (resp, "Content-Location");
# +  if (content_location)
# +    {
# +      char *tmp = uri_merge (u->url, content_location);
# +      xfree_null (content_location);
# +      content_location = tmp;
# +    }
# +  else
# +    content_location = xstrdup (u->url);
#    hs->newloc = resp_header_strdup (resp, "Location");
#    hs->remote_time = resp_header_strdup (resp, "Last-Modified");
#  
# @@ -1772,6 +1785,7 @@
#  	  else
#  	    CLOSE_INVALIDATE (sock);
#  	  xfree_null (type);
# +	  xfree_null (content_location);
#  	  return NEWLOCATION;
#  	}
#      }
# @@ -1830,6 +1844,7 @@
#        /* Mark as successfully retrieved. */
#        *dt |= RETROKF;
#        xfree_null (type);
# +      xfree_null (content_location);
#        CLOSE_INVALIDATE (sock);	/* would be CLOSE_FINISH, but there
#  				   might be more bytes in the body. */
#        return RETRUNNEEDED;
# @@ -1840,6 +1855,7 @@
#        /* The Range request was somehow misunderstood by the server.
#  	 Bail out.  */
#        xfree_null (type);
# +      xfree_null (content_location);
#        CLOSE_INVALIDATE (sock);
#        return RANGEERR;
#      }
# @@ -1889,6 +1905,7 @@
#        hs->len = 0;
#        hs->res = 0;
#        xfree_null (type);
# +      xfree_null (content_location);
#        if (head_only)
#  	/* Pre-1.10 Wget used CLOSE_INVALIDATE here.  Now we trust the
#  	   servers not to send body in response to a HEAD request, and
# @@ -1911,12 +1928,12 @@
#        if (opt.backups)
#  	rotate_backups (*hs->local_file);
#        if (hs->restval)
# -	fp = fopen (*hs->local_file, "ab");
# +	fp = fopen (*hs->local_file, "ab"); /* xattr set below */
#        else if (ALLOW_CLOBBER)
# -	fp = fopen (*hs->local_file, "wb");
# +	fp = fopen (*hs->local_file, "wb"); /* xattr set below */
#        else
#  	{
# -	  fp = fopen_excl (*hs->local_file, true);
# +	  fp = fopen_excl (*hs->local_file, true); /* xattr set below */
#  	  if (!fp && errno == EEXIST)
#  	    {
#  	      /* We cannot just invent a new name and use it (which is
# @@ -1940,6 +1957,18 @@
#    else
#      fp = output_stream;
#  
# +#ifdef ENABLE_XATTR
# +  if (opt.content_location_xattr)
# +    {
# +      if (fsetxattr (fileno (fp), "user.Content-Location", content_location,
# +                     strlen (content_location), XATTR_CREATE) != 0)
# +	fsetxattr (fileno (fp), "user.Content-Location", "", 0, 0);
# +    }
# +#endif
# +
# +  xfree_null (content_location);
# +  content_location = NULL;	/* We don't need it any more.  */
# +
#    /* #### This confuses the timestamping code that checks for file
#       size.  Maybe we should save some additional information?  */
#    if (opt.save_headers)
# Index: src/ftp.c
# ===================================================================
# --- src/ftp.c	(revision 2052)
# +++ src/ftp.c	(working copy)
# @@ -37,6 +37,9 @@
#  #endif
#  #include <assert.h>
#  #include <errno.h>
# +#ifdef ENABLE_XATTR
# +# include <sys/xattr.h>
# +#endif
#  
#  #include "wget.h"
#  #include "utils.h"
# @@ -914,13 +917,13 @@
#  	rotate_backups (con->target);
#  
#        if (restval)
# -	fp = fopen (con->target, "ab");
# +	fp = fopen (con->target, "ab"); /* xattr set below */
#        else if (opt.noclobber || opt.always_rest || opt.timestamping || opt.dirstruct
#  	       || opt.output_document)
# -	fp = fopen (con->target, "wb");
# +	fp = fopen (con->target, "wb"); /* xattr set below */
#        else
#  	{
# -	  fp = fopen_excl (con->target, true);
# +	  fp = fopen_excl (con->target, true); /* xattr set below */
#  	  if (!fp && errno == EEXIST)
#  	    {
#  	      /* We cannot just invent a new name and use it (which is
# @@ -949,6 +952,15 @@
#    else
#      fp = output_stream;
#  
# +#ifdef ENABLE_XATTR
# +  if (opt.content_location_xattr)
# +    {
# +      if (fsetxattr (fileno (fp), "user.Content-Location",
# +                     u->url, strlen (u->url), XATTR_CREATE) != 0)
# +	fsetxattr (fileno (fp), "user.Content-Location", "", 0, 0);
# +    }
# +#endif
# +
#    if (*len)
#      {
#        print_length (*len, restval, true);
# @@ -1492,6 +1504,11 @@
#  		  unlink (con->target);
#  		  if (symlink (f->linkto, con->target) == -1)
#  		    logprintf (LOG_NOTQUIET, "symlink: %s\n", strerror (errno));
# +#ifdef ENABLE_XATTR
# +		  if (opt.content_location_xattr)
# +		    lsetxattr (con->target, "user.Content-Location",
# +                               u->url, strlen (u->url), 0);
# +#endif /* ENABLE_XATTR */
#  		  logputs (LOG_VERBOSE, "\n");
#  		} /* have f->linkto */
#  #else  /* not HAVE_SYMLINK */
# Index: src/ftp-ls.c
# ===================================================================
# --- src/ftp-ls.c	(revision 2052)
# +++ src/ftp-ls.c	(working copy)
# @@ -37,6 +37,9 @@
#  #endif
#  #include <errno.h>
#  #include <time.h>
# +#ifdef ENABLE_XATTR
# +# include <sys/xattr.h>
# +#endif
#  
#  #include "wget.h"
#  #include "utils.h"
# @@ -857,7 +860,7 @@
#  
#    if (!output_stream)
#      {
# -      fp = fopen (file, "wb");
# +      fp = fopen (file, "wb"); /* xattr set below */
#        if (!fp)
#  	{
#  	  logprintf (LOG_NOTQUIET, "%s: %s\n", file, strerror (errno));
# @@ -866,6 +869,16 @@
#      }
#    else
#      fp = output_stream;
# +
# +#ifdef ENABLE_XATTR
# +  if (opt.content_location_xattr)
# +    {
# +      if (fsetxattr (fileno (fp), "user.Content-Location",
# +                     u->url, strlen (u->url), XATTR_CREATE) != 0)
# +	fsetxattr (fileno (fp), "user.Content-Location", "", 0, 0);
# +    }
# +#endif
# +
#    if (u->user)
#      {
#        char *tmpu, *tmpp;        /* temporary, clean user and passwd */
# Index: src/convert.c
# ===================================================================
# --- src/convert.c	(revision 2052)
# +++ src/convert.c	(working copy)
# @@ -37,6 +37,9 @@
#  #endif /* HAVE_UNISTD_H */
#  #include <errno.h>
#  #include <assert.h>
# +#ifdef ENABLE_XATTR
# +# include <sys/xattr.h>
# +#endif
#  
#  #include "wget.h"
#  #include "convert.h"
# @@ -189,6 +192,7 @@
#    FILE *fp;
#    const char *p;
#    downloaded_file_t downloaded_file_return;
# +  char *content_location = 0;
#  
#    struct urlpos *link;
#    int to_url_count = 0, to_file_count = 0;
# @@ -223,6 +227,25 @@
#    if (opt.backup_converted && downloaded_file_return)
#      write_backup_file (file, downloaded_file_return);
#  
# +#ifdef ENABLE_XATTR
# +  if (opt.content_location_xattr)
# +    {
# +      ssize_t tmp = getxattr (file, "user.Content-Location", 0, 0);
# +      if (tmp >= 0)
# +	{
# +	  content_location = xmalloc (tmp + 1);
# +	  tmp = getxattr (file, "user.Content-Location", content_location, tmp);
# +	  if (tmp >= 0)
# +	    content_location[tmp] = '\0';
# +	  else
# +	    {
# +	      xfree_null (content_location);
# +	      content_location = 0;
# +	    }
# +	}
# +    }
# +#endif
# +
#    /* Before opening the file for writing, unlink the file.  This is
#       important if the data in FM is mmaped.  In such case, nulling the
#       file, which is what fopen() below does, would make us read all
# @@ -232,6 +255,7 @@
#        logprintf (LOG_NOTQUIET, _("Unable to delete `%s': %s\n"),
#  		 file, strerror (errno));
#        read_file_free (fm);
# +      xfree_null (content_location);
#        return;
#      }
#    /* Now open the file for writing.  */
# @@ -241,9 +265,21 @@
#        logprintf (LOG_NOTQUIET, _("Cannot convert links in %s: %s\n"),
#  		 file, strerror (errno));
#        read_file_free (fm);
# +      xfree_null (content_location);
#        return;
#      }
# +#ifdef ENABLE_XATTR
# +  else
# +    {
# +      if (opt.content_location_xattr && content_location)
# +	fsetxattr (fileno (fp), "user.Content-Location",
# +                   content_location, strlen (content_location), 0);
# +    }
# +#endif
#  
# +  xfree_null (content_location);
# +  content_location = 0;
# +
#    /* Here we loop through all the URLs in file, replacing those of
#       them that are downloaded with relative references.  */
#    p = fm->content;
# Index: src/main.c
# ===================================================================
# --- src/main.c	(revision 2052)
# +++ src/main.c	(working copy)
# @@ -227,6 +227,9 @@
#      { "save-headers", 0, OPT_BOOLEAN, "saveheaders", -1 },
#      { IF_SSL ("secure-protocol"), 0, OPT_VALUE, "secureprotocol", -1 },
#      { "server-response", 'S', OPT_BOOLEAN, "serverresponse", -1 },
# +#ifdef ENABLE_XATTR
# +    { "set-content-location", 0, OPT_BOOLEAN, "setcontentlocation", -1 },
# +#endif
#      { "span-hosts", 'H', OPT_BOOLEAN, "spanhosts", -1 },
#      { "spider", 0, OPT_BOOLEAN, "spider", -1 },
#      { "strict-comments", 0, OPT_BOOLEAN, "strictcomments", -1 },
# @@ -462,6 +465,11 @@
#         --user=USER               set both ftp and http user to USER.\n"),
#      N_("\
#         --password=PASS           set both ftp and http password to PASS.\n"),
# +#ifdef ENABLE_XATTR
# +    N_("\
# +       --set-content-location    set an extended file attribute,\n\
# +                                 user.Content-Location, on downloaded files.\n"),
# +#endif
#      "\n",
#  
#      N_("\
# @@ -897,8 +905,11 @@
#        else
#  	{
#  	  struct_fstat st;
# +	  if (opt.always_rest == 0)
# +	    unlink (opt.output_document); /* nuke problematic state, if any */
#  	  output_stream = fopen (opt.output_document,
#  				 opt.always_rest ? "ab" : "wb");
# +	  /* xattr set just before stream usage */
#  	  if (output_stream == NULL)
#  	    {
#  	      perror (opt.output_document);
# Index: doc/sample.wgetrc
# ===================================================================
# --- doc/sample.wgetrc	(revision 2052)
# +++ doc/sample.wgetrc	(working copy)
# @@ -58,6 +58,12 @@
#  ## are doing before doing so.
#  ##
#  
# +# Set this to on to put an extended attribute called
# +# user.Content-Location on all your downloaded files containing the url
# +# of where the file was downloaded from. (This option has no effect if
# +# your filesystem does not support extended attributes.)
# +#set-content-location = off
# +
#  # Set this to on to use timestamping by default:
#  #timestamping = off
#  
# Index: doc/wget.texi
# ===================================================================
# --- doc/wget.texi	(revision 2052)
# +++ doc/wget.texi	(working copy)
# @@ -969,6 +969,13 @@
#  using the @samp{--ftp-user} and @samp{--ftp-password} options for 
#  @sc{ftp} connections and the @samp{--http-user} and @samp{--http-password} 
#  options for @sc{http} connections.
# +
# +@cindex Content-Location, capture
# +@cindex extended file attributes
# +@item --set-content-location
# +On filesystems that support it, add onto every downloaded file, an
# +extended attribute called user.Content-Location, containing the url of
# +where the file was downloaded from.
#  @end table
#  
#  @node Directory Options
# Index: INSTALL
# ===================================================================
# --- INSTALL	(revision 2052)
# +++ INSTALL	(working copy)
# @@ -98,6 +98,7 @@
#    --disable-largefile     omit support for large files
#    --disable-ipv6          disable IPv6 support
#    --disable-rpath         do not hardcode runtime library paths
# +  --disable-xattr         disable support for extended attributes on files
#  
#  You can inspect decisions made by configure by editing the generated
#  Makefiles and the `src/config.h' include file.  The defaults should
# Index: NEWS
# ===================================================================
# --- NEWS	(revision 2052)
# +++ NEWS	(working copy)
# @@ -7,6 +7,12 @@
#  
#  * Changes in Wget 1.11.
#  
# +** The new function `--set-content-location' makes Wget put an
# +extended attribute called `user.Content-Location' on all downloaded
# +files containing the url of where the file was downloaded file. (This
# +option has no effect if your filesystem does not support extended
# +attributes.)
# +
#  ** The new function `--ignore-case' makes Wget ignore case when
#  matching files, directories, and wildcards.  This affects the -X, -I,
#  -A, and -R options, as well as globbing in FTP URLs.
#