#include "mkdir-parents.h"
#include <sys/stat.h>
+#include <unistd.h>
-int mkdir_parents(const char *path, mode_t mode)
+static int mkdir_chown(const char *path, mode_t mode, uid_t uid, gid_t gid)
{
- const char *p;
+ mode_t old_mask;
int ret;
- if (mkdir(path, mode) == 0) {
- /* success */
- } else if (errno != ENOENT) {
- /* EISDIR check is for BSD/OS which returns it if path
- contains '/' at the end and it exists.
+ old_mask = umask(0);
+ ret = mkdir(path, mode);
+ umask(old_mask);
+
+ if (ret < 0) {
+ if (errno == EISDIR || errno == ENOSYS) {
+ /* EISDIR check is for BSD/OS which returns it if path
+ contains '/' at the end and it exists.
- ENOSYS check is for NFS mount points.
- */
- if (errno == EISDIR && errno == ENOSYS)
+ ENOSYS check is for NFS mount points. */
errno = EEXIST;
+ }
+ return -1;
+ }
+ if (chown(path, uid, gid) < 0) {
+ i_error("chown(%s, %ld, %ld) failed: %m", path,
+ uid == (uid_t)-1 ? -1L : (long)uid,
+ gid == (gid_t)-1 ? -1L : (long)gid);
return -1;
- } else {
+ }
+ return 0;
+}
+
+int mkdir_parents_chown(const char *path, mode_t mode, uid_t uid, gid_t gid)
+{
+ const char *p;
+ int ret;
+
+ if (mkdir_chown(path, mode, uid, gid) < 0) {
+ if (errno != ENOENT)
+ return -1;
+
+ /* doesn't exist, try recursively creating our parent dir */
p = strrchr(path, '/');
if (p == NULL || p == path)
return -1; /* shouldn't happen */
T_BEGIN {
- ret = mkdir_parents(t_strdup_until(path, p), mode);
+ ret = mkdir_parents_chown(t_strdup_until(path, p),
+ mode, uid, gid);
} T_END;
if (ret < 0)
return -1;
/* should work now */
- if (mkdir(path, mode) < 0 && errno != EEXIST && errno != EISDIR)
+ if (mkdir_chown(path, mode, uid, gid) < 0)
return -1;
}
-
return 0;
}
+
+int mkdir_parents(const char *path, mode_t mode)
+{
+ return mkdir_parents_chown(path, mode, (uid_t)-1, (gid_t)-1);
+}