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