X-Git-Url: http://git.tuebingen.mpg.de/?p=osl.git;a=blobdiff_plain;f=examples%2Fosltar%2Fosltar.c;fp=examples%2Fosltar%2Fosltar.c;h=0b2263a072206a09b7c7a183a5bc3388b3a7931b;hp=0000000000000000000000000000000000000000;hb=e7a4c2cc4b391e0e30ea8f4cd8c2ba4614248550;hpb=cff86feb29f48a2d56475a0261e6fcbfcee4cbbc diff --git a/examples/osltar/osltar.c b/examples/osltar/osltar.c new file mode 100644 index 0000000..0b2263a --- /dev/null +++ b/examples/osltar/osltar.c @@ -0,0 +1,341 @@ +/* + * Copyright (C) 2009 Andre Noll + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +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 \n"); + fprintf(stderr, "\tosltar x file1 [file2...]\n"); + fprintf(stderr, "\tosltar t \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); + +}