]> git.tuebingen.mpg.de Git - osl.git/blob - examples/osltar/osltar.c
osltar: Minor cleanups.
[osl.git] / examples / osltar / osltar.c
1 /*
2  * Copyright (C) 2009 Andre Noll <maan@systemlinux.org>
3  *
4  * Licensed under the GPL v2. For licencing details see COPYING.
5  */
6
7 /**
8  * \file osltar.c A simple file archiver with many limitations. Do not use it.
9  * It is just an * example to illustrate programming with libosl.
10  */
11
12 #include <inttypes.h>
13 #include <osl.h>
14 #include <string.h>
15 #include <stdio.h>
16 #include <stdlib.h>
17 #include <sys/types.h>
18 #include <sys/stat.h>
19 #include <unistd.h>
20 #include <sys/types.h>
21 #include <dirent.h>
22 #include <errno.h>
23 #include <sys/mman.h>
24 #include <fcntl.h>
25
26 /** The columns of the osl table. */
27 enum osltar_columns {
28         /** File name. */
29         OTC_NAME,
30         /** File content. */
31         OTC_DATA,
32         /** two. */
33         NUM_OT_COLUMNS
34 };
35
36
37 /**
38  * We want doxygen to create documentation for certain static functions. So we
39  * use __static__ for such functions.
40  */
41 #define __static__ static
42
43 /**
44  * Compare two osl objects of string type.
45  *
46  * \param obj1 Pointer to the first object.
47  * \param obj2 Pointer to the second object.
48  *
49  * \return It returns an integer less than, equal to, or greater than zero if
50  * \a obj1 is found, respectively, to be less than, to match, or be greater than
51  * obj2.
52  *
53  * \sa strcmp(3), strncmp(3), osl_compare_func.
54  */
55 __static__ int string_compare(const struct osl_object *obj1, const struct osl_object *obj2)
56 {
57         const char *str1 = (const char *)obj1->data;
58         const char *str2 = (const char *)obj2->data;
59         return strcmp(str1, str2);
60 }
61
62 static struct osl_column_description tar_table_cols[] = {
63         [OTC_NAME] = {
64                 .storage_type = OSL_MAPPED_STORAGE,
65                 .storage_flags = OSL_RBTREE | OSL_UNIQUE,
66                 .name = "filename",
67                 .compare_function = string_compare,
68         },
69         [OTC_DATA] = {
70                 .storage_type = OSL_MAPPED_STORAGE,
71                 .storage_flags = 0,
72                 .name = "data",
73         },
74 };
75
76 static struct osl_table *table;
77
78 static struct osl_table_description tar_table_desc = {
79         .name = "tar_table",
80         .num_columns = NUM_OT_COLUMNS,
81         .flags = 0,
82         .column_descriptions = tar_table_cols,
83 };
84
85 static void print_usage_and_die(void)
86 {
87         fprintf(stderr, "usage:\n\tosltar c <db_dir> <data_dir>\n");
88         fprintf(stderr, "\tosltar x <db_dir> file1 [file2...]\n");
89         fprintf(stderr, "\tosltar t <db_dir>\n");
90         exit(EXIT_FAILURE);
91 }
92
93 /**
94  * Open a file and map it into memory.
95  */
96 static int mmap_full_file(const char *path, void **map,
97                 size_t *size)
98 {
99         int fd, ret, mmap_prot, mmap_flags;
100         struct stat file_status;
101
102         mmap_prot = PROT_READ;
103         mmap_flags = MAP_PRIVATE;
104         ret = open(path, O_RDONLY, 0);
105         if (ret < 0) {
106                 fprintf(stderr, "open: %s\n", strerror(errno));
107                 return ret;
108         }
109         fd = ret;
110         if (fstat(fd, &file_status) < 0) {
111                 ret = -1;
112                 fprintf(stderr, "fstat: %s\n", strerror(errno));
113                 goto out;
114         }
115         *size = file_status.st_size;
116         if (!*size) {
117                 fprintf(stderr, "can not add empty file: %s\n", path);
118                 goto out;
119         }
120         *map = mmap(NULL, *size, mmap_prot, mmap_flags, fd, 0);
121         if (*map == MAP_FAILED) {
122                 fprintf(stderr, "map failed: %s\n", path);
123                 *map = NULL;
124                 goto out;
125         }
126         ret = 1;
127 out:
128         close(fd);
129         return ret;
130 }
131
132
133 static int add_file(char *name)
134 {
135         int ret;
136         struct osl_object objs[NUM_OT_COLUMNS] = {
137                 [OTC_NAME] = {
138                         .data = name,
139                         .size = strlen(name) + 1
140                 },
141         };
142         printf("%s\n", name);
143         ret = mmap_full_file(name, &objs[OTC_DATA].data,
144                 &objs[OTC_DATA].size);
145         if (ret < 0)
146                 return ret;
147         return osl_add_row(table, objs);
148 }
149
150 static int populate_table(const char *dirname)
151 {
152         struct dirent *entry;
153         DIR *dir;
154         int ret = chdir(dirname);
155
156         if (ret < 0) {
157                 fprintf(stderr, "chdir: %s\n", strerror(errno));
158                 exit(EXIT_FAILURE);
159         }
160         dir = opendir(".");
161         if (!dir) {
162                 fprintf(stderr, "opendir: %s\n", strerror(errno));
163                 exit(EXIT_FAILURE);
164         }
165         while ((entry = readdir(dir))) {
166                 mode_t m;
167                 struct stat s;
168
169                 if (!strcmp(entry->d_name, "."))
170                         continue;
171                 if (!strcmp(entry->d_name, ".."))
172                         continue;
173                 if (lstat(entry->d_name, &s) == -1)
174                         continue;
175                 m = s.st_mode;
176                 if (!S_ISREG(m))
177                         continue;
178                 ret = add_file(entry->d_name);
179                 if (ret < 0)
180                         goto out;
181         }
182         ret = 1;
183 out:
184         closedir(dir);
185         return ret;
186 }
187
188 static int com_create(int argc, char **argv)
189 {
190         struct stat statbuf;
191         int ret;
192
193         if (argc != 3)
194                 print_usage_and_die();
195         if (lstat(argv[2], &statbuf) == -1) {
196                 fprintf(stderr, "no such dir: %s\n", argv[2]);
197                 exit(EXIT_FAILURE);
198         }
199         if (!S_ISDIR(statbuf.st_mode)) {
200                 fprintf(stderr, "not a dir: %s\n", argv[2]);
201                 exit(EXIT_FAILURE);
202         }
203         tar_table_desc.dir = argv[1];
204         ret = osl_create_table(&tar_table_desc);
205         if (ret < 0) {
206                 fprintf(stderr, "failed to create table\n");
207                 exit(EXIT_FAILURE);
208
209         }
210         ret = osl_open_table(&tar_table_desc, &table);
211         if (ret < 0) {
212                 fprintf(stderr, "osl_open_table: %s\n", osl_strerror(-ret));
213                 exit(EXIT_FAILURE);
214         }
215         ret = populate_table(argv[2]);
216         osl_close_table(table, OSL_MARK_CLEAN);
217         return ret < 0? EXIT_FAILURE : EXIT_SUCCESS;
218 }
219
220 /**
221  * Write the whole buffer to a file descriptor.
222  */
223 ssize_t write_all(int fd, const void *buf, size_t size)
224 {
225         const char *b = buf;
226         while (size) {
227                 ssize_t ret = write(fd, b, size);
228                 if (ret < 0) {
229                         fprintf(stderr, "open: %s\n", strerror(errno));
230                         return ret;
231
232                 }
233                 b += ret;
234                 size -= ret;
235         }
236         return 1;
237 }
238
239 /**
240  * Open a file, write the given buffer and close the file.
241  */
242 static int write_file(const char *filename, const void *buf, size_t size)
243 {
244         int ret, fd;
245
246         ret = open(filename, O_WRONLY | O_CREAT | O_EXCL, 0644);
247         if (ret < 0) {
248                 fprintf(stderr, "open: %s\n", strerror(errno));
249                 return ret;
250
251         }
252         fd = ret;
253         printf("%s\n", filename);
254         ret = write_all(fd, buf, size);
255         if (ret < 0)
256                 goto out;
257         ret = 1;
258 out:
259         close(fd);
260         return ret;
261 }
262
263 static int extract_file(char *name)
264 {
265         int ret;
266         struct osl_row *row;
267         struct osl_object obj = {.data = name, .size = strlen(name) + 1};
268
269         ret = osl_get_row(table, OTC_NAME, &obj, &row);
270         if (ret < 0) {
271                 fprintf(stderr, "osl_get_row(%s): %s\n", name,
272                         osl_strerror(-ret));
273                 return ret;
274         }
275         ret = osl_get_object(table, row, OTC_DATA, &obj);
276         if (ret < 0) {
277                 fprintf(stderr, "osl_get_object: %s\n", osl_strerror(-ret));
278                 return ret;
279         }
280         return write_file(name, obj.data, obj.size);
281 }
282
283 static int com_extract(int argc, char **argv)
284 {
285         int i, ret;
286
287         if (argc < 3)
288                 print_usage_and_die();
289         tar_table_desc.dir = argv[1];
290         ret = osl_open_table(&tar_table_desc, &table);
291         if (ret < 0) {
292                 fprintf(stderr, "osl_open_table: %s\n", osl_strerror(-ret));
293                 exit(EXIT_FAILURE);
294
295         }
296         for (i = 2; i < argc; i++) {
297                 ret = extract_file(argv[i]);
298                 if (ret < 0)
299                         goto out;
300         }
301 out:
302         osl_close_table(table, OSL_MARK_CLEAN);
303         return ret;
304 }
305
306 static int list_entry(struct osl_row *row, void *data)
307 {
308         struct osl_object obj;
309         int ret = osl_get_object(table, row, OTC_NAME, &obj);
310         if (ret < 0) {
311                 fprintf(stderr, "osl_get_object: %s\n", osl_strerror(-ret));
312                 return ret;
313         }
314         printf("%s\n", (char *)obj.data);
315         return 1;
316 }
317
318 static int com_list(int argc, char **argv)
319 {
320         int ret;
321
322         if (argc != 2)
323                 print_usage_and_die();
324         tar_table_desc.dir = argv[1];
325         ret = osl_open_table(&tar_table_desc, &table);
326         if (ret < 0) {
327                 fprintf(stderr, "osl_open_table: %s\n", osl_strerror(-ret));
328                 exit(EXIT_FAILURE);
329
330         }
331         ret = osl_rbtree_loop(table, OTC_NAME, NULL, list_entry);
332         osl_close_table(table, OSL_MARK_CLEAN);
333         return ret;
334 }
335
336 /**
337  * The osltar main funcion.
338  *
339  * \param argc Usual argument count.
340  * \param argv Usual argument vector.
341  */
342 int main(int argc, char **argv)
343 {
344         if (argc < 2)
345                 print_usage_and_die();
346         if (!strcmp(argv[1], "c"))
347                 return com_create(argc - 1, argv + 1);
348         if (!strcmp(argv[1], "x"))
349                 return com_extract(argc - 1, argv + 1);
350         if (!strcmp(argv[1], "t"))
351                 return com_list(argc - 1, argv + 1);
352         print_usage_and_die();
353         exit(EXIT_FAILURE);
354
355 }