/* * Make the given directory and its parents as necessary, using the * given mode. Return true on success, false otherwise. Partial * results are not cleaned up on errors. */ static bool mkdir_recursive (const void *ctx, const char *path, int mode) { struct stat st; int r; char *parent = NULL, *slash; /* First check the common case: directory already exists. */ r = stat (path, &st); if (r == 0) { if (! S_ISDIR (st.st_mode)) { fprintf (stderr, "Error: '%s' is not a directory: %s\n", path, strerror (EEXIST)); return false; } return true; } else if (errno != ENOENT) { fprintf (stderr, "Error: stat '%s': %s\n", path, strerror (errno)); return false; } /* mkdir parents, if any */ slash = strrchr (path, '/'); if (slash && slash != path) { parent = talloc_strndup (ctx, path, slash - path); if (! parent) { fprintf (stderr, "Error: %s\n", strerror (ENOMEM)); return false; } if (! mkdir_recursive (ctx, parent, mode)) return false; } if (mkdir (path, mode)) { fprintf (stderr, "Error: mkdir '%s': %s\n", path, strerror (errno)); return false; } return parent ? sync_dir (parent) : true; }
/* * Write fdin to a new file in maildir/new, using an intermediate temp * file in maildir/tmp, return full path to the new file, or NULL on * errors. */ static char * maildir_write_new (const void *ctx, int fdin, const char *maildir) { char *cleanpath, *tmppath, *newpath, *newdir; tmppath = maildir_write_tmp (ctx, fdin, maildir); if (! tmppath) return NULL; cleanpath = tmppath; newpath = talloc_strdup (ctx, tmppath); if (! newpath) { fprintf (stderr, "Error: %s\n", strerror (ENOMEM)); goto FAIL; } /* sanity checks needed? */ memcpy (newpath + strlen (maildir) + 1, "new", 3); if (rename (tmppath, newpath)) { fprintf (stderr, "Error: rename '%s' '%s': %s\n", tmppath, newpath, strerror (errno)); goto FAIL; } cleanpath = newpath; newdir = talloc_asprintf (ctx, "%s/%s", maildir, "new"); if (! newdir) { fprintf (stderr, "Error: %s\n", strerror (ENOMEM)); goto FAIL; } if (! sync_dir (newdir)) goto FAIL; return newpath; FAIL: unlink (cleanpath); return NULL; }