Add two examples to illiustrate programming with libosl.
[osl.git] / examples / osltar / osltar.c
diff --git a/examples/osltar/osltar.c b/examples/osltar/osltar.c
new file mode 100644 (file)
index 0000000..0b2263a
--- /dev/null
@@ -0,0 +1,341 @@
+/*
+ * Copyright (C) 2009 Andre Noll <maan@systemlinux.org>
+ *
+ * Licensed under the GPL v2. For licencing details see COPYING.
+ */
+
+/*
+ * A simple file archiver with many limitations. Do not use it. It is just an
+ * example to illustrate programming with libosl.
+ */
+
+#include <inttypes.h>
+#include <osl.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <dirent.h>
+#include <errno.h>
+#include <sys/mman.h>
+#include <fcntl.h>
+
+enum osltar_columns {
+       OTC_NAME,
+       OTC_DATA,
+       NUM_OT_COLUMNS
+};
+
+/**
+ * Compare two osl objects of string type.
+ *
+ * \param obj1 Pointer to the first object.
+ * \param obj2 Pointer to the second object.
+ *
+ * In any case, only \p MIN(obj1->size, obj2->size) characters of each string
+ * are taken into account.
+ *
+ * \return It returns an integer less than, equal to, or greater than zero if
+ * \a obj1 is found, respectively, to be less than, to match, or be greater than
+ * obj2.
+ *
+ * \sa strcmp(3), strncmp(3), osl_compare_func.
+ */
+int string_compare(const struct osl_object *obj1, const struct osl_object *obj2)
+{
+       const char *str1 = (const char *)obj1->data;
+       const char *str2 = (const char *)obj2->data;
+       return strcmp(str1, str2);
+}
+
+static struct osl_column_description tar_table_cols[] = {
+       [OTC_NAME] = {
+               .storage_type = OSL_MAPPED_STORAGE,
+               .storage_flags = OSL_RBTREE | OSL_UNIQUE,
+               .name = "filename",
+               .compare_function = string_compare,
+       },
+       [OTC_DATA] = {
+               .storage_type = OSL_MAPPED_STORAGE,
+               .storage_flags = 0,
+               .name = "data",
+       },
+};
+
+static struct osl_table *table;
+
+static struct osl_table_description tar_table_desc = {
+       .name = "tar_table",
+       .num_columns = NUM_OT_COLUMNS,
+       .flags = 0,
+       .column_descriptions = tar_table_cols,
+};
+
+static void print_usage_and_die(void)
+{
+       fprintf(stderr, "usage:\n\tosltar c <db_dir> <data_dir>\n");
+       fprintf(stderr, "\tosltar x <db_dir> file1 [file2...]\n");
+       fprintf(stderr, "\tosltar t <db_dir>\n");
+       exit(EXIT_FAILURE);
+}
+
+/**
+ * Open a file and map it into memory.
+ */
+static int mmap_full_file(const char *path, void **map,
+               size_t *size)
+{
+       int fd, ret, mmap_prot, mmap_flags;
+       struct stat file_status;
+
+       mmap_prot = PROT_READ;
+       mmap_flags = MAP_PRIVATE;
+       ret = open(path, O_RDONLY, 0);
+       if (ret < 0) {
+               fprintf(stderr, "open: %s\n", strerror(errno));
+               return ret;
+       }
+       fd = ret;
+       if (fstat(fd, &file_status) < 0) {
+               ret = -1;
+               fprintf(stderr, "fstat: %s\n", strerror(errno));
+               goto out;
+       }
+       *size = file_status.st_size;
+       if (!*size) {
+               fprintf(stderr, "can not add empty file: %s\n", path);
+               goto out;
+       }
+       *map = mmap(NULL, *size, mmap_prot, mmap_flags, fd, 0);
+       if (*map == MAP_FAILED) {
+               fprintf(stderr, "map failed: %s\n", path);
+               *map = NULL;
+               goto out;
+       }
+       ret = 1;
+out:
+       close(fd);
+       return ret;
+}
+
+
+static int add_file(char *name)
+{
+       int ret;
+       struct osl_object objs[NUM_OT_COLUMNS] = {
+               [OTC_NAME] = {
+                       .data = name,
+                       .size = strlen(name) + 1
+               },
+       };
+       printf("%s\n", name);
+       ret = mmap_full_file(name, &objs[OTC_DATA].data,
+               &objs[OTC_DATA].size);
+       if (ret < 0)
+               return ret;
+       return osl_add_row(table, objs);
+}
+
+static int populate_table(const char *dirname)
+{
+       struct dirent *entry;
+       DIR *dir;
+       int ret = chdir(dirname);
+
+       if (ret < 0) {
+               fprintf(stderr, "chdir: %s\n", strerror(errno));
+               exit(EXIT_FAILURE);
+       }
+       dir = opendir(".");
+       if (!dir) {
+               fprintf(stderr, "opendir: %s\n", strerror(errno));
+               exit(EXIT_FAILURE);
+       }
+       while ((entry = readdir(dir))) {
+               mode_t m;
+               struct stat s;
+
+               if (!strcmp(entry->d_name, "."))
+                       continue;
+               if (!strcmp(entry->d_name, ".."))
+                       continue;
+               if (lstat(entry->d_name, &s) == -1)
+                       continue;
+               m = s.st_mode;
+               if (!S_ISREG(m))
+                       continue;
+               ret = add_file(entry->d_name);
+               if (ret < 0)
+                       goto out;
+       }
+       ret = 1;
+out:
+       closedir(dir);
+       return ret;
+}
+
+static int com_create(int argc, char **argv)
+{
+       struct stat statbuf;
+       int ret;
+
+       if (argc != 3)
+               print_usage_and_die();
+       if (lstat(argv[2], &statbuf) == -1) {
+               fprintf(stderr, "no such dir: %s\n", argv[2]);
+               exit(EXIT_FAILURE);
+       }
+       if (!S_ISDIR(statbuf.st_mode)) {
+               fprintf(stderr, "not a dir: %s\n", argv[2]);
+               exit(EXIT_FAILURE);
+       }
+       tar_table_desc.dir = argv[1];
+       ret = osl_create_table(&tar_table_desc);
+       if (ret < 0) {
+               fprintf(stderr, "failed to create table\n");
+               exit(EXIT_FAILURE);
+
+       }
+       ret = osl_open_table(&tar_table_desc, &table);
+       if (ret < 0) {
+               fprintf(stderr, "osl_open_table: %s\n", osl_strerror(-ret));
+               exit(EXIT_FAILURE);
+       }
+       ret = populate_table(argv[2]);
+       osl_close_table(table, OSL_MARK_CLEAN);
+       return ret < 0? EXIT_FAILURE : EXIT_SUCCESS;
+}
+
+/**
+ * Write the whole buffer to a file descriptor.
+ */
+ssize_t write_all(int fd, const void *buf, size_t size)
+{
+       const char *b = buf;
+       while (size) {
+               ssize_t ret = write(fd, b, size);
+               if (ret < 0) {
+                       fprintf(stderr, "open: %s\n", strerror(errno));
+                       return ret;
+
+               }
+               b += ret;
+               size -= ret;
+       }
+       return 1;
+}
+
+/**
+ * Open a file, write the given buffer and close the file.
+ */
+static int write_file(const char *filename, const void *buf, size_t size)
+{
+       int ret, fd;
+
+       ret = open(filename, O_WRONLY | O_CREAT | O_EXCL, 0644);
+       if (ret < 0) {
+               fprintf(stderr, "open: %s\n", strerror(errno));
+               return ret;
+
+       }
+       fd = ret;
+       printf("%s\n", filename);
+       ret = write_all(fd, buf, size);
+       if (ret < 0)
+               goto out;
+       ret = 1;
+out:
+       close(fd);
+       return ret;
+}
+
+static int extract_file(char *name)
+{
+       int ret;
+       struct osl_row *row;
+       struct osl_object obj = {.data = name, .size = strlen(name) + 1};
+
+       ret = osl_get_row(table, OTC_NAME, &obj, &row);
+       if (ret < 0) {
+               fprintf(stderr, "osl_get_row(%s): %s\n", name,
+                       osl_strerror(-ret));
+               return ret;
+       }
+       ret = osl_get_object(table, row, OTC_DATA, &obj);
+       if (ret < 0) {
+               fprintf(stderr, "osl_get_object: %s\n", osl_strerror(-ret));
+               return ret;
+       }
+       return write_file(name, obj.data, obj.size);
+}
+
+static int com_extract(int argc, char **argv)
+{
+       int i, ret;
+
+       if (argc < 3)
+               print_usage_and_die();
+       tar_table_desc.dir = argv[1];
+       ret = osl_open_table(&tar_table_desc, &table);
+       if (ret < 0) {
+               fprintf(stderr, "osl_open_table: %s\n", osl_strerror(-ret));
+               exit(EXIT_FAILURE);
+
+       }
+       for (i = 2; i < argc; i++) {
+               ret = extract_file(argv[i]);
+               if (ret < 0)
+                       goto out;
+       }
+out:
+       osl_close_table(table, OSL_MARK_CLEAN);
+       return ret;
+}
+
+static int list_entry(struct osl_row *row, void *data)
+{
+       struct osl_object obj;
+       int ret = osl_get_object(table, row, OTC_NAME, &obj);
+       if (ret < 0) {
+               fprintf(stderr, "osl_get_object: %s\n", osl_strerror(-ret));
+               return ret;
+       }
+       printf("%s\n", (char *)obj.data);
+       return 1;
+}
+
+int com_list(int argc, char **argv)
+{
+       int ret;
+
+       if (argc != 2)
+               print_usage_and_die();
+       tar_table_desc.dir = argv[1];
+       ret = osl_open_table(&tar_table_desc, &table);
+       if (ret < 0) {
+               fprintf(stderr, "osl_open_table: %s\n", osl_strerror(-ret));
+               exit(EXIT_FAILURE);
+
+       }
+       ret = osl_rbtree_loop(table, OTC_NAME, NULL, list_entry);
+       osl_close_table(table, OSL_MARK_CLEAN);
+       return ret;
+}
+
+int main(int argc, char **argv)
+{
+       if (argc < 2)
+               print_usage_and_die();
+       if (!strcmp(argv[1], "c"))
+               return com_create(argc - 1, argv + 1);
+       if (!strcmp(argv[1], "x"))
+               return com_extract(argc - 1, argv + 1);
+       if (!strcmp(argv[1], "t"))
+               return com_list(argc - 1, argv + 1);
+       print_usage_and_die();
+       exit(EXIT_FAILURE);
+
+}