]> wimlib.net Git - wimlib/blobdiff - src/paths.c
timestamp.c: correctly convert negative UNIX timestamps
[wimlib] / src / paths.c
index 040ed697c083537730a7acb278ab7a15e91fb25b..4b9db67f87ebed18b7404c5864cf676f4fb6c5a4 100644 (file)
 /*
  * Copyright (C) 2012, 2013 Eric Biggers
  *
- * This file is part of wimlib, a library for working with WIM files.
+ * This file is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU Lesser General Public License as published by the Free
+ * Software Foundation; either version 3 of the License, or (at your option) any
+ * later version.
  *
- * wimlib 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 3 of the License, or (at your option)
- * any later version.
- *
- * wimlib 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
+ * This file 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 Lesser General Public License for more
  * details.
  *
- * You should have received a copy of the GNU General Public License
- * along with wimlib; if not, see http://www.gnu.org/licenses/.
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this file; if not, see http://www.gnu.org/licenses/.
  */
 
 #ifdef HAVE_CONFIG_H
 #  include "config.h"
 #endif
 
+#include <string.h>
+
+#include "wimlib.h"
 #include "wimlib/paths.h"
 #include "wimlib/util.h"
 
-#include <string.h>
-
 /* Like the basename() function, but does not modify @path; it just returns a
- * pointer to it. */
+ * pointer to it.  This assumes the path separator is the
+ * OS_PREFERRED_PATH_SEPARATOR.  */
 const tchar *
 path_basename(const tchar *path)
 {
        return path_basename_with_len(path, tstrlen(path));
 }
 
-/* Like path_basename(), but take an explicit string length. */
+/* Like path_basename(), but take an explicit string length.  */
 const tchar *
 path_basename_with_len(const tchar *path, size_t len)
 {
-       const tchar *p = &path[len] - 1;
-
-       /* Trailing slashes. */
-       while (1) {
-               if (p == path - 1)
-                       return T("");
-               if (*p != T('/'))
-                       break;
-               p--;
-       }
+       const tchar *p = &path[len];
 
-       while ((p != path - 1) && *p != T('/'))
-               p--;
+       do {
+               if (p == path)
+                       return &path[len];
+       } while (*--p == OS_PREFERRED_PATH_SEPARATOR);
 
-       return p + 1;
+       do {
+               if (p == path)
+                       return &path[0];
+       } while (*--p != OS_PREFERRED_PATH_SEPARATOR);
+
+       return ++p;
 }
 
 
-/*
- * Returns a pointer to the part of @path following the first colon in the last
- * path component, or NULL if the last path component does not contain a colon.
- */
+/* Returns a pointer to the part of @path following the first colon in the last
+ * path component, or NULL if the last path component does not contain a colon
+ * or has no characters following the first colon.  */
 const tchar *
 path_stream_name(const tchar *path)
 {
        const tchar *base = path_basename(path);
        const tchar *stream_name = tstrchr(base, T(':'));
-       if (!stream_name)
+       if (stream_name == NULL || *(stream_name + 1) == T('\0'))
                return NULL;
        else
                return stream_name + 1;
 }
 
-
-/* Translate backslashes to forward slashes in-place. */
+/* Collapse and translate path separators, and strip trailing slashes.  Doesn't
+ * add or delete a leading slash.
+ *
+ * @in may alias @out.
+ */
 void
-zap_backslashes(tchar *s)
+do_canonicalize_path(const tchar *in, tchar *out)
 {
-       if (s) {
-               while (*s != T('\0')) {
-                       if (*s == T('\\'))
-                               *s = T('/');
-                       s++;
+       tchar *orig_out = out;
+
+       while (*in) {
+               if (is_any_path_separator(*in)) {
+                       /* Collapse multiple path separators into one  */
+                       *out++ = WIM_PATH_SEPARATOR;
+                       do {
+                               in++;
+                       } while (is_any_path_separator(*in));
+               } else {
+                       /* Copy non-path-separator character  */
+                       *out++ = *in++;
                }
        }
-}
 
-/* Duplicate a path; return empty string for NULL input. */
-tchar *
-canonicalize_fs_path(const tchar *fs_path)
-{
-       if (!fs_path)
-               fs_path = T("");
-       return TSTRDUP(fs_path);
+       /* Remove trailing slash if existent  */
+       if (out - orig_out > 1 && *(out - 1) == WIM_PATH_SEPARATOR)
+               --out;
+
+       *out = T('\0');
 }
 
-/* Duplicate a path, with backslashes translated into forward slashes; return
- * empty string for NULL input;  also strip leading and trailing slashes. */
+/*
+ * canonicalize_wim_path() - Given a user-provided path to a file within a WIM
+ * image, translate it into a "canonical" path.
+ *
+ * - Translate both types of slash into a consistent type (WIM_PATH_SEPARATOR).
+ * - Collapse path separators.
+ * - Add leading slash if missing.
+ * - Strip trailing slashes.
+ *
+ * Examples (with WIM_PATH_SEPARATOR == '/'):
+ *
+ *             => /            [ either NULL or empty string ]
+ * /           => /
+ * \           => /
+ * hello       => /hello
+ * \hello      => /hello
+ * \hello      => /hello
+ * /hello/     => /hello
+ * \hello/     => /hello
+ * /hello//1   => /hello/1
+ * \\hello\\1\\        => /hello/1
+ */
 tchar *
 canonicalize_wim_path(const tchar *wim_path)
 {
-       tchar *p;
-       tchar *canonical_path;
-
-       if (wim_path == NULL) {
-               wim_path = T("");
-       } else {
-               while (*wim_path == T('/') || *wim_path == T('\\'))
-                       wim_path++;
-       }
-       canonical_path = TSTRDUP(wim_path);
-       if (canonical_path) {
-               zap_backslashes(canonical_path);
-               for (p = tstrchr(canonical_path, T('\0')) - 1;
-                    p >= canonical_path && *p == T('/');
-                    p--)
-               {
-                       *p = T('\0');
-               }
-       }
-       return canonical_path;
+       const tchar *in;
+       tchar *out;
+       tchar *result;
+
+       in = wim_path;
+       if (!in)
+               in = T("");
+
+       result = MALLOC((1 + tstrlen(in) + 1) * sizeof(result[0]));
+       if (!result)
+               return NULL;
+
+       out = result;
+
+       /* Add leading slash if missing  */
+       if (!is_any_path_separator(*in))
+               *out++ = WIM_PATH_SEPARATOR;
+
+       do_canonicalize_path(in, out);
+
+       return result;
 }