1 /*
2 * Copyright � 2007 Alistair Crooks. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * 3. The name of the author may not be used to endorse or promote
13 * products derived from this software without specific prior written
14 * permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
17 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
22 * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
24 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
25 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
26 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28 #include <sys/types.h>
29
30 #include <db.h>
31 #include <err.h>
32 #include <errno.h>
33 #include <fcntl.h>
34 #include <fuse.h>
35 #include <stdio.h>
36 #include <stdlib.h>
37 #include <string.h>
38 #include <unistd.h>
39
40 enum {
41 BigEndian = 4321,
42 LittleEndian = 1234
43 };
44
45 static struct stat dbst; /* stat info of database file */
46 static BTREEINFO bt; /* btree information */
47 static int verbose; /* how chatty are we? */
48 static DB *db; /* data base operations struct */
49
50 /* perform the stat operation */
51 /* if this is the root, then just synthesise the data */
52 /* otherwise, retrieve the data, and be sure to fill in the size */
53 /* we use the mtime of the database file for each of the records */
54 static int
dbfs_getattr(const char * path,struct stat * st)55 dbfs_getattr(const char *path, struct stat *st)
56 {
57 int res = 0;
58 DBT k;
59 DBT v;
60
61 (void) memset(st, 0x0, sizeof(*st));
62 if (strcmp(path, "/") == 0) {
63 st->st_mode = S_IFDIR | 0755;
64 st->st_nlink = 2;
65 } else {
66 k.size = strlen(k.data = __UNCONST(path + 1));
67 if ((*db->seq)(db, &k, &v, R_CURSOR) != 0) {
68 return -ENOENT;
69 }
70 st->st_mode = S_IFREG | 0444;
71 st->st_nlink = 1;
72 st->st_size = v.size;
73 st->st_mtime = dbst.st_mtime;
74 st->st_atime = dbst.st_atime;
75 st->st_ctime = dbst.st_ctime;
76 st->st_uid = dbst.st_uid;
77 st->st_gid = dbst.st_gid;
78 }
79 return res;
80 }
81
82 /* readdir operation */
83 /* run through the database file, returning records by key */
84 static int
dbfs_readdir(const char * path,void * buf,fuse_fill_dir_t filler,off_t offset,struct fuse_file_info * fi)85 dbfs_readdir(const char *path, void *buf, fuse_fill_dir_t filler,
86 off_t offset, struct fuse_file_info * fi)
87 {
88 static int ret;
89 static DBT k;
90 int flag;
91 DBT v;
92 (void) fi;
93
94 if (offset == 0) {
95 (void) memset(&k, 0x0, sizeof(k));
96 (void) filler(buf, ".", NULL, 0);
97 (void) filler(buf, "..", NULL, 0);
98 flag = R_FIRST;
99 ret = 0;
100 } else {
101 flag = R_CURSOR;
102 }
103 if (ret != 0) {
104 return 0;
105 }
106 for ( ; (ret = (*db->seq)(db, &k, &v, flag)) == 0 ; flag = R_NEXT) {
107 if (filler(buf, k.data, NULL, 0) != 0) {
108 return 0;
109 }
110 }
111 return 0;
112 }
113
114 /* open the file in the file system */
115 /* use seq method to get the record - get doesn't seem to work */
116 static int
dbfs_open(const char * path,struct fuse_file_info * fi)117 dbfs_open(const char *path, struct fuse_file_info * fi)
118 {
119 DBT k;
120 DBT v;
121
122 k.size = strlen(k.data = __UNCONST(path));
123 if ((*db->get)(db, &k, &v, 0) != 0) {
124 return -ENOENT;
125 }
126
127 if ((fi->flags & 3) != O_RDONLY) {
128 return -EACCES;
129 }
130 return 0;
131 }
132
133 /* read the file's contents in the file system */
134 /* use seq method to get the record - get doesn't seem to work */
135 static int
dbfs_read(const char * path,char * buf,size_t size,off_t offset,struct fuse_file_info * fi)136 dbfs_read(const char *path, char *buf, size_t size, off_t offset,
137 struct fuse_file_info * fi)
138 {
139 size_t len;
140 DBT k;
141 DBT v;
142 (void) fi;
143
144 k.size = strlen(k.data = __UNCONST(path + 1));
145 if ((*db->seq)(db, &k, &v, R_CURSOR) != 0) {
146 return -ENOENT;
147 }
148 len = v.size;
149 if (offset < len) {
150 if (offset + size > len) {
151 size = len - offset;
152 }
153 (void) memcpy(buf, (char *) v.data + offset, size);
154 buf[size - 1] = '\n';
155 } else {
156 size = 0;
157 }
158 return size;
159 }
160
161 /* fill in the statvfs struct */
162 static int
dbfs_statfs(const char * path,struct statvfs * st)163 dbfs_statfs(const char *path, struct statvfs *st)
164 {
165 (void) memset(st, 0x0, sizeof(*st));
166 st->f_blocks = dbst.st_size / dbst.st_blksize;
167 st->f_bsize = st->f_frsize = st->f_iosize = dbst.st_blksize;
168 st->f_owner = dbst.st_uid;
169 st->f_files = 1;
170 return 0;
171 }
172
173 /* operations struct */
174 static struct fuse_operations dbfs_oper = {
175 .getattr = dbfs_getattr,
176 .readdir = dbfs_readdir,
177 .open = dbfs_open,
178 .read = dbfs_read,
179 .statfs = dbfs_statfs
180 };
181
182 int
main(int argc,char ** argv)183 main(int argc, char **argv)
184 {
185 int i;
186
187 while ((i = getopt(argc, argv, "v")) != -1) {
188 switch(i) {
189 case 'v':
190 verbose = 1;
191 break;
192 }
193 }
194 if (stat(argv[optind], &dbst) != 0) {
195 err(EXIT_FAILURE, "can't stat `%s'", argv[optind]);
196 }
197 bt.lorder = LittleEndian;
198 if ((db = dbopen(argv[optind], O_RDONLY, 0666, DB_BTREE, &bt)) == NULL) {
199 bt.lorder = BigEndian;
200 db = dbopen(argv[optind], O_RDONLY, 0666, DB_BTREE, &bt);
201 if (verbose) {
202 printf("Database not little endian - trying big endian now\n");
203 }
204 }
205 if (db == NULL) {
206 err(EXIT_FAILURE, "can't open db `%s'", argv[optind]);
207 }
208 return fuse_main(argc, argv, &dbfs_oper);
209 }
210