mkdir_p.c
#include "ustr.h"
#include <sys/stat.h>
#include <sys/types.h>
#include <errno.h>
static void die(const char *prog_name, const char *msg)
{
fprintf(stderr, "%s: %s\n", prog_name, msg);
exit (EXIT_FAILURE);
}
static int fu__mkdir_p(const Ustr *s1, int mode, size_t off, int ret)
{
Ustr *allocd = USTR_NULL;
char *ptr = NULL;
if (mkdir(ustr_cstr(s1), mode) != -1)
return (ret + 1);
switch (errno)
{
case EEXIST: return (ret);
case ENOENT: break;
default: return (-1);
}
if ((off = ustr_srch_chr_rev(s1, off, '/')) <= 1)
{
errno = EINVAL;
return (-1);
}
--off;
if (!ustr_owner(s1))
{
if (!(allocd = ustr_dup_buf(ustr_cstr(s1), ustr_len(s1))))
return (-1);
s1 = allocd;
}
ptr = ustr_wstr((Ustr *)s1);
ptr[off] = 0;
if ((ret = fu__mkdir_p(s1, mode, ustr_len(s1) - off, ret + 1)) != -1)
{
ptr[off] = '/';
if (mkdir(ustr_cstr(s1), mode) == -1)
ret = -1;
}
ustr_free(allocd);
return (ret);
}
static int mkdir_p(const Ustr *s1, int mode)
{
return (fu__mkdir_p(s1, mode, 0, 0));
}
int main(int argc, char *argv[])
{
const char *prog_name = NULL;
int scan = 1;
Ustr *s1 = USTR("");
USTR_CNTL_MALLOC_CHECK_BEG(USTR_DEBUG);
if (!argc)
exit (EXIT_FAILURE);
if ((prog_name = strrchr(argv[0], '/')))
++prog_name;
else
prog_name = argv[0];
#ifdef TST
mkdir_p(USTR1(\x24, "/tmp/abcd/1/2/3/4/5/6/7/8/9/10/11/12"), 0700, prog_name);
#endif
if (argc == 1)
die(prog_name, "No arguments given");
while (scan < argc)
{
int num = 0;
if (!ustr_set_cstr(&s1, argv[scan++]))
die(prog_name, strerror(ENOMEM));
if ((num = mkdir_p(s1, 0700)) == -1)
{
int sve_err = errno;
die(ustr_cstr(ustr_dup_fmt("%s: mkdir(\"%s\")", prog_name,
ustr_cstr(s1))), strerror(sve_err));
}
if (num)
{
Ustr *msg = ustr_dup_fmt(" Created %d leaves of: ", num);
if (!msg)
die(prog_name, strerror(ENOMEM));
if (!ustr_io_putfile(&msg, stdout))
die(prog_name, strerror(errno));
if (!ustr_io_putfileline(&s1, stdout))
die(prog_name, strerror(errno));
ustr_free(msg);
}
}
ustr_free(s1);
USTR_CNTL_MALLOC_CHECK_END();
return (EXIT_SUCCESS);
}