mkdir-parents.c revision aeb01e4ba09e5be7a642e98ab54c4ab05cdebd86
a8c5a86d183db25a57bf193c06b41e092ec2e151Timo Sirainen/* Copyright (c) 2003-2009 Dovecot authors, see the included COPYING file */
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainen#include "lib.h"
46552a931924c2d743f045e95b08c3ce6beda91aTimo Sirainen#include "mkdir-parents.h"
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen#include <sys/stat.h>
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen#include <unistd.h>
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainenint mkdir_chown(const char *path, mode_t mode, uid_t uid, gid_t gid)
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen{
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen mode_t old_mask;
de754cb78f75e8b3b994cddafe41c9ed1467c33dTimo Sirainen int ret;
f29756821a4c6b12b73e4a2a3e1c230117a43773Timo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen old_mask = umask(0);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen ret = mkdir(path, mode);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen umask(old_mask);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
53dfcefa9440a49d703e49193819a79be99c9ba6Timo Sirainen if (ret < 0) {
f0d93763f210ecdb85a115fdd0210a16cfc5ff5cTimo Sirainen if (errno == EISDIR || errno == ENOSYS) {
53dfcefa9440a49d703e49193819a79be99c9ba6Timo Sirainen /* EISDIR check is for BSD/OS which returns it if path
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen contains '/' at the end and it exists.
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen ENOSYS check is for NFS mount points. */
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainen errno = EEXIST;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen }
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainen return -1;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen }
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen if (chown(path, uid, gid) < 0) {
2e78f05b11df23ec2731afaf8f19d5b5240cb29fTimo Sirainen i_error("chown(%s, %ld, %ld) failed: %m", path,
2e78f05b11df23ec2731afaf8f19d5b5240cb29fTimo Sirainen uid == (uid_t)-1 ? -1L : (long)uid,
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen gid == (gid_t)-1 ? -1L : (long)gid);
d1e7425048c61d71f41f737ba947687198842dc2Timo Sirainen return -1;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen }
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen return 0;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen}
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainenint mkdir_parents_chown(const char *path, mode_t mode, uid_t uid, gid_t gid)
660b99a7059824676b2b8d6f79b8e15d47df25a2Timo Sirainen{
660b99a7059824676b2b8d6f79b8e15d47df25a2Timo Sirainen const char *p;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen int ret;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen if (mkdir_chown(path, mode, uid, gid) < 0) {
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen if (errno != ENOENT)
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainen return -1;
b9c76fe9d9ca194816606342da1ddbd9be6bc8abTimo Sirainen
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainen /* doesn't exist, try recursively creating our parent dir */
b9c76fe9d9ca194816606342da1ddbd9be6bc8abTimo Sirainen p = strrchr(path, '/');
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainen if (p == NULL || p == path)
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainen return -1; /* shouldn't happen */
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen T_BEGIN {
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen ret = mkdir_parents_chown(t_strdup_until(path, p),
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen mode, uid, gid);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen } T_END;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen if (ret < 0)
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen return -1;
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainen
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainen /* should work now */
b9c76fe9d9ca194816606342da1ddbd9be6bc8abTimo Sirainen if (mkdir_chown(path, mode, uid, gid) < 0)
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen return -1;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen }
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen return 0;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen}
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainenint mkdir_parents(const char *path, mode_t mode)
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen{
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen return mkdir_parents_chown(path, mode, (uid_t)-1, (gid_t)-1);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen}
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen