tUse mmap to read metadata files in delete() - pm - barely a pack manager
(HTM) git clone git://z3bra.org/pm
(DIR) Log
(DIR) Files
(DIR) Refs
(DIR) README
(DIR) LICENSE
---
(DIR) commit c293e2c77808dc0c1f1b292111dd18dd19280a46
(DIR) parent d66413a9f2f5c91fb4f7e7b5e147e71f6478a881
(HTM) Author: z3bra <willyatmailoodotorg>
Date: Sat, 30 Jan 2016 15:24:02 +0100
Use mmap to read metadata files in delete()
Diffstat:
M pm.c | 118 ++++++++++++++++++-------------
1 file changed, 68 insertions(+), 50 deletions(-)
---
(DIR) diff --git a/pm.c b/pm.c
t@@ -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>
t@@ -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);
t@@ -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;
t@@ -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
t@@ -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;
}
t@@ -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;