Replaced the SAX parser with DOM + XPath. Added RelaxNG schema validation of the configuration file. Made domain and mount options elements optional. - susmb - mounting of SMB/CIFS shares via FUSE
 (HTM) git clone git://git.codemadness.org/susmb
 (DIR) Log
 (DIR) Files
 (DIR) Refs
 (DIR) README
 (DIR) LICENSE
       ---
 (DIR) commit 3f2aa4880ce666e10ff6bafe46d4041e7e49fe8b
 (DIR) parent d83453ae77a122ee32d410edd113b6915252e9df
 (HTM) Author: geoff <devnull@localhost>
       Date:   Tue,  2 Jan 2007 22:19:03 +0000
       
       Replaced the SAX parser with DOM + XPath.
       Added RelaxNG schema validation of the configuration file.
       Made domain and mount options elements optional.
       
       Diffstat:
         M Makefile                            |      14 ++++++++++----
         M conffile.c                          |     204 +++++++++++++++++--------------
         M conffile.h                          |      41 ++++++++-----------------------
         A config.rng                          |      46 +++++++++++++++++++++++++++++++
         M doc/README                          |       1 +
         D doc/sax_model.mdzip                 |       0 
         D doc/sax_state_machine.png           |       0 
         M options.c                           |       8 ++++----
         M options.h                           |       4 ++--
         D sax.c                               |     720 -------------------------------
         D sax.h                               |      27 ---------------------------
         M usmb.c                              |      88 ++++++++-----------------------
         M usmb.h                              |       2 +-
         M usmb_dir.c                          |       2 +-
         M usmb_dir.h                          |       2 +-
         M usmb_file.c                         |       2 +-
         M usmb_file.h                         |       2 +-
         M utils.c                             |       2 +-
         M utils.h                             |       2 +-
         M version.c                           |       4 ++--
         M version.h                           |       4 ++--
         A xml.c                               |     158 +++++++++++++++++++++++++++++++
         A xml.h                               |      35 +++++++++++++++++++++++++++++++
       
       23 files changed, 410 insertions(+), 958 deletions(-)
       ---
 (DIR) diff --git a/Makefile b/Makefile
       @@ -1,5 +1,5 @@
        # usmb - mount SMB shares via FUSE and Samba
       -# Copyright (C) 2006 Geoff Johnstone
       +# Copyright (C) 2006-2007 Geoff Johnstone
        #
        # 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
       @@ -36,8 +36,8 @@ CFLAGS  += $(shell pkg-config --cflags $(PACKAGES))
        LDLIBS  += $(shell pkg-config --libs-only-l $(PACKAGES))
        LDFLAGS += $(shell pkg-config --libs-only-L $(PACKAGES))
        
       -SOURCES = conffile.c options.c sax.c usmb.c usmb_dir.c usmb_file.c utils.c \
       -          version.c
       +SOURCES = conffile.c options.c usmb.c usmb_dir.c usmb_file.c utils.c \
       +          version.c xml.c
        OBJECTS = $(SOURCES:.c=.o)
        
        PROGRAM = usmb
       @@ -45,6 +45,12 @@ PROGRAM = usmb
        
        all: $(PROGRAM)
        
       +conffile.c: config.rng.h
       +config.rng.h: config.rng
       +        sed -e 's/"/\\"/g' -e 's/\(.*\)/  "\1" \\/' \
       +            -e '1istatic const char *rng_$(^:.rng=) =' $^ > config.rng.h
       +        echo '  "";' >> config.rng.h
       +
        debug: CFLAGS += -ggdb -DDEBUG
        debug: all
        
       @@ -58,7 +64,7 @@ clean:
        
        
        distclean: clean
       -        $(RM) core usmb-*.tar.bz2 usmb-*.tar.gz doc/*.mdzip.bak
       +        $(RM) core usmb-*.tar.bz2 usmb-*.tar.gz doc/*.mdzip.bak config.rng.h
        
        
        install-strip: STRIPFLAGS = -s
 (DIR) diff --git a/conffile.c b/conffile.c
       @@ -1,5 +1,5 @@
        /* usmb - mount SMB shares via FUSE and Samba
       - * Copyright (C) 2006 Geoff Johnstone
       + * Copyright (C) 2006-2007 Geoff Johnstone
         *
         * 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
       @@ -17,17 +17,18 @@
         */
        
        #include <assert.h>
       -#include <glib.h>
        #include <stdio.h>
        #include <stdlib.h>
        #include <string.h>
        #include "conffile.h"
        #include "utils.h"
       +#include "xml.h"
       +#include "config.rng.h"
        
        
        struct conffile {
       -  GHashTable *credentials;
       -  GHashTable *mounts;
       +  xmlDocPtr doc;
       +  xmlXPathContextPtr ctx;
        };
        
        
       @@ -40,17 +41,9 @@ struct credentials * credentials_new (const char *domain,
          if (NULL == creds)
            return NULL;
          
       -  creds->domain = xstrdup (domain);
       -  creds->username = xstrdup (username);
       -  creds->password = xstrdup (password);
       -
       -  if ((NULL == creds->domain) ||
       -      (NULL == creds->username) ||
       -      (NULL == creds->password))
       -  {
       -    credentials_destroy (creds);
       -    creds = NULL;
       -  }
       +  creds->domain = domain;
       +  creds->username = username;
       +  creds->password = password;
        
          return creds;
        }
       @@ -59,11 +52,6 @@ struct credentials * credentials_new (const char *domain,
        void credentials_destroy (struct credentials *creds)
        {
          assert (creds != NULL);
       -
       -  xfree (creds->password);
       -  xfree (creds->username);
       -  xfree (creds->domain);
       -
          free (creds);
        }
        
       @@ -80,21 +68,12 @@ struct mount * mount_new (const char *server, const char *share,
          if (NULL == mount)
            return NULL;
        
       -  mount->server = xstrdup (server);
       -  mount->share = xstrdup (share);
       -  mount->mountpoint = xstrdup (mountpoint);
       -  mount->options = xstrdup (options);
       +  mount->server = server;
       +  mount->share = share;
       +  mount->mountpoint = mountpoint;
       +  mount->options = options;
          mount->credentials = credentials;
        
       -  if ((NULL == mount->server) ||
       -      (NULL == mount->share) ||
       -      (NULL == mount->mountpoint) ||
       -      (NULL == mount->options))
       -  {
       -    mount_destroy (mount);
       -    mount = NULL;
       -  }
       -
          return mount;
        }
        
       @@ -102,35 +81,50 @@ struct mount * mount_new (const char *server, const char *share,
        void mount_destroy (struct mount *mount)
        {
          assert (NULL != mount);
       -
       -  xfree (mount->options);
       -  xfree (mount->mountpoint);
       -  xfree (mount->share);
       -  xfree (mount->server);
       -
          free (mount);
        }
        
        
       -struct conffile * conffile_new (void)
       +struct conffile * conffile_new (const char *filename)
        {
       -  struct conffile *cf = malloc (sizeof (struct conffile));
       -
       -  if (NULL == cf)
       +  xmlDocPtr doc;
       +  xmlXPathContextPtr ctx;
       +  struct conffile *cf;
       +  
       +  doc = xmlParseFile (filename);
       +  if (NULL == doc)
       +  {
       +    fprintf (stderr, "Cannot parse %s\n", filename);
            return NULL;
       +  }
        
       +  if (!xml_validate_relaxng (doc, rng_config))
       +  {
       +    fprintf (stderr, "%s isn't a valid USMB configuration\n", filename);
       +    xmlFreeDoc (doc);
       +    return NULL;
       +  }
        
       -  cf->credentials = g_hash_table_new_full (g_str_hash, g_str_equal, free,
       -                                           (GDestroyNotify)credentials_destroy);
       -  cf->mounts = g_hash_table_new_full (g_str_hash, g_str_equal,
       -                                      free, (GDestroyNotify)mount_destroy);
       +  ctx = xmlXPathNewContext (doc);
       +  if (NULL == ctx)
       +  {
       +    fputs ("Cannot create XPath context\n", stderr);
       +    xmlFreeDoc (doc);
       +    return NULL;
       +  }
       +  
       +  cf = malloc (sizeof (struct conffile));
        
       -  if ((NULL == cf->credentials) || (NULL == cf->mounts))
       +  if (NULL == cf)
          {
       -    conffile_destroy (cf);
       -    cf = NULL;
       +    xmlXPathFreeContext (ctx);
       +    xmlFreeDoc (doc);
       +    return NULL;
          }
        
       +  cf->doc = doc;
       +  cf->ctx = ctx;
       +
          return cf;
        }
        
       @@ -139,69 +133,93 @@ void conffile_destroy (struct conffile *cf)
        {
          assert (NULL != cf);
        
       -  if (NULL != cf->mounts)
       -    g_hash_table_destroy (cf->mounts);
       -
       -  if (NULL != cf->credentials)
       -    g_hash_table_destroy (cf->credentials);
       -
       +  xmlXPathFreeContext (cf->ctx);
       +  xmlFreeDoc (cf->doc);
          free (cf);
        }
        
        
       -bool conffile_add_mount (struct conffile *cf, char *key, struct mount *mount)
       +struct mount * conffile_get_mount (struct conffile *cf, const char *key)
        {
       +  char xpath[2048];
       +  char *creds = NULL;
       +  void *server = NULL, *share = NULL, *mountpoint = NULL, *options = NULL;
       +  void *domain = NULL, *username = NULL, *password = NULL;
       +  bool ok = true;
       +  struct credentials *credentials = NULL;
       +  struct mount *ret = NULL;
       +
          assert (NULL != cf);
          assert (NULL != key);
       -  assert (NULL != mount);
        
       -  DEBUG (fprintf (stderr, "add_mount (%s)\n", key));
       +  if (strchr (key, '\''))
       +    return NULL;
        
       -  if (NULL != g_hash_table_lookup (cf->mounts, key))
       -  {
       -    fprintf (stderr, "Duplicate mount name: %s\n", key);
       -    return false;
       -  }
       +  snprintf (xpath, sizeof (xpath),
       +            "/usmbconfig/mount[@id='%s']/server/text()", key);
       +  xml_xpath_text (cf->ctx, BAD_CAST xpath, (void *)&server) || (ok = false);
        
       -  g_hash_table_insert (cf->mounts, key, mount);
       -  return true;
       -}
       +  snprintf (xpath, sizeof (xpath),
       +            "/usmbconfig/mount[@id='%s']/share/text()", key);
       +  xml_xpath_text (cf->ctx, BAD_CAST xpath, (void *)&share) || (ok = false);
        
       +  snprintf (xpath, sizeof (xpath),
       +            "/usmbconfig/mount[@id='%s']/mountpoint/text()", key);
       +  xml_xpath_text (cf->ctx, BAD_CAST xpath, (void *)&mountpoint) || (ok = false);
        
       -bool conffile_add_credentials (struct conffile *cf, char *key,
       -                               struct credentials *credentials)
       -{
       -  assert (NULL != cf);
       -  assert (NULL != key);
       -  assert (NULL != credentials);
       -
       -  DEBUG (fprintf (stderr, "add_credentials (%s)\n", key));
       +  snprintf (xpath, sizeof (xpath), "/usmbconfig/mount[@id='%s']", key);
       +  xml_xpath_attr_value (cf->ctx, BAD_CAST xpath, BAD_CAST "credentials",
       +                        (xmlChar **)&creds) || (ok = false);
        
       -  if (NULL != g_hash_table_lookup (cf->credentials, key))
       +  if (!ok)
          {
       -    fprintf (stderr, "Duplicate credentials name: %s\n", key);
       -    return false;
       +    xfree (creds);
       +    xfree (mountpoint);
       +    xfree (share);
       +    xfree (server);
       +
       +    return NULL;
          }
        
       -  g_hash_table_insert (cf->credentials, key, credentials);
       -  return true;
       -}
       +  snprintf (xpath, sizeof (xpath),
       +            "/usmbconfig/credentials[@id='%s']/domain/text()", creds);
       +  (void)xml_xpath_text (cf->ctx, BAD_CAST xpath, (void *)&domain);
        
       +  snprintf (xpath, sizeof (xpath),
       +            "/usmbconfig/credentials[@id='%s']/username/text()", creds);
       +  xml_xpath_text (cf->ctx, BAD_CAST xpath, (void *)&username) || (ok = false);
        
       -struct mount * conffile_get_mount (struct conffile *cf, const char *key)
       -{
       -  assert (NULL != cf);
       -  assert (NULL != key);
       +  snprintf (xpath, sizeof (xpath),
       +            "/usmbconfig/credentials[@id='%s']/password/text()", creds);
       +  xml_xpath_text (cf->ctx, BAD_CAST xpath, (void *)&password) || (ok = false);
        
       -  return g_hash_table_lookup (cf->mounts, key);
       -}
       +  if (ok)
       +  {
       +    credentials = credentials_new (domain, username, password);
        
       +    if (NULL != credentials)
       +    {
       +      ret = mount_new (server, share, mountpoint, credentials, options);
       +      ok = (NULL != ret);
       +    }
       +  }
        
       -struct credentials * conffile_get_credentials (struct conffile *cf,
       -                                               const char *key)
       -{
       -  assert (NULL != cf);
       -  assert (NULL != key);
       +  if (!ok)
       +  {
       +    if (NULL != credentials)
       +      credentials_destroy (credentials);
        
       -  return g_hash_table_lookup (cf->credentials, key);
       +    xfree (password);
       +    xfree (domain);
       +    xfree (username);
       +    xfree (creds);
       +    xfree (mountpoint);
       +    xfree (share);
       +    xfree (server);
       +
       +    return NULL;
       +  }
       +
       +  return ret;
        }
       +
 (DIR) diff --git a/conffile.h b/conffile.h
       @@ -1,5 +1,5 @@
        /* usmb - mount SMB shares via FUSE and Samba
       - * Copyright (C) 2006 Geoff Johnstone
       + * Copyright (C) 2006-2007 Geoff Johnstone
         *
         * 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
       @@ -22,49 +22,28 @@
          #include <stdbool.h>
        
          struct credentials {
       -    char *domain;
       -    char *username;
       -    char *password;
       +    const char *domain;
       +    const char *username;
       +    const char *password;
          };
        
        
          struct mount {
       -    char *server;
       -    char *share;
       -    char *mountpoint;
       +    const char *server;
       +    const char *share;
       +    const char *mountpoint;
            const struct credentials *credentials;
       -    char *options;
       +    const char *options;
          };
        
        
          struct conffile;
        
        
       -  struct credentials * credentials_new (const char *domain,
       -                                        const char *username,
       -                                        const char *password);
       -
       -  void credentials_destroy (struct credentials *creds);
       -
       -  struct mount * mount_new (const char *server, const char *share,
       -                            const char *mountpoint,
       -                            const struct credentials *credentials,
       -                            const char *options);
       -
       -  void mount_destroy (struct mount *mount);
       -
       -  struct conffile * conffile_new (void);
       -
       +  struct conffile * conffile_new (const char *filename);
          void conffile_destroy (struct conffile *cf);
        
       -  bool conffile_add_mount (struct conffile *cf, char *key, struct mount *mount);
       -
       -  bool conffile_add_credentials (struct conffile *cf, char *key,
       -                                 struct credentials *credentials);
       -
          struct mount * conffile_get_mount (struct conffile *cf, const char *key);
       -
       -  struct credentials * conffile_get_credentials (struct conffile *cf,
       -                                                 const char *key);
       +  void mount_destroy (struct mount *mount);
        
        #endif
 (DIR) diff --git a/config.rng b/config.rng
       @@ -0,0 +1,46 @@
       +<grammar xmlns="http://relaxng.org/ns/structure/1.0">
       +
       +  <start>
       +    <ref name="usmbconfig" />
       +  </start>
       +
       +
       +  <define name="usmbconfig">
       +    <element name="usmbconfig">
       +      <zeroOrMore>
       +        <choice>
       +          <ref name="credentials" />
       +          <ref name="mount" />
       +        </choice>
       +      </zeroOrMore>
       +    </element>
       +  </define>
       +
       +
       +  <define name="credentials">
       +    <element name="credentials">
       +      <attribute name="id" />
       +      <optional>
       +        <element name="domain"> <text /> </element>
       +      </optional>
       +      <element name="username"> <text /> </element>
       +      <element name="password"> <text /> </element>
       +    </element>
       +  </define>
       +
       +
       +  <define name="mount">
       +    <element name="mount">
       +      <attribute name="id" />
       +      <attribute name="credentials" />
       +      <element name="server"> <text /> </element>
       +      <element name="share"> <text /> </element>
       +      <element name="mountpoint"> <text /> </element>
       +      <optional>
       +        <element name="options"> <text /> </element>
       +      </optional>
       +    </element>
       +  </define>
       +
       +</grammar>
       +
 (DIR) diff --git a/doc/README b/doc/README
       @@ -43,6 +43,7 @@ Installation
        ------------
        
        Sorry, no autoconf yet.
       +You need GNU sed.
        Edit the Makefile with brain engaged.
        Run make.
        Run make install (maybe as root).
 (DIR) diff --git a/doc/sax_model.mdzip b/doc/sax_model.mdzip
       Binary files differ.
 (DIR) diff --git a/doc/sax_state_machine.png b/doc/sax_state_machine.png
       Binary files differ.
 (DIR) diff --git a/options.c b/options.c
       @@ -1,5 +1,5 @@
        /* usmb - mount SMB shares via FUSE and Samba
       - * Copyright (C) 2006 Geoff Johnstone
       + * Copyright (C) 2006-2007 Geoff Johnstone
         *
         * 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
       @@ -133,7 +133,7 @@ bool parse_args (int *argc, char ***argv,
         * mount point
         */
        #define MAXARGS 12
       -void build_fuse_args (char *options, char *mountpoint,
       +void build_fuse_args (const char *options, const char *mountpoint,
                              int *out_argc, char ***out_argv)
        {
          assert (NULL != mountpoint);
       @@ -159,10 +159,10 @@ void build_fuse_args (char *options, char *mountpoint,
          if ((NULL != options) && ('\0' != options[0]))
          {
            argv[argc++] = "-o";
       -    argv[argc++] = options;
       +    argv[argc++] = (char *)options;
          }
        
       -  argv[argc++] = mountpoint;
       +  argv[argc++] = (char *)mountpoint;
          argv[argc] = NULL;          // for good measure...
        
          assert (argc < MAXARGS);
 (DIR) diff --git a/options.h b/options.h
       @@ -1,5 +1,5 @@
        /* usmb - mount SMB shares via FUSE and Samba
       - * Copyright (C) 2006 Geoff Johnstone
       + * Copyright (C) 2006-2007 Geoff Johnstone
         *
         * 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
       @@ -21,7 +21,7 @@
        
          bool parse_args (int *argc, char ***argv,
                           const char **mountid, const char **out_conffile);
       -  void build_fuse_args (char *options, char *mountpoint,
       +  void build_fuse_args (const char *options, const char *mountpoint,
                                int *out_argc, char ***out_argv);
        
        #endif
 (DIR) diff --git a/sax.c b/sax.c
       @@ -1,720 +0,0 @@
       -/* usmb - mount SMB shares via FUSE and Samba
       - * Copyright (C) 2006 Geoff Johnstone
       - *
       - * 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 of the License, 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
       - */
       -
       -#include <assert.h>
       -#include <ctype.h>
       -#include <stdarg.h>
       -#include <stdbool.h>
       -#include <stdio.h>
       -#include <string.h>
       -#include <libxml/xmlreader.h>
       -#include <glib.h>
       -#include "conffile.h"
       -#include "sax.h"
       -#include "utils.h"
       -
       -
       -/* Configuration file format
       - * -------------------------
       - *
       - * usmbconfig section
       - *   Any number of credentials and mount sections
       - *
       - *   credentials section
       - *     domain
       - *     username
       - *     password
       - *
       - *   mount section
       - *     server
       - *     share
       - *     mountpoint
       - *     options
       - *
       - * Example:
       - *   <usmbconfig>
       - *   
       - *     <credentials id="workgroup">
       - *       <domain>WORKGROUP</domain>
       - *       <username>user</username>
       - *       <password>password</password>
       - *     </credentials>
       - *   
       - *     <mount id="home" credentials="workgroup">
       - *       <server>127.0.0.1</server>
       - *       <share>home</share>
       - *       <mountpoint>/tmp/smb</mountpoint>
       - *       <options>readonly</options>
       - *     </mount>
       - *   
       - *   </usmbconfig>
       - */    
       -
       -
       -/* SAX state machine
       - * -----------------
       - *
       - * See doc/sax_state_machine.png or the MagicDraw model doc/sax_model.mdzip.
       - */
       -
       -
       -enum sax_state {
       -  START,
       -  INITIAL,
       -  USMBCFG,
       -  DONE,
       -  FINISH,
       -  CREDS,
       -  MOUNT,
       -  SERVER,
       -  SHARE,
       -  MOUNTPT,
       -  OPTIONS,
       -  DOMAIN,
       -  USER,
       -  PASS,
       -  ERROR
       -};
       -
       -
       -enum element {
       -  ELT_USMBCFG,
       -  ELT_CREDS,
       -  ELT_DOMAIN,
       -  ELT_USER,
       -  ELT_PASS,
       -  ELT_MOUNT,
       -  ELT_SERVER,
       -  ELT_SHARE,
       -  ELT_MOUNTPT,
       -  ELT_OPTIONS,
       -  ELT_UNKNOWN
       -};
       -
       -
       -// passed as the ctx pointer into SAX callbacks
       -struct sax_parser {
       -  enum sax_state state;
       -
       -  union {
       -    struct {
       -      char *id;
       -
       -      bool got_domain;
       -      bool got_username;
       -      bool got_password;
       -
       -      GString *domain;
       -      GString *username;
       -      GString *password;
       -    } credentials;
       -
       -    struct {
       -      char *id;
       -      struct credentials *creds;
       -
       -      bool got_server;
       -      bool got_share;
       -      bool got_mountpoint;
       -      bool got_options;
       -
       -      GString *server;
       -      GString *share;
       -      GString *mountpoint;
       -      GString *options;
       -    } mount;
       -  } strs;
       -
       -  struct conffile *cf;
       -};
       -
       -
       -static enum element get_element (const char *elt)
       -{
       -  const char *elts[] = {
       -    [ ELT_USMBCFG ] = "usmbconfig",
       -      [ ELT_CREDS ] = "credentials",
       -     [ ELT_DOMAIN ] = "domain",
       -       [ ELT_USER ] = "username",
       -       [ ELT_PASS ] = "password",
       -      [ ELT_MOUNT ] = "mount",
       -     [ ELT_SERVER ] = "server",
       -      [ ELT_SHARE ] = "share",
       -    [ ELT_MOUNTPT ] = "mountpoint",
       -    [ ELT_OPTIONS ] = "options"
       -  };
       -
       -  for (size_t i = 0; i < sizeof (elts) / sizeof (elts[0]); ++i)
       -    if (!strcmp (elt, elts[i]))
       -      return i;
       -  
       -  return ELT_UNKNOWN;
       -}
       -
       -
       -static void start_document (void *ctx)
       -{
       -  struct sax_parser *sp = ctx;
       -  assert (sp->state == START);
       -  sp->state = INITIAL;
       -}
       -
       -
       -static void end_document (void *ctx)
       -{
       -  struct sax_parser *sp = ctx;
       -
       -  if (ERROR == sp->state)
       -    return;
       -
       -  if (sp->state != DONE)
       -  {
       -    fputs ("Unexpected end of configuration file\n", stderr);
       -    sp->state = ERROR;
       -  }
       -
       -  sp->state = FINISH;
       -}
       -
       -
       -static void error (void *ctx, const char *msg, ...)
       -{
       -  struct sax_parser *sp = ctx;
       -
       -  if (ERROR == sp->state)
       -    return;
       -
       -  va_list ap;
       -
       -  fputs ("Parse error: ", stderr);
       -  va_start (ap, msg);
       -  vfprintf (stderr, msg ,ap);
       -  va_end (ap);
       -  sp->state = ERROR;
       -}
       -
       -
       -typedef void * (* cf_get_fn) (struct conffile *, const char *);
       -static bool handle_id (char **out, const char *in, cf_get_fn func,
       -                       struct conffile *cf)
       -{
       -  assert (NULL != out);
       -  assert (NULL != in);
       -
       -  if (NULL != *out)
       -  {
       -    fprintf (stderr,
       -             "Multiple ID attributes in <mount> or <credentials>: %s\n", in);
       -    return false;
       -  }
       -
       -  if (NULL != func (cf, in))
       -  {
       -    fprintf (stderr, "Duplicate ID: %s\n", in);
       -    return false;
       -  }
       -
       -  *out = xstrdup (in);
       -
       -  if (NULL == *out)
       -  {
       -    fputs ("Out of memory\n", stderr);
       -    return false;
       -  }
       -
       -  return true;
       -}
       -
       -
       -static void start_mount (struct sax_parser *sp, const xmlChar **attrs)
       -{
       -  sp->strs.mount.id = NULL;
       -  sp->strs.mount.creds = NULL;
       -
       -  // must have id and credentials attributes
       -  for (int i = 0; NULL != attrs[i]; i += 2)
       -  {
       -    assert (NULL != attrs[i+1]);
       -
       -    if (!strcmp (attrs[i], "id"))
       -    {
       -      if (!handle_id (&sp->strs.mount.id, (const char *)attrs[i+1],
       -                      (cf_get_fn)conffile_get_mount, sp->cf))
       -      {
       -        sp->state = ERROR;
       -        return;
       -      }
       -    }
       -
       -    else if (!strcmp (attrs[i], "credentials"))
       -    {
       -      if (NULL != sp->strs.mount.creds)
       -      {
       -        fputs ("Duplicate credentials attribute in <mount>\n", stderr);
       -        sp->state = ERROR;
       -        return;
       -      }
       -
       -      sp->strs.mount.creds =
       -        conffile_get_credentials (sp->cf, (const char *)attrs[i+1]);
       -
       -      if (NULL == sp->strs.mount.creds)
       -      {
       -        fprintf (stderr, "Credentials %s not found for <mount>\n", attrs[i+1]);
       -        sp->state = ERROR;
       -        return;
       -      }
       -    }
       -
       -    else
       -    {
       -      fprintf (stderr, "Unrecognised <mount> attribute %s\n", attrs[i]);
       -      sp->state = ERROR;
       -      return;
       -    }
       -  }
       -
       -  if ((NULL == sp->strs.mount.id) ||
       -      (NULL == sp->strs.mount.creds))
       -  {
       -    fputs ("<mount> must have id and credentials attributes\n", stderr);
       -    sp->state = ERROR;
       -    return;
       -  }
       -
       -  sp->strs.mount.server     = g_string_new (NULL);
       -  sp->strs.mount.share      = g_string_new (NULL);
       -  sp->strs.mount.mountpoint = g_string_new (NULL);
       -  sp->strs.mount.options    = g_string_new (NULL);
       -
       -  sp->strs.mount.got_server     = false;
       -  sp->strs.mount.got_share      = false;
       -  sp->strs.mount.got_mountpoint = false;
       -  sp->strs.mount.got_options    = false;
       -
       -  sp->state = MOUNT;
       -}
       -
       -
       -static void start_creds (struct sax_parser *sp, const xmlChar **attrs)
       -{
       -  assert (NULL == sp->strs.credentials.domain);
       -  assert (NULL == sp->strs.credentials.username);
       -  assert (NULL == sp->strs.credentials.password);
       -
       -  sp->strs.credentials.id = NULL;
       -
       -  // must have an id attribute
       -  for (int i = 0; NULL != attrs[i]; i += 2)
       -  {
       -    assert (NULL != attrs[i+1]);
       -
       -    if (!strcmp (attrs[i], "id"))
       -    {
       -      if (!handle_id (&sp->strs.credentials.id, (const char *)attrs[i+1],
       -                      (cf_get_fn)conffile_get_credentials, sp->cf))
       -      {
       -        sp->state = ERROR;
       -        return;
       -      }
       -    }
       -
       -    else
       -    {
       -      fprintf (stderr, "Unrecognised <credentials> attribute %s\n", attrs[i]);
       -      sp->state = ERROR;
       -      return;
       -    }
       -  }
       -
       -  if (NULL == sp->strs.credentials.id)
       -  {
       -    fputs ("<credentials> must have an id attribute\n", stderr);
       -    sp->state = ERROR;
       -    return;
       -  }
       -
       -  sp->strs.credentials.domain   = g_string_new (NULL);
       -  sp->strs.credentials.username = g_string_new (NULL);
       -  sp->strs.credentials.password = g_string_new (NULL);
       -
       -  sp->strs.credentials.got_domain   = false;
       -  sp->strs.credentials.got_username = false;
       -  sp->strs.credentials.got_password = false;
       -
       -  sp->state = CREDS;
       -}
       -
       -
       -static void start_char_state (struct sax_parser *sp,
       -                              GString *target,
       -                              bool *got,
       -                              const char *name,
       -                              const xmlChar **attrs)
       -{
       -  assert (NULL != target);
       -
       -  if (ERROR == sp->state)
       -    return;
       -
       -  if ((NULL != attrs) && (NULL != attrs[0]))
       -  {
       -    fprintf (stderr, "Spurious attributes on <%s>\n", name);
       -    sp->state = ERROR;
       -    return;
       -  }
       -
       -  if (false != *got)
       -  {
       -    fprintf (stderr, "Duplicate <%s>\n", name);
       -    sp->state = ERROR;
       -    return;
       -  }
       -
       -  *got = true;
       -}
       -
       -
       -static void start_server (struct sax_parser *sp, const xmlChar **attrs)
       -{
       -  start_char_state (sp, sp->strs.mount.server, &sp->strs.mount.got_server,
       -                    "server", attrs);
       -}
       -
       -
       -static void start_share (struct sax_parser *sp, const xmlChar **attrs)
       -{
       -  start_char_state (sp, sp->strs.mount.share, &sp->strs.mount.got_share,
       -                    "share", attrs);
       -}
       -
       -
       -static void start_mtpt (struct sax_parser *sp, const xmlChar **attrs)
       -{
       -  start_char_state (sp, sp->strs.mount.mountpoint,
       -                    &sp->strs.mount.got_mountpoint, "mountpoint", attrs);
       -}
       -
       -
       -static void start_options (struct sax_parser *sp, const xmlChar **attrs)
       -{
       -  start_char_state (sp, sp->strs.mount.options, &sp->strs.mount.got_options,
       -                    "options", attrs);
       -}
       -
       -
       -static void start_domain (struct sax_parser *sp, const xmlChar **attrs)
       -{
       -  start_char_state (sp, sp->strs.credentials.domain,
       -                    &sp->strs.credentials.got_domain, "domain", attrs);
       -}
       -
       -
       -static void start_username (struct sax_parser *sp, const xmlChar **attrs)
       -{
       -  start_char_state (sp, sp->strs.credentials.username,
       -                    &sp->strs.credentials.got_username, "username", attrs);
       -}
       -
       -
       -static void start_password (struct sax_parser *sp, const xmlChar **attrs)
       -{
       -  start_char_state (sp, sp->strs.credentials.password,
       -                    &sp->strs.credentials.got_password, "password", attrs);
       -}
       -
       -
       -static void start_element (void *ctx,
       -                           const xmlChar *name, const xmlChar **attrs)
       -{
       -  struct sax_parser *sp = ctx;
       -
       -  if (ERROR == sp->state)
       -    return;
       -
       -  /* all valid transitions on <element> */
       -  const struct {
       -    enum sax_state to, from;
       -    enum element on;
       -    void (*fn) (struct sax_parser *, const xmlChar **attrs);
       -  } transitions[] = {
       -    { .from = INITIAL, .on = ELT_USMBCFG, .to = USMBCFG, .fn = NULL           },
       -    { .from = USMBCFG, .on = ELT_MOUNT,   .to = MOUNT,   .fn = start_mount    },
       -    { .from = USMBCFG, .on = ELT_CREDS,   .to = CREDS,   .fn = start_creds    },
       -    { .from = MOUNT,   .on = ELT_SERVER,  .to = SERVER,  .fn = start_server   },
       -    { .from = MOUNT,   .on = ELT_SHARE,   .to = SHARE,   .fn = start_share    },
       -    { .from = MOUNT,   .on = ELT_MOUNTPT, .to = MOUNTPT, .fn = start_mtpt     },
       -    { .from = MOUNT,   .on = ELT_OPTIONS, .to = OPTIONS, .fn = start_options  },
       -    { .from = CREDS,   .on = ELT_DOMAIN,  .to = DOMAIN,  .fn = start_domain   },
       -    { .from = CREDS,   .on = ELT_USER,    .to = USER,    .fn = start_username },
       -    { .from = CREDS,   .on = ELT_PASS,    .to = PASS,    .fn = start_password }
       -  };
       -
       -
       -  enum element elt = get_element ((const char *)name);
       -
       -  for (size_t i = 0; i < sizeof (transitions) / sizeof (transitions[0]); ++i)
       -  {
       -    if ((transitions[i].from == sp->state) &&
       -        (transitions[i].on == elt))
       -    {
       -      if (NULL != transitions[i].fn)
       -        transitions[i].fn (sp, attrs);
       -
       -      if (ERROR != sp->state)
       -        sp->state = transitions[i].to;
       -      return;
       -    }
       -  }
       -
       -  fprintf (stderr, "Unexpected <%s>\n", name);
       -  sp->state = ERROR;
       -}
       -
       -
       -static void end_mount (struct sax_parser *sp)
       -{
       -  // must have id, creds, server, share and mountpoint; options are optional
       -  assert (NULL != sp->strs.mount.id);
       -  assert (NULL != sp->strs.mount.creds);
       -
       -  if (!sp->strs.mount.got_server || (0 == sp->strs.mount.server->len))
       -  {
       -    fprintf (stderr, "Mount %s: no server given\n", sp->strs.mount.id);
       -    sp->state = ERROR;
       -  }
       -
       -  else if (!sp->strs.mount.got_share || (0 == sp->strs.mount.share->len))
       -  {
       -    fprintf (stderr, "Mount %s: no share given\n", sp->strs.mount.id);
       -    sp->state = ERROR;
       -  }
       -
       -  else if (!sp->strs.mount.got_mountpoint ||
       -           (0 == sp->strs.mount.mountpoint->len))
       -  {
       -    fprintf (stderr, "Mount %s: no mount point given\n", sp->strs.mount.id);
       -    sp->state = ERROR;
       -  }
       -
       -  else
       -  {
       -    struct mount *mount =
       -      mount_new (sp->strs.mount.server->str,
       -                 sp->strs.mount.share->str,
       -                 sp->strs.mount.mountpoint->str,
       -                 sp->strs.mount.creds,
       -                 sp->strs.mount.options->str);
       -
       -    if ((NULL == mount) ||
       -        !conffile_add_mount (sp->cf, sp->strs.mount.id, mount))
       -      sp->state = ERROR;
       -  }
       -
       -  g_string_free (sp->strs.mount.server, TRUE);
       -  g_string_free (sp->strs.mount.share, TRUE);
       -  g_string_free (sp->strs.mount.mountpoint, TRUE);
       -  g_string_free (sp->strs.mount.options, TRUE);
       -
       -  // we need the mount ID (for the hashtable key) if parsing succeeded
       -  if (ERROR == sp->state)
       -    xfree (sp->strs.mount.id);
       -}
       -
       -
       -static void end_creds (struct sax_parser *sp)
       -{
       -  // must have username; domain and password are optional
       -  assert (NULL != sp->strs.credentials.id);
       -
       -  if (!sp->strs.credentials.got_username ||
       -           (0 == sp->strs.credentials.username->len))
       -  {
       -    fprintf (stderr, "Credentials %s: no username given\n",
       -    sp->strs.credentials.id);
       -    sp->state = ERROR;
       -  }
       -
       -  else
       -  {
       -    struct credentials *creds =
       -      credentials_new (sp->strs.credentials.domain->str,
       -                       sp->strs.credentials.username->str,
       -                       sp->strs.credentials.password->str);
       -
       -    if ((NULL == creds) ||
       -        !conffile_add_credentials (sp->cf, sp->strs.credentials.id, creds))
       -      sp->state = ERROR;
       -  }
       -
       -  g_string_free (sp->strs.credentials.domain, TRUE);
       -  g_string_free (sp->strs.credentials.username, TRUE);
       -  g_string_free (sp->strs.credentials.password, TRUE);
       -
       -  sp->strs.credentials.domain = NULL;
       -  sp->strs.credentials.username = NULL;
       -  sp->strs.credentials.password = NULL;
       -
       -  if (ERROR == sp->state)
       -    xfree (sp->strs.credentials.id);
       -}
       -
       -
       -static void end_element (void *ctx, const xmlChar *name)
       -{
       -  struct sax_parser *sp = ctx;
       -
       -  if (ERROR == sp->state)
       -    return;
       -
       -  /* all valid transitions on </element> */
       -  const struct {
       -    enum sax_state to, from;
       -    enum element on;
       -    void (*fn) (struct sax_parser *);
       -  } transitions[] = {
       -    { .from = USMBCFG, .on = ELT_USMBCFG, .to = DONE,    .fn = NULL      },
       -    { .from = MOUNT,   .on = ELT_MOUNT,   .to = USMBCFG, .fn = end_mount },
       -    { .from = CREDS,   .on = ELT_CREDS,   .to = USMBCFG, .fn = end_creds },
       -    { .from = SERVER,  .on = ELT_SERVER,  .to = MOUNT,   .fn = NULL      },
       -    { .from = SHARE,   .on = ELT_SHARE,   .to = MOUNT,   .fn = NULL      },
       -    { .from = MOUNTPT, .on = ELT_MOUNTPT, .to = MOUNT,   .fn = NULL      },
       -    { .from = OPTIONS, .on = ELT_OPTIONS, .to = MOUNT,   .fn = NULL      },
       -    { .from = DOMAIN,  .on = ELT_DOMAIN,  .to = CREDS,   .fn = NULL      },
       -    { .from = USER,    .on = ELT_USER,    .to = CREDS,   .fn = NULL      },
       -    { .from = PASS,    .on = ELT_PASS,    .to = CREDS,   .fn = NULL      }
       -  };
       -
       -
       -  enum element elt = get_element ((const char *)name);
       -
       -  for (size_t i = 0; i < sizeof (transitions) / sizeof (transitions[0]); ++i)
       -  {
       -    if ((transitions[i].from == sp->state) &&
       -        (transitions[i].on == elt))
       -    {
       -      if (NULL != transitions[i].fn)
       -        transitions[i].fn (sp);
       -
       -      if (ERROR != sp->state)
       -        sp->state = transitions[i].to;
       -      return;
       -    }
       -  }
       -
       -  fprintf (stderr, "Unexpected </%s>\n", name);
       -  sp->state = ERROR;
       -}
       -
       -
       -// strips leading and trailing whitespace; returns true iff characters remain
       -static bool strip_whitespace (const char **str, int *len)
       -{
       -  assert (NULL != str);
       -  assert (NULL != len);
       -
       -  /* leading whitespace */
       -  while ((*len > 0) && isspace (**str))
       -  {
       -    ++(*str);
       -    --(*len);
       -  }
       -
       -  /* trailing whitespace */
       -  while ((*len > 0) && (isspace ((*str)[*len - 1])))
       -    --(*len);
       -  
       -  return (0 != *len);
       -}
       -
       -
       -static inline void append_chars (GString *target, const xmlChar *str, int len)
       -{
       -  assert (NULL != target);
       -  assert (NULL != str);
       -
       -  g_string_append_len (target, (const char *)str, len);
       -}
       -
       -
       -static void chars (void *ctx, const xmlChar *str, int len)
       -{
       -  struct sax_parser *sp = ctx;
       -
       -  if (ERROR == sp->state)
       -    return;
       -
       -  // all states admit whitespace characters
       -  if (!strip_whitespace ((const char **)&str, &len))
       -    return;
       -
       -  // these states admit non-whitespace characters
       -  switch (sp->state)
       -  {
       -    case SERVER:  append_chars (sp->strs.mount.server,         str, len); break;
       -    case SHARE:   append_chars (sp->strs.mount.share,          str, len); break;
       -    case MOUNTPT: append_chars (sp->strs.mount.mountpoint,     str, len); break;
       -    case OPTIONS: append_chars (sp->strs.mount.options,        str, len); break;
       -    case DOMAIN:  append_chars (sp->strs.credentials.domain,   str, len); break;
       -    case USER:    append_chars (sp->strs.credentials.username, str, len); break;
       -    case PASS:    append_chars (sp->strs.credentials.password, str, len); break;
       -
       -    default:
       -      fputs ("Unexpected characters: ", stderr);
       -      while (len--)
       -        fputc (*str++, stderr);
       -      fputc ('\n', stderr);
       -      sp->state = ERROR;
       -      break;
       -  }
       -}
       -
       -
       -struct conffile * parse_xml_conf (const char *file)
       -{
       -  LIBXML_TEST_VERSION;
       -
       -  struct _xmlSAXHandler sax = {
       -    .startDocument = start_document,
       -    .endDocument = end_document,
       -    .startElement = start_element,
       -    .endElement = end_element,
       -    .error = error,
       -    .characters = chars,
       -  };
       -
       -
       -  struct sax_parser user_data = {
       -    .state = START
       -  };
       -
       -  user_data.cf = conffile_new();
       -
       -  if (NULL != user_data.cf)
       -  {
       -    if ((0 != xmlSAXUserParseFile (&sax, &user_data, file)) ||
       -        (user_data.state != FINISH))
       -    {
       -      fputs ("Parse error\n", stderr);
       -      conffile_destroy (user_data.cf);
       -      user_data.cf = NULL;
       -    }
       -  }
       -
       -  return user_data.cf;
       -}
 (DIR) diff --git a/sax.h b/sax.h
       @@ -1,27 +0,0 @@
       -/* usmb - mount SMB shares via FUSE and Samba
       - * Copyright (C) 2006 Geoff Johnstone
       - *
       - * 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 of the License, 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
       - */
       -
       -#ifndef SAX_H
       -  #define SAX_H
       -
       -  #include "conffile.h"
       -
       -  struct conffile * parse_xml_conf (const char *file);
       -
       -#endif
       -
 (DIR) diff --git a/usmb.c b/usmb.c
       @@ -1,5 +1,5 @@
        /* usmb - mount SMB shares via FUSE and Samba
       - * Copyright (C) 2006 Geoff Johnstone
       + * Copyright (C) 2006-2007 Geoff Johnstone
         *
         * 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
       @@ -32,7 +32,6 @@
        #include <string.h>
        #include "conffile.h"
        #include "options.h"
       -#include "sax.h"
        #include "usmb.h"
        #include "usmb_dir.h"
        #include "usmb_file.h"
       @@ -41,7 +40,7 @@
        
        
        SMBCCTX *ctx;
       -static const char *share = NULL;
       +static char *share = NULL;
        
        
        char * make_url (const char *path)
       @@ -62,9 +61,7 @@ static inline void do_strncpy (char *to, const char *from, int tolen)
        }
        
        
       -static char *domain = NULL;
       -static char *username = NULL;
       -static char *password = NULL;
       +static struct mount *mount;
        
        static void auth_fn (const char *srv, const char *shr, char *wg, int wglen,
                             char *un, int unlen, char *pw, int pwlen)
       @@ -73,13 +70,11 @@ static void auth_fn (const char *srv, const char *shr, char *wg, int wglen,
          (void)shr;
          DEBUG (fprintf (stderr, "Authenticating for \\\\%s\\%s\n", srv, shr));
        
       -  assert (NULL != domain);
       -  assert (NULL != username);
       -  assert (NULL != password);
       +  if (NULL != mount->credentials->domain)
       +    do_strncpy (wg, mount->credentials->domain, wglen);
        
       -  do_strncpy (wg, domain, wglen);
       -  do_strncpy (un, username, unlen);
       -  do_strncpy (pw, password, pwlen);
       +  do_strncpy (un, mount->credentials->username, unlen);
       +  do_strncpy (pw, mount->credentials->password, pwlen);
        }
        
        
       @@ -205,45 +200,22 @@ static bool check_conf_perms (const char *conffile)
        }
        
        
       -static bool fix_up_conf_details (struct mount *mount)
       +static bool create_share_name (struct mount *mount)
        {
          assert (NULL != mount->credentials);
        
          size_t len = strlen ("smb:///") +
                       strlen (mount->server) +
                       strlen (mount->share) + 1;
       -  char *str;
       -  if (NULL == (str = malloc (len)))
       -  {
       -    perror ("Cannot allocate share name");
       -    return false;
       -  }
       -
       -  strcpy (str, "smb://");
       -  strcat (str, mount->server);
       -  strcat (str, "/");
       -  strcat (str, mount->share);
        
       -  domain = xstrdup (mount->credentials->domain);
       -  username = xstrdup (mount->credentials->username);
       -  password = xstrdup (mount->credentials->password);
       -
       -  if ((NULL == domain) ||
       -      (NULL == username) ||
       -      (NULL == password))
       +  if (NULL == (share = malloc (len)))
          {
       -    fputs ("Out of memory\n", stderr);
       -    xfree (password);
       -    xfree (username);
       -    xfree (domain);
       -    free (str);
       +    perror ("Cannot allocate share name");
            return false;
          }
        
       -  share = str;
       -
       +  snprintf (share, len, "smb://%s/%s", mount->server, mount->share);
          DEBUG (fprintf (stderr, "Share URL: %s\n", share));
       -  DEBUG (fprintf (stderr, "Username: %s\\%s\n", domain, username));
          return true;
        }
        
       @@ -265,12 +237,11 @@ int main (int argc, char **argv)
          if (!check_conf_perms (conffile))
            return EXIT_FAILURE;
        
       -  struct conffile *cf = parse_xml_conf (conffile);
       +  struct conffile *cf = conffile_new (conffile);
          if (NULL == cf)
            return EXIT_FAILURE;
        
          struct mount *mount = conffile_get_mount (cf, mountid);
       -
          if (NULL == mount)
          {
            fprintf (stderr, "Mount %s not defined in configuration file %s\n",
       @@ -279,42 +250,27 @@ int main (int argc, char **argv)
            return EXIT_FAILURE;
          }
        
       -  char *mountpoint = xstrdup (mount->mountpoint);
       -  char *options = xstrdup (mount->options);
       -
       -  if ((NULL == mountpoint) ||
       -      (mount->options && (NULL == options)))
       +  if (!create_share_name (mount) ||
       +      !create_smb_context ((char *)mount->credentials->domain,
       +                           (char *)mount->credentials->username, &ctx))
          {
       -    perror ("Cannot allocate mountpoint");
       -    return EXIT_FAILURE;
       -  }
       -
       -  {
       -    bool ret = fix_up_conf_details (mount);
       +    mount_destroy (mount);
            conffile_destroy (cf);
       -
       -    if (false == ret)
       -      return EXIT_FAILURE;
       -  }
       -
       -  if (!create_smb_context (domain, username, &ctx))
            return EXIT_FAILURE;
       +  }
        
       +  DEBUG (fprintf (stderr, "Username: %s\\%s\n",
       +                  mount->credentials->domain, mount->credentials->username));
          show_about (stdout);
        
          int fuse_argc;
          char **fuse_argv;
       -  build_fuse_args (options, mountpoint, &fuse_argc, &fuse_argv);
       +  build_fuse_args (mount->options, mount->mountpoint, &fuse_argc, &fuse_argv);
          int ret = fuse_main (fuse_argc, fuse_argv, &fuse_ops);
        
          smbc_free_context (ctx, 1);
       -
       -  xfree (mountpoint);
       -  xfree (options);
       -  xfree (domain);
       -  xfree (username);
       -  xfree (password);
       -  xfree (share);
       +  mount_destroy (mount);
       +  conffile_destroy (cf);
        
          return ret;
        }
 (DIR) diff --git a/usmb.h b/usmb.h
       @@ -1,5 +1,5 @@
        /* usmb - mount SMB shares via FUSE and Samba
       - * Copyright (C) 2006 Geoff Johnstone
       + * Copyright (C) 2006-2007 Geoff Johnstone
         *
         * 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
 (DIR) diff --git a/usmb_dir.c b/usmb_dir.c
       @@ -1,5 +1,5 @@
        /* usmb - mount SMB shares via FUSE and Samba
       - * Copyright (C) 2006 Geoff Johnstone
       + * Copyright (C) 2006-2007 Geoff Johnstone
         *
         * 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
 (DIR) diff --git a/usmb_dir.h b/usmb_dir.h
       @@ -1,5 +1,5 @@
        /* usmb - mount SMB shares via FUSE and Samba
       - * Copyright (C) 2006 Geoff Johnstone
       + * Copyright (C) 2006-2007 Geoff Johnstone
         *
         * 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
 (DIR) diff --git a/usmb_file.c b/usmb_file.c
       @@ -1,5 +1,5 @@
        /* usmb - mount SMB shares via FUSE and Samba
       - * Copyright (C) 2006 Geoff Johnstone
       + * Copyright (C) 2006-2007 Geoff Johnstone
         *
         * 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
 (DIR) diff --git a/usmb_file.h b/usmb_file.h
       @@ -1,5 +1,5 @@
        /* usmb - mount SMB shares via FUSE and Samba
       - * Copyright (C) 2006 Geoff Johnstone
       + * Copyright (C) 2006-2007 Geoff Johnstone
         *
         * 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
 (DIR) diff --git a/utils.c b/utils.c
       @@ -1,5 +1,5 @@
        /* usmb - mount SMB shares via FUSE and Samba
       - * Copyright (C) 2006 Geoff Johnstone
       + * Copyright (C) 2006-2007 Geoff Johnstone
         *
         * 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
 (DIR) diff --git a/utils.h b/utils.h
       @@ -1,5 +1,5 @@
        /* usmb - mount SMB shares via FUSE and Samba
       - * Copyright (C) 2006 Geoff Johnstone
       + * Copyright (C) 2006-2007 Geoff Johnstone
         *
         * 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
 (DIR) diff --git a/version.c b/version.c
       @@ -1,5 +1,5 @@
        /* usmb - mount SMB shares via FUSE and Samba
       - * Copyright (C) 2006 Geoff Johnstone
       + * Copyright (C) 2006-2007 Geoff Johnstone
         *
         * 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
       @@ -35,7 +35,7 @@ void show_about (FILE *fp)
        {
          fputs ("usmb - mount SMB shares via FUSE and Samba\n"
                 "\n"
       -         "Copyright (C) 2006 Geoff Johnstone.\n"
       +         "Copyright (C) 2006-2007 Geoff Johnstone.\n"
                 "Licensed under the GNU General Public License.\n"
                 "usmb comes with ABSOLUTELY NO WARRANTY; for details please see\n"
                 "http://www.gnu.org/licenses/gpl.txt\n", fp);
 (DIR) diff --git a/version.h b/version.h
       @@ -1,5 +1,5 @@
        /* usmb - mount SMB shares via FUSE and Samba
       - * Copyright (C) 2006 Geoff Johnstone
       + * Copyright (C) 2006-2007 Geoff Johnstone
         *
         * 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
       @@ -21,7 +21,7 @@
        
          #include <stdio.h>
        
       -  #define USMB_VERSION 0x20060708
       +  #define USMB_VERSION 0x20070102
        
          // a - alpha, b - beta, p - pre-release, s - stable
          #define USMB_VERSION_STATUS 'a'
 (DIR) diff --git a/xml.c b/xml.c
       @@ -0,0 +1,158 @@
       +#include <libxml/xmlreader.h>
       +#include <libxml/xpath.h>
       +#include <libxml/xpathInternals.h>
       +#include <assert.h>
       +#include <stdbool.h>
       +#include <string.h>
       +#include "xml.h"
       +#include "utils.h"
       +
       +
       +bool xml_validate_relaxng (xmlDocPtr doc, const char *schema)
       +{
       +  xmlRelaxNGParserCtxtPtr rngpcptr = NULL;
       +  xmlRelaxNGPtr rngptr = NULL;
       +  xmlRelaxNGValidCtxtPtr rngvptr = NULL;
       +  bool ret = false;
       +
       +  assert (NULL != doc);
       +
       +  if ((rngpcptr = xmlRelaxNGNewMemParserCtxt (schema, strlen (schema))) &&
       +      ((rngptr = xmlRelaxNGParse (rngpcptr))) &&
       +      ((rngvptr = xmlRelaxNGNewValidCtxt (rngptr))))
       +  {
       +    ret = (0 == xmlRelaxNGValidateDoc (rngvptr, doc));
       +  }
       +
       +  if (NULL != rngvptr)
       +    xmlRelaxNGFreeValidCtxt (rngvptr);
       +
       +  if (NULL != rngptr)
       +    xmlRelaxNGFree (rngptr);
       +
       +  if (NULL != rngpcptr)
       +    xmlRelaxNGFreeParserCtxt (rngpcptr);
       +
       +  return ret;
       +}
       +
       +
       +bool xml_xpath_attr_value (xmlXPathContextPtr ctx,
       +                           xmlChar *xpath,
       +                           const xmlChar *attribute,
       +                           xmlChar **out)
       +{
       +  xmlXPathObjectPtr obj;
       +  xmlChar *tmp;
       +
       +  assert (NULL != ctx);
       +  assert (NULL != xpath);
       +  assert (NULL != out);
       +
       +  *out = NULL;
       +
       +  obj = xmlXPathEval (xpath, ctx);
       +  if (NULL == obj)
       +  {
       +    DEBUG (fputs ("XPath evaluation error\n", stderr));
       +    return false;
       +  }
       +
       +  do {
       +    if (XPATH_NODESET != obj->type)
       +    {
       +      DEBUG (fputs ("XPath evaluation didn't return a nodeset\n", stderr));
       +      break;
       +    }
       +
       +    if (NULL == obj->nodesetval)
       +    {
       +      DEBUG (fputs ("nodesetval is NULL\n", stderr));
       +      break;
       +    }
       +
       +    if (1 != obj->nodesetval->nodeNr)
       +    {
       +      DEBUG (fprintf (stderr, "Nodeset has %d elements\n",
       +                          obj->nodesetval->nodeNr));
       +      break;
       +    }
       +
       +    tmp = xmlGetProp (obj->nodesetval->nodeTab[0], attribute);
       +    if (NULL == tmp)
       +      break;
       +
       +    *out = (xmlChar *)xstrdup ((char *)tmp);
       +    if (NULL == *out)
       +      break;
       +
       +    xmlXPathFreeObject (obj);
       +    return true;
       +    /*NOTREACHED*/
       +  } while (false);
       +
       +  *out = NULL;
       +  xmlXPathFreeObject (obj);
       +  return false;
       +}
       +
       +
       +bool xml_xpath_text (xmlXPathContextPtr ctx, xmlChar *xpath, xmlChar **out)
       +{
       +  xmlXPathObjectPtr obj;
       +
       +  assert (NULL != ctx);
       +  assert (NULL != xpath);
       +  assert (NULL != out);
       +
       +  *out = NULL;
       +
       +  DEBUG (fprintf (stderr, "xml_xpath_text (%s)\n", xpath));
       +
       +  obj = xmlXPathEval (xpath, ctx);
       +  if (NULL == obj)
       +  {
       +    DEBUG (fputs ("XPath evaluation error\n", stderr));
       +    return false;
       +  }
       +
       +  do {
       +    if (XPATH_NODESET != obj->type)
       +    {
       +      DEBUG (fputs ("XPath evaluation didn't return a nodeset\n", stderr));
       +      break;
       +    }
       +
       +    if (NULL == obj->nodesetval)
       +    {
       +      DEBUG (fputs ("nodesetval is NULL\n", stderr));
       +      break;
       +    }
       +
       +    if (1 != obj->nodesetval->nodeNr)
       +    {
       +      DEBUG (fprintf (stderr, "Nodeset has %d elements\n",
       +                          obj->nodesetval->nodeNr));
       +      break;
       +    }
       +
       +    if (NULL == obj->nodesetval->nodeTab[0]->content)
       +    {
       +      DEBUG (fputs ("Node has no text\n", stderr));
       +      break;
       +    }
       +
       +    *out = (xmlChar *)xstrdup ((char *)obj->nodesetval->nodeTab[0]->content);
       +    if (NULL == *out)
       +      break;
       +
       +    xmlXPathFreeObject (obj);
       +    return true;
       +    /*NOTREACHED*/
       +  } while (false);
       +
       +  *out = NULL;
       +  xmlXPathFreeObject (obj);
       +  return false;
       +}
       +
 (DIR) diff --git a/xml.h b/xml.h
       @@ -0,0 +1,35 @@
       +/* usmb - mount SMB shares via FUSE and Samba
       + * Copyright (C) 2006-2007 Geoff Johnstone
       + *
       + * 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 of the License, 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
       + */
       +
       +#ifndef XML_H
       +  #define XML_H
       +
       +  #include <libxml/xmlreader.h>
       +  #include <libxml/xpath.h>
       +  #include <libxml/xpathInternals.h>
       +  #include <stdbool.h>
       +
       +
       +  bool xml_validate_relaxng (xmlDocPtr doc, const char *schema);
       +  bool xml_xpath_attr_value (xmlXPathContextPtr ctx,
       +                             xmlChar *xpath,
       +                             const xmlChar *attribute,
       +                             xmlChar **out);
       +  bool xml_xpath_text (xmlXPathContextPtr ctx, xmlChar *xpath, xmlChar **out);
       +
       +#endif