aft: Store resolved paths when adding files.
authorAndre Noll <maan@tuebingen.mpg.de>
Wed, 24 Dec 2014 03:07:48 +0000 (03:07 +0000)
committerAndre Noll <maan@tuebingen.mpg.de>
Mon, 30 Mar 2015 21:40:58 +0000 (21:40 +0000)
Currently the add command performs some sanity checks on the given
paths, but stores them unmodified in the audio file table if they
pass the checks. This commit removes the checks in favor of a call to
realpath(3) to get the canonicalized absolute pathname to be stored
in the audio file table.

The new code relies on POSIX.1-2008 semantics. That is, it calls
realpath() with second argument NULL to let the function allocate a
suitably sized buffer. This should not be a problem, since the old
POSIX.1-2001 version is broken by design, and all moderately recent
systems support the new semantics.

This change breaks t0004 which expects the ls -p command to print
the same paths that were used earlier to add audio files, which is
no longer true. We fix the test by simply running ls without the
-p option.

aft.c
t/t0004-server.sh

diff --git a/aft.c b/aft.c
index 59be56e..fb0d4fd 100644 (file)
--- a/aft.c
+++ b/aft.c
@@ -293,60 +293,36 @@ static struct osl_table_description audio_file_table_desc = {
        .column_descriptions = aft_cols
 };
 
-/* We don't want dot or dot-dot anywhere. */
-static int verify_dotfile(const char *rest)
-{
-       /*
-        * The first character was '.', but that has already been discarded, we
-        * now test the rest.
-        */
-       switch (*rest) {
-       case '\0': case '/': /* /foo/. and /foo/./bar are not ok */
-               return -1;
-       case '.': /* path start with /foo/.. */
-               if (rest[1] == '\0' || rest[1] == '/')
-                       return -1; /* /foo/.. or /foo/../bar are not ok */
-               /* /foo/..bar is ok */
-       }
-       return 1;
-}
-
 /*
- * We fundamentally don't like some paths: We don't want double slashes or
- * slashes at the end that can make pathnames ambiguous.
+ * Produce a canonicalized absolute pathname.
+ *
+ * Returns one if the resolved path a directory, zero if it is a regular file,
+ * negative on errors.
  */
 static int verify_path(const char *orig_path, char **resolved_path)
 {
-       char c;
-       size_t len;
-       char *path;
+       int ret;
+       char *path = NULL;
+       struct stat statbuf;
 
        if (*orig_path != '/') /* we only accept absolute paths */
-               return -E_BAD_PATH;
-       len = strlen(orig_path);
-       *resolved_path = para_strdup(orig_path);
-       path = *resolved_path;
-       while (len > 1 && path[--len] == '/')
-               path[len] = '\0'; /* remove slash at the end */
-       c = *path++;
-       while (c) {
-               if (c == '/') {
-                       c = *path++;
-                       switch (c) {
-                       case '/': /* double slash */
-                               goto bad_path;
-                       case '.':
-                               if (verify_dotfile(path) < 0)
-                                       goto bad_path;
-                       default:
-                               continue;
-                       }
-               }
-               c = *path++;
-       }
-       return 1;
-bad_path:
-       free(*resolved_path);
+               goto fail;
+       path = realpath(orig_path, NULL);
+       if (!path)
+               goto fail;
+       if (stat(path, &statbuf) < 0)
+               goto fail;
+       if (S_ISREG(statbuf.st_mode))
+               ret = 0;
+       else if (S_ISDIR(statbuf.st_mode))
+               ret = 1;
+       else
+               goto fail;
+       *resolved_path = path;
+       return ret;
+fail:
+       *resolved_path = NULL;
+       free(path);
        return -E_BAD_PATH;
 }
 
@@ -1981,7 +1957,6 @@ int com_add(struct command_context *cc)
 {
        int i, ret;
        struct private_add_data pad = {.cc = cc, .flags = 0};
-       struct stat statbuf;
 
        for (i = 1; i < cc->argc; i++) {
                const char *arg = cc->argv[i];
@@ -2020,20 +1995,10 @@ int com_add(struct command_context *cc)
                                return ret;
                        continue;
                }
-               ret = stat(path, &statbuf);
-               if (ret < 0) {
-                       ret = send_sb_va(&cc->scc, SBD_ERROR_LOG,
-                               "failed to stat %s (%s)\n", path,
-                               strerror(errno));
-                       free(path);
-                       if (ret < 0)
-                               return ret;
-                       continue;
-               }
-               if (S_ISDIR(statbuf.st_mode))
+               if (ret == 1) /* directory */
                        ret = for_each_file_in_dir(path, add_one_audio_file,
                                &pad);
-               else
+               else /* regular file */
                        ret = add_one_audio_file(path, &pad);
                if (ret < 0) {
                        send_sb_va(&cc->scc, SBD_OUTPUT, "%s: %s\n", path,
index 04d6cd6..a14a04e 100755 (executable)
@@ -21,7 +21,8 @@ pubkey=$privkey.pub
 serverlog=server.log
 
 get_audio_file_paths ogg
-oggs="$result"
+declare -a oggs=($result)
+declare -a oggs_base=(${oggs[@]##*/})
 
 declare -a commands=() cmdline=() required_objects=() good=() bad=()
 i=0
@@ -38,14 +39,14 @@ bad[$i]='!^successfully'
 let i++
 commands[$i]="add_ogg"
 required_objects[$i]='ogg_afh'
-cmdline[$i]="add $oggs"
+cmdline[$i]="add ${oggs[@]}"
 bad[$i]='.'
 
 let i++
 commands[$i]="ls_ogg"
 required_objects[$i]='ogg_afh'
-cmdline[$i]="ls -lv -p $oggs"
-good[$i]='^path:'
+cmdline[$i]="ls -lv ${oggs_base[@]}"
+good[$i]='^basename:'
 
 let i++
 commands[$i]="term"