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