/* * Copyright (C) 2009 Andre Noll * * Licensed under the GPL v2. For licencing details see COPYING. */ /** * \file osltar.c 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 /** The columns of the osl table. */ enum osltar_columns { /** File name. */ OTC_NAME, /** File content. */ OTC_DATA, /** two. */ NUM_OT_COLUMNS }; /** * Compare two osl objects of string type. * * \param obj1 Pointer to the first object. * \param obj2 Pointer to the second object. * * \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. */ static 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. */ static 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; } static 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; } /** * The osltar main funcion. * * \param argc Usual argument count. * \param argv Usual argument vector. */ 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); }