]> granicus.if.org Git - neomutt/commitdiff
hcache: use mutt_mkdir
authorRichard Russon <rich@flatcap.org>
Mon, 9 Jan 2017 00:53:31 +0000 (00:53 +0000)
committerRichard Russon <rich@flatcap.org>
Mon, 23 Jan 2017 15:11:23 +0000 (15:11 +0000)
Use mutt_mkdir() to recursively create the directories that the header
cache needs.

hcache.c
lib.c

index 052f780c903f0a1461fb6633e51e484c8284b616..cce3bc75480ee0fd76154ef861f19ab3b9405d06 100644 (file)
--- a/hcache.c
+++ b/hcache.c
@@ -526,103 +526,111 @@ crc_matches(const char *d, unsigned int crc)
   return (crc == mycrc);
 }
 
-/* Append md5sumed folder to path if path is a directory. */
-static const char *
-mutt_hcache_per_folder(const char *path, const char *folder,
-                       hcache_namer_t namer)
+/**
+ * create_hcache_dir - Create parent dirs for the hcache database
+ * @path: Database filename
+ *
+ * @retval 1 Success
+ * @retval 0 Failure (errno set)
+ */
+static int create_hcache_dir(const char *path)
 {
-  static char hcpath[_POSIX_PATH_MAX];
-  struct stat sb;
-  unsigned char md5sum[16];
-  char* s;
-  int ret, plen;
-#ifndef HAVE_ICONV
-  const char *chs = Charset && *Charset ? Charset : 
-                   mutt_get_default_charset ();
-#endif
+  if (!path)
+    return 0;
 
-  plen = mutt_strlen (path);
+  static char dir[_POSIX_PATH_MAX];
+  strfcpy (dir, path, sizeof(dir));
 
-  ret = stat(path, &sb);
-  if (ret < 0 && path[plen-1] != '/')
-  {
-#ifdef HAVE_ICONV
-    return path;
-#else
-    snprintf (hcpath, _POSIX_PATH_MAX, "%s-%s", path, chs);
-    return hcpath;
-#endif
-  }
+  char *p = strrchr (dir, '/');
+  if (!p)
+    return 1;
 
-  if (ret >= 0 && !S_ISDIR(sb.st_mode))
-  {
-#ifdef HAVE_ICONV
-    return path;
-#else
-    snprintf (hcpath, _POSIX_PATH_MAX, "%s-%s", path, chs);
-    return hcpath;
-#endif
-  }
+  *p = 0;
+  if (mutt_mkdir (dir, S_IRWXU | S_IRWXG | S_IRWXO) == 0)
+    return 1;
+
+  mutt_error (_("Can't create %s: %s."), dir, strerror (errno));
+  mutt_sleep (2);
+  return 0;
+}
+
+/**
+ * mutt_hcache_per_folder - Generate the hcache pathname
+ * @param path   Base directory, from $header_cache
+ * @paran folder Mailbox name (including protocol)
+ * @param namer  Callback to generate database filename
+ *
+ * @return Full pathname to the database (to be generated)
+ *         (path must be freed by the caller)
+ *
+ * Generate the pathname for the hcache database, it will be of the form:
+ *     BASE/FOLDER/NAME-SUFFIX
+ *
+ * BASE :  Base directory (@path)
+ * FOLDER: Mailbox name (@folder)
+ * NAME:   Create by @namer, or md5sum of @folder
+ * SUFFIX: Character set (if ICONV isn't being used)
+ *
+ * This function will create any parent directories needed, so the caller just
+ * needs to create the database file.
+ *
+ * If @path exists and is a directory, it is used.
+ * If @path has a trailing '/' it is assumed to be a directory.
+ * If ICONV isn't being used, then a suffix is added to the path, e.g. '-utf-8'.
+ * Otherise @path is assumed to be a file.
+ */
+static const char *mutt_hcache_per_folder(const char *path, const char *folder,
+                                          hcache_namer_t namer)
+{
+  static char hcpath[_POSIX_PATH_MAX];
+  struct stat sb;
+
+  int plen = mutt_strlen(path);
+  int ret = stat(path, &sb);
+  int slash = (path[plen - 1] == '/');
 
   if (namer)
   {
-    snprintf (hcpath, sizeof (hcpath), "%s%s", path,
-              path[plen-1] == '/' ? "" : "/");
-    if (path[plen-1] != '/')
+    /* We have a mailbox-specific namer function */
+    snprintf(hcpath, sizeof(hcpath), "%s%s", path, slash ? "" : "/");
+    if (!slash)
       plen++;
 
-    ret = namer (folder, hcpath + plen, sizeof (hcpath) - plen);
+    ret = namer(folder, hcpath + plen, sizeof(hcpath) - plen);
   }
   else
   {
-    md5_buffer (folder, strlen (folder), &md5sum);
-
-    /* On some systems (e.g. OS X), snprintf is defined as a macro.
-     * Embedding directives inside macros is undefined, so we have to duplicate
-     * the whole call:
-     */
+    unsigned char m[16]; /* binary md5sum */
+    char name[33];
+    md5_buffer(folder, strlen(folder), &m);
+    snprintf(name, sizeof(name),
+             "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x",
+             m[0], m[1], m[2],  m[3],  m[4],  m[5],  m[6],  m[7],
+             m[8], m[9], m[10], m[11], m[12], m[13], m[14], m[15]);
+
+    char suffix[32] = "";
 #ifndef HAVE_ICONV
-    ret = snprintf(hcpath, _POSIX_PATH_MAX,
-                   "%s/%02x%02x%02x%02x%02x%02x%02x%02x"
-                   "%02x%02x%02x%02x%02x%02x%02x%02x"
-                  "-%s"
-                  ,
-                  path, md5sum[0], md5sum[1], md5sum[2], md5sum[3],
-                   md5sum[4], md5sum[5], md5sum[6], md5sum[7], md5sum[8],
-                   md5sum[9], md5sum[10], md5sum[11], md5sum[12],
-                   md5sum[13], md5sum[14], md5sum[15]
-                  ,chs
-                  );
-#else
-    ret = snprintf(hcpath, _POSIX_PATH_MAX,
-                   "%s/%02x%02x%02x%02x%02x%02x%02x%02x"
-                   "%02x%02x%02x%02x%02x%02x%02x%02x"
-                  ,
-                  path, md5sum[0], md5sum[1], md5sum[2], md5sum[3],
-                   md5sum[4], md5sum[5], md5sum[6], md5sum[7], md5sum[8],
-                   md5sum[9], md5sum[10], md5sum[11], md5sum[12],
-                   md5sum[13], md5sum[14], md5sum[15]
-                  );
+    const char *chs = Charset && *Charset ? Charset : mutt_get_default_charset();
+    snprintf(suffix, sizeof(suffix), "-%s", chs);
 #endif
-  }
-  
-  if (ret <= 0)
-    return path;
-
-  if (stat (hcpath, &sb) >= 0)
-    return hcpath;
 
-  s = strchr (hcpath + 1, '/');
-  while (s)
-  {
-    /* create missing path components */
-    *s = '\0';
-    if (stat (hcpath, &sb) < 0 && (errno != ENOENT || mkdir (hcpath, 0777) < 0))
-      return path;
-    *s = '/';
-    s = strchr (s + 1, '/');
+    if (((ret == 0) && S_ISDIR(sb.st_mode)) || ((ret == -1) && slash))
+    {
+      /* An existing directory or a trailing slash => a directory */
+      ret = snprintf(hcpath, sizeof(hcpath), "%s%s%s%s", path,
+          slash ? "" : "/", name, suffix);
+    }
+    else
+    {
+      /* Otherwise, we have a file */
+      ret = snprintf(hcpath, sizeof(hcpath), "%s%s", path, suffix);
+    }
   }
 
+  if (ret < 0)
+    return path;
+
+  create_hcache_dir(hcpath);
   return hcpath;
 }
 
diff --git a/lib.c b/lib.c
index 1519b2f63875ef68a6a1616070d9f5c34a83fad1..299b19dfadb98ed01a1d22f63541a45a2e4acce1 100644 (file)
--- a/lib.c
+++ b/lib.c
@@ -1179,6 +1179,7 @@ int mutt_mkdir(const char *path, mode_t mode)
     return -1;
   }
 
+  errno = 0;
   char *p;
   char _path[PATH_MAX];
   const size_t len = strlen(path);
@@ -1189,6 +1190,10 @@ int mutt_mkdir(const char *path, mode_t mode)
     return -1;
   }
 
+  struct stat sb;
+  if ((stat(path, &sb) == 0) && S_ISDIR(sb.st_mode))
+    return 0;
+
   /* Create a mutable copy */
   strfcpy(_path, path, sizeof(_path));
 
@@ -1209,7 +1214,6 @@ int mutt_mkdir(const char *path, mode_t mode)
   if ((mkdir(_path, mode) != 0) && (errno != EEXIST))
     return -1;
 
-  errno = 0;
   return 0;
 }