summaryrefslogtreecommitdiff
path: root/package/cfgfs/src/ft_creat.c
diff options
context:
space:
mode:
Diffstat (limited to 'package/cfgfs/src/ft_creat.c')
-rw-r--r--package/cfgfs/src/ft_creat.c304
1 files changed, 304 insertions, 0 deletions
diff --git a/package/cfgfs/src/ft_creat.c b/package/cfgfs/src/ft_creat.c
new file mode 100644
index 000000000..5838f8647
--- /dev/null
+++ b/package/cfgfs/src/ft_creat.c
@@ -0,0 +1,304 @@
+/* $MirOS: contrib/hosted/fwcf/ft_creat.c,v 1.2 2006/09/23 23:21:04 tg Exp $ */
+
+/*-
+ * Copyright (c) 2006
+ * Thorsten Glaser <tg@mirbsd.de>
+ *
+ * Licensee is hereby permitted to deal in this work without restric-
+ * tion, including unlimited rights to use, publicly perform, modify,
+ * merge, distribute, sell, give away or sublicence, provided all co-
+ * pyright notices above, these terms and the disclaimer are retained
+ * in all redistributions or reproduced in accompanying documentation
+ * or other materials provided with binary redistributions.
+ *
+ * Licensor offers the work "AS IS" and WITHOUT WARRANTY of any kind,
+ * express, or implied, to the maximum extent permitted by applicable
+ * law, without malicious intent or gross negligence; in no event may
+ * licensor, an author or contributor be held liable for any indirect
+ * or other damage, or direct damage except proven a consequence of a
+ * direct error of said person and intended use of this work, loss or
+ * other issues arising in any way out of its use, even if advised of
+ * the possibility of such damage or existence of a defect.
+ */
+
+#include <sys/param.h>
+#include <sys/time.h>
+#include <sys/stat.h>
+#include <err.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "defs.h"
+#include "pack.h"
+
+__RCSID("$MirOS: contrib/hosted/fwcf/ft_creat.c,v 1.2 2006/09/23 23:21:04 tg Exp $");
+
+static size_t ft_creat(char *);
+static void make_directory(char *, uint32_t, uint32_t, uint32_t, time_t);
+static void make_file(char *, uint8_t *, size_t);
+static void make_symlink(char *, uint8_t *, size_t);
+static void pop_directories(void);
+static void do_chown(char *, uid_t, gid_t);
+static void do_chmod(char *, mode_t);
+static void do_mtime(char *, time_t);
+static char *pfxname(const char *);
+
+static struct a_directory {
+ struct a_directory *next;
+ char *pathname;
+ uid_t owner;
+ gid_t group;
+ mode_t perms;
+ time_t mtime;
+} *directories;
+
+static char basename[PATH_MAX];
+static size_t basename_len;
+
+void
+ft_creatm(char *buf, const char *pathname)
+{
+ directories = NULL;
+ snprintf(basename, sizeof (basename), "%s/", pathname);
+ basename_len = strlen(basename);
+ while (*buf)
+ buf += ft_creat(buf);
+ if (directories != NULL)
+ pop_directories();
+}
+
+static size_t
+ft_creat(char *buf)
+{
+ uint8_t c, *p;
+ char *fname;
+ size_t i, type = 0, size = 0;
+ uint32_t x_uid = 0, x_gid = 0, x_mode = 0;
+ time_t x_mtime = 0;
+
+ i = strlen(buf) + 1;
+ p = (uint8_t *)buf + i;
+ fname = pfxname(buf);
+ while (*p)
+ switch (c = *p++) {
+ case 0x01:
+ /* block special device */
+ type = 1;
+ break;
+ case 0x02:
+ /* character special device */
+ type = 1;
+ break;
+ case 0x03:
+ /* symbolic link */
+ type = 2;
+ break;
+ case 0x04:
+ /* hard link */
+ type = 1;
+ break;
+ case 0x05:
+ /* directory */
+ type = 3;
+ break;
+ case 0x10:
+ /* modification time */
+ x_mtime = LOADD(p);
+ p += 4;
+ break;
+ case 'g':
+ case 'G':
+ x_gid = (c == 'g') ? *p : LOADD(p);
+ p += (c == 'g') ? 1 : 4;
+ break;
+ case 'i':
+ case 'I':
+ /* x_inode = (c == 'i') ? *p : LOADW(p); */
+ p += (c == 'i') ? 1 : 2;
+ break;
+ case 'm':
+ case 'M':
+ x_mode = (c == 'm') ? LOADW(p) : LOADD(p);
+ p += (c == 'm') ? 2 : 4;
+ break;
+ case 'u':
+ case 'U':
+ x_uid = (c == 'u') ? *p : LOADD(p);
+ p += (c == 'u') ? 1 : 4;
+ break;
+ case 's':
+ case 'S':
+ size = (c == 's') ? *p : LOADT(p);
+ p += (c == 's') ? 1 : 3;
+ break;
+ default:
+ errx(1, "unknown attribute %02Xh", c);
+ }
+ /* skip over final NUL byte */
+ ++p;
+
+ switch (type) {
+ case 1:
+ /* no data, not implemented */
+ if (size)
+ fputs("WARN: size not allowed, ignoring\n", stderr);
+ size = 0;
+ break;
+ case 2:
+ /* symbolic link */
+ make_symlink(fname, p, size);
+ x_mtime = 0;
+ x_mode = 0;
+ break;
+ case 3:
+ /* directory */
+ if (size)
+ fputs("WARN: size not allowed, ignoring\n", stderr);
+ size = 0;
+ make_directory(fname, x_mode, x_uid, x_gid, x_mtime);
+ goto notfile;
+ break;
+ case 0:
+ /* regular file */
+ make_file(fname, p, size);
+ break;
+ default:
+ abort();
+ }
+
+ if (x_uid || x_gid)
+ do_chown(fname, x_uid, x_gid);
+
+ if (x_mode)
+ do_chmod(fname, x_mode);
+
+ if (x_mtime)
+ do_mtime(fname, x_mtime);
+
+ notfile:
+ if (type != 3)
+ free(fname);
+
+ return ((p - (uint8_t *)buf) + size);
+}
+
+static void
+make_directory(char *n, uint32_t m, uint32_t u, uint32_t g, time_t t)
+{
+ struct a_directory *newdir;
+
+ if ((newdir = malloc(sizeof (struct a_directory))) == NULL)
+ err(1, "out of memory");
+
+ newdir->next = directories;
+ directories = newdir;
+
+ newdir->pathname = n;
+ newdir->owner = u;
+ newdir->group = g;
+ newdir->perms = m;
+ newdir->mtime = t;
+
+ if (mkdir(n, 0700))
+ if (errno != EEXIST)
+ warn("mkdir %s", n);
+}
+
+static void
+make_file(char *n, uint8_t *buf, size_t len)
+{
+ int fd;
+
+ unlink(n);
+
+ if ((fd = open(n, O_WRONLY | O_CREAT | O_TRUNC, 0700)) < 0) {
+ warn("open %s", n);
+ return;
+ }
+
+ if ((size_t)write(fd, buf, len) != len)
+ warn("could not write %lu bytes", (u_long)len);
+
+ if (close(fd))
+ warn("close");
+}
+
+static void
+make_symlink(char *n, uint8_t *buf, size_t len)
+{
+ char target[len + 1];
+
+ memcpy(target, buf, len);
+ target[len] = '\0';
+
+ unlink(n);
+
+ if (symlink(target, n))
+ warn("symlink %s -> %s", n, target);
+}
+
+static void
+pop_directories(void)
+{
+ struct a_directory *p;
+
+ while ((p = directories) != NULL) {
+ directories = p->next;
+
+ if (p->pathname == NULL)
+ warnx("pathname for a directory is NULL");
+ else {
+ do_chown(p->pathname, p->owner, p->group);
+ do_chmod(p->pathname, p->perms);
+ do_mtime(p->pathname, p->mtime);
+ free(p->pathname);
+ }
+ free(p);
+ }
+}
+
+static void
+do_chown(char *n, uid_t o, gid_t g)
+{
+ if (lchown(n, o, g))
+ warn("lchown %d:%d %s", (int)o, (int)g, n);
+}
+
+static void
+do_chmod(char *n, mode_t m)
+{
+ if (chmod(n, m & 07777))
+ warn("lchmod 0%o %s", m & 07777, n);
+}
+
+static void
+do_mtime(char *n, time_t t)
+{
+ struct timeval tv[2] = { {0,0}, {0,0} };
+
+ tv[1].tv_sec = t;
+ if (utimes(n, tv))
+ warn("utimes %d %s", (int)t, n);
+}
+
+static char *
+pfxname(const char *component)
+{
+ char *foo;
+ size_t len, x;
+
+ len = basename_len + (x = strlen(component) + /* NUL */ 1);
+ if ((foo = malloc(len)) == NULL)
+ err(1, "out of memory");
+ memcpy(foo, basename, basename_len);
+ if ((component[0] == '.') && (component[1] == '\0'))
+ foo[basename_len] = '\0';
+ else
+ memcpy(foo + basename_len, component, x);
+
+ return (foo);
+}