xref: /netbsd-src/share/examples/refuse/dbfs/dbfs.c (revision 7f4005e3b07707dc08553709c5a1fd18da67d357)
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