diff --git a/configure.ac b/configure.ac index 67eb27a1..4298cd91 100644 --- a/configure.ac +++ b/configure.ac @@ -138,7 +138,7 @@ AS_IF([test -z "$PKG_CONFIG"], ) # glib2? -PKG_CHECK_MODULES(GLIB,glib-2.0 >= 2.38 gobject-2.0 gio-2.0) +PKG_CHECK_MODULES(GLIB,glib-2.0 >= 2.50 gobject-2.0 gio-2.0) glib_version="$($PKG_CONFIG --modversion glib-2.0)" # gmime, version 3.0 or higher diff --git a/lib/mu-msg-file.c b/lib/mu-msg-file.c index eb37670a..121af38f 100644 --- a/lib/mu-msg-file.c +++ b/lib/mu-msg-file.c @@ -110,7 +110,7 @@ init_file_metadata (MuMsgFile *self, const char* path, const gchar* mdir, self->_timestamp = statbuf.st_mtime; self->_size = (size_t)statbuf.st_size; - self->_path = g_canonicalize_filename(path, NULL); + self->_path = mu_canonicalize_filename(path, NULL); self->_maildir = g_strdup(mdir ? mdir : ""); return TRUE; diff --git a/lib/utils/mu-util.c b/lib/utils/mu-util.c index d9885216..f0515789 100644 --- a/lib/utils/mu-util.c +++ b/lib/utils/mu-util.c @@ -501,3 +501,141 @@ mu_util_read_password (const char *prompt) return g_strdup (pass); } + + +/* Pick g_canonicalize_file name from glib >= 2.58 */ + +/** + * g_canonicalize_filename: + * @filename: (type filename): the name of the file + * @relative_to: (type filename) (nullable): the relative directory, or %NULL + * to use the current working directory + * + * Gets the canonical file name from @filename. All triple slashes are turned into + * single slashes, and all `..` and `.`s resolved against @relative_to. + * + * Symlinks are not followed, and the returned path is guaranteed to be absolute. + * + * If @filename is an absolute path, @relative_to is ignored. Otherwise, + * @relative_to will be prepended to @filename to make it absolute. @relative_to + * must be an absolute path, or %NULL. If @relative_to is %NULL, it'll fallback + * to g_get_current_dir(). + * + * This function never fails, and will canonicalize file paths even if they don't + * exist. + * + * No file system I/O is done. + * + * Returns: (type filename) (transfer full): a newly allocated string with the + * canonical file path + * Since: 2.58 + */ +gchar * +mu_canonicalize_filename (const gchar *filename, + const gchar *relative_to) +{ + gchar *canon, *start, *p, *q; + guint i; + + g_return_val_if_fail (relative_to == NULL || g_path_is_absolute (relative_to), NULL); + + if (!g_path_is_absolute (filename)) + { + gchar *cwd_allocated = NULL; + const gchar *cwd; + + if (relative_to != NULL) + cwd = relative_to; + else + cwd = cwd_allocated = g_get_current_dir (); + + canon = g_build_filename (cwd, filename, NULL); + g_free (cwd_allocated); + } + else + { + canon = g_strdup (filename); + } + + start = (char *)g_path_skip_root (canon); + + if (start == NULL) + { + /* This shouldn't really happen, as g_get_current_dir() should + return an absolute pathname, but bug 573843 shows this is + not always happening */ + g_free (canon); + return g_build_filename (G_DIR_SEPARATOR_S, filename, NULL); + } + + /* POSIX allows double slashes at the start to + * mean something special (as does windows too). + * So, "//" != "/", but more than two slashes + * is treated as "/". + */ + i = 0; + for (p = start - 1; + (p >= canon) && + G_IS_DIR_SEPARATOR (*p); + p--) + i++; + if (i > 2) + { + i -= 1; + start -= i; + memmove (start, start+i, strlen (start+i) + 1); + } + + /* Make sure we're using the canonical dir separator */ + p++; + while (p < start && G_IS_DIR_SEPARATOR (*p)) + *p++ = G_DIR_SEPARATOR; + + p = start; + while (*p != 0) + { + if (p[0] == '.' && (p[1] == 0 || G_IS_DIR_SEPARATOR (p[1]))) + { + memmove (p, p+1, strlen (p+1)+1); + } + else if (p[0] == '.' && p[1] == '.' && (p[2] == 0 || G_IS_DIR_SEPARATOR (p[2]))) + { + q = p + 2; + /* Skip previous separator */ + p = p - 2; + if (p < start) + p = start; + while (p > start && !G_IS_DIR_SEPARATOR (*p)) + p--; + if (G_IS_DIR_SEPARATOR (*p)) + *p++ = G_DIR_SEPARATOR; + memmove (p, q, strlen (q)+1); + } + else + { + /* Skip until next separator */ + while (*p != 0 && !G_IS_DIR_SEPARATOR (*p)) + p++; + + if (*p != 0) + { + /* Canonicalize one separator */ + *p++ = G_DIR_SEPARATOR; + } + } + + /* Remove additional separators */ + q = p; + while (*q && G_IS_DIR_SEPARATOR (*q)) + q++; + + if (p != q) + memmove (p, q, strlen (q) + 1); + } + + /* Remove trailing slashes */ + if (p > start && G_IS_DIR_SEPARATOR (*(p-1))) + *(p-1) = 0; + + return canon; +} diff --git a/lib/utils/mu-util.h b/lib/utils/mu-util.h index 3bde4ba0..f7147bd5 100644 --- a/lib/utils/mu-util.h +++ b/lib/utils/mu-util.h @@ -49,6 +49,20 @@ G_BEGIN_DECLS char* mu_util_dir_expand (const char* path) G_GNUC_MALLOC G_GNUC_WARN_UNUSED_RESULT; + +/** + * See g_canonicalize_filename + * + * @param filename + * @param relative_to + * + * @return + */ +char *mu_canonicalize_filename (const gchar *filename, + const gchar *relative_to) + G_GNUC_MALLOC G_GNUC_WARN_UNUSED_RESULT; + + /** * guess the maildir; first try $MAILDIR; if it is unset or * non-existent, try ~/Maildir if both fail, return NULL