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 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 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 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 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 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 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