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