pm

barely a pack manager
git clone git://z3bra.org/pm
Log | Files | Refs | README | LICENSE

commit c293e2c77808dc0c1f1b292111dd18dd19280a46
parent d66413a9f2f5c91fb4f7e7b5e147e71f6478a881
Author: z3bra <willyatmailoodotorg>
Date:   Sat Jan 30 15:24:02 +0100

Use mmap to read metadata files in delete()

Diffstat:
pm.c | 118+++++++++++++++++++++++++++++++++++++++++++++----------------------------------
1 file changed, 68 insertions(+), 50 deletions(-)
diff --git a/pm.c b/pm.c @@ -5,6 +5,7 @@ #include <stdio.h> #include <stdlib.h> #include <string.h> +#include <sys/mman.h> #include <sys/stat.h> #include <sys/types.h> @@ -49,7 +50,6 @@ void usage(char *name); int is_empty(char *dir); int mkdir_parents(char *dir, mode_t mode); char *base_name(char *path); -char *lread(int fd, char *buf, size_t len); struct pack *pack_load(char *path); void pack_free(struct pack *p); @@ -63,7 +63,8 @@ int write_metadata(char *datadir, struct pack *pack); int write_entry(struct archive *a, struct archive *w); int unpack(char *rootfs, char *datadir, struct pack *p); int install(char *rootfs, char *datadir, struct pack *p); -int delete_content(int fd); +int delete_node(char *path); +int delete_content(char *map, size_t size); int delete(const char *rootfs, const char *datadir, const char *name); char *argv0; @@ -141,23 +142,6 @@ base_name(char *path) /* - * Reads a line which is at least 'len' bytes long. It will load - * the line into "buf". The user has to ensure the addressed - * pointed to by 'buf' is big enough to contain the line. - */ -char * -lread(int fd, char *buf, size_t len) -{ - size_t i; - int r, c = 0; - while ((r = read(fd, &c, 1)) > 0 && c != '\n' && i < len) { - buf[i++] = c; - } - buf[i] = '\0'; - return r > 0 ? buf : NULL; -} - -/* * Check for collisions between the filesystem and the tarball */ int @@ -450,51 +434,80 @@ install(char *rootfs, char *datadir, struct pack *p) /* - * Delete all entries listed in the given file. - * if the entry doesn't exist, it will be ignored + * Deletes a node, be it a file or a directory. + * In case the node doesn't exists, we're done */ int -delete_content(int fd) +delete_node(char *path) { int r = 0; - char file[PATH_MAX] = ""; struct stat st; size_t len = 0; - if (lread(fd, file, PATH_MAX)) - if ((r = delete_content(fd)) < 0) - return r; - - /* remove trailing '\n' */ - if ((len = strnlen(file, PATH_MAX)) == 0) - return 0; - - file[len - 1] = 0; - len--; - + len = strnlen(path, PATH_MAX); /* remove potential trailing '/' */ - if (file[len - 1] == '/') { - file[len - 1] = 0; - len--; - } + if (path[len - 1] == '/') + path[--len] = 0; /* - * if file doesn't exist anymore, it's all good :) + * if path doesn't exist anymore, it's all good :) * we use lstat here so that dangling links can be delt with too */ - if (lstat(file, &st) < 0 && errno == ENOENT) + if (lstat(path, &st) < 0 && errno == ENOENT) return 0; - if (S_ISDIR(st.st_mode) && is_empty(file) == 0) { - if ((r = rmdir(file)) < 0) - perror(file); + if (verbose == 1) + printf("- %s\n", path); + + if (S_ISDIR(st.st_mode) && is_empty(path) == 0) { + if ((r = rmdir(path)) < 0) { + perror(path); + return r; + } + } + + if (!S_ISDIR(st.st_mode) && (r = unlink(path)) < 0) { + perror(path); return r; } - if (!S_ISDIR(st.st_mode) && (r = unlink(file)) < 0) - perror(file); + return 0; +} + +/* + * Delete all entries listed in the given file. + * if the entry doesn't exist, it will be ignored + */ +int +delete_content(char *map, size_t size) +{ + char *path = NULL; + size_t off; - return r; + if (size < 1) + return -1; + + do { + /* + * it is assumed here that the file is POSIX and thus that + * the last char will be \n. + * This might sound stupid; but this is what unpack() will do. + * We read the mmap file backward until we encounter \n or the + * beginning of the file. If it's an \n, we replace it by 0 and + * process to the deletion of the inode, either with rmdir or + * unlink. + */ + for (off=size-1; off>0 && map[off] != '\n'; off--); + map[off] = (off > 0 ? 0 : *map); + path = (off < size-1 ? &map[off] + 1 : NULL); + + if (path != NULL && strnlen(path, PATH_MAX) > 0) { + if (delete_node(path) < 0) + return ERR_DELETE; + } + } while (off > 0); + + return 0; } @@ -507,30 +520,35 @@ int delete(const char *rootfs, const char *datadir, const char *packname) { int fd; + char *addr = NULL; char tmp[PATH_MAX]; struct stat st; - snprintf(tmp, PATH_MAX, "%s/%s", datadir, packname); + snprintf(tmp, PATH_MAX, "%s/%s/files", datadir, packname); if (stat(tmp, &st) < 0 && errno == ENOENT) { fprintf(stderr, "%s: not installed\n", packname); return -1; } - - snprintf(tmp, PATH_MAX, "%s/%s/files", datadir, packname); if ((fd = open(tmp, O_RDONLY)) < 0) { perror(tmp); return ERR_DELETE; } + addr = mmap(0, st.st_size, PROT_READ|PROT_WRITE, MAP_PRIVATE, fd, 0); + if (addr == MAP_FAILED) { + perror(tmp); + close(fd); + } if (verbose == 1) printf("%s: deleting from %s\n", packname, rootfs); if (chdir(rootfs) < 0) { perror(rootfs); + close(fd); return ERR_DELETE; } /* ignore errors so everything gets deleted */ - if (delete_content(fd) < 0) { + if (delete_content(addr, st.st_size) < 0) { fprintf(stderr, "%s: cannot remove pack\n", packname); close(fd); return ERR_DELETE;