xref: /netbsd-src/share/examples/refuse/id3fs/id3fs.c (revision cfb41894f86927de5bfbcbb7328670af96fd1aa7)
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 #include "virtdir.h"
41 #include "defs.h"
42 
43 static char		*prefix; /* where the music is */
44 static int		 verbose; /* how chatty are we? */
45 
46 static BTREEINFO	 bt;
47 
48 static virtdir_t	 id3;
49 
50 
51 /* perform the stat operation */
52 /* if this is the root, then just synthesise the data */
53 /* otherwise, retrieve the data, and be sure to fill in the size */
54 static int
id3fs_getattr(const char * path,struct stat * st)55 id3fs_getattr(const char *path, struct stat *st)
56 {
57 	virt_dirent_t	*ep;
58 
59 	if (strcmp(path, "/") == 0) {
60 		(void) memset(st, 0x0, sizeof(*st));
61 		st->st_mode = S_IFDIR | 0755;
62 		st->st_nlink = 2;
63 		return 0;
64 	}
65 	if ((ep = virtdir_find(&id3, path, strlen(path))) == NULL) {
66 		return -ENOENT;
67 	}
68 	switch(ep->type) {
69 	case 'f':
70 		(void) memcpy(st, &id3.file, sizeof(*st));
71 		break;
72 	case 'd':
73 		(void) memcpy(st, &id3.dir, sizeof(*st));
74 		break;
75 	case 'l':
76 		(void) memcpy(st, &id3.lnk, sizeof(*st));
77 		st->st_size = ep->tgtlen;
78 		break;
79 	}
80 	return 0;
81 }
82 
83 /* readdir operation */
84 static int
id3fs_readdir(const char * path,void * buf,fuse_fill_dir_t filler,off_t offset,struct fuse_file_info * fi)85 id3fs_readdir(const char *path, void *buf, fuse_fill_dir_t filler,
86 	      off_t offset, struct fuse_file_info * fi)
87 {
88 	virt_dirent_t	*dp;
89 	VIRTDIR		*dirp;
90 
91 	if ((dirp = openvirtdir(&id3, path)) == NULL) {
92 		return 0;
93 	}
94 	filler(buf, ".", NULL, 0);
95 	filler(buf, "..", NULL, 0);
96 	while ((dp = readvirtdir(dirp)) != NULL) {
97 		filler(buf, dp->d_name, NULL, 0);
98 	}
99 	closevirtdir(dirp);
100 	return 0;
101 }
102 
103 /* open the file in the file system */
104 static int
id3fs_open(const char * path,struct fuse_file_info * fi)105 id3fs_open(const char *path, struct fuse_file_info * fi)
106 {
107 	return 0;
108 }
109 
110 /* read the file's contents in the file system */
111 static int
id3fs_read(const char * path,char * buf,size_t size,off_t offset,struct fuse_file_info * fi)112 id3fs_read(const char *path, char *buf, size_t size, off_t offset,
113 	   struct fuse_file_info * fi)
114 {
115 	return 0;
116 }
117 
118 /* fill in the statvfs struct */
119 static int
id3fs_statfs(const char * path,struct statvfs * st)120 id3fs_statfs(const char *path, struct statvfs *st)
121 {
122 	(void) memset(st, 0x0, sizeof(*st));
123 	return 0;
124 }
125 
126 /* read the symbolic link */
127 static int
id3fs_readlink(const char * path,char * buf,size_t size)128 id3fs_readlink(const char *path, char *buf, size_t size)
129 {
130 	virt_dirent_t	*ep;
131 
132 	if ((ep = virtdir_find(&id3, path, strlen(path))) == NULL) {
133 		return -ENOENT;
134 	}
135 	if (ep->tgt == NULL) {
136 		return -ENOENT;
137 	}
138 	(void) strlcpy(buf, ep->tgt, size);
139 	return 0;
140 }
141 
142 /* operations struct */
143 static struct fuse_operations id3fs_oper = {
144 	.getattr = id3fs_getattr,
145 	.readlink = id3fs_readlink,
146 	.readdir = id3fs_readdir,
147 	.open = id3fs_open,
148 	.read = id3fs_read,
149 	.statfs = id3fs_statfs
150 };
151 
152 /* build up a fuse_tree from the information in the database */
153 static void
build_id3_tree(DB * db,virtdir_t * tp)154 build_id3_tree(DB *db, virtdir_t *tp)
155 {
156 	struct stat	 dir;
157 	struct stat	 f;
158 	const char	*d;
159 	char		 name[MAXPATHLEN];
160 	char		*slash;
161 	char		*key;
162 	char		*val;
163 	int		 flag;
164 	DBT		 k;
165 	DBT		 v;
166 
167 	(void) stat(".", &dir);
168 	(void) memcpy(&f, &dir, sizeof(f));
169 	f.st_mode = S_IFREG | 0644;
170 	(void) memset(&k, 0x0, sizeof(k));
171 	(void) memset(&v, 0x0, sizeof(v));
172 	for (flag = R_FIRST ; (*db->seq)(db, &k, &v, flag) == 0 ; flag = R_NEXT) {
173 		key = (char *) k.data;
174 		switch (*key) {
175 		case 'a':
176 			d = "/artists";
177 			break;
178 		case 'g':
179 			d = "/genre";
180 			break;
181 		case 'y':
182 			d = "/year";
183 			break;
184 		default:
185 			continue;
186 		}
187 		val = (char *) v.data;
188 		if ((slash = strrchr(key, '/')) == NULL) {
189 			slash = key;
190 		}
191 		slash += 1;
192 		/* add the symbolic link in that directory */
193 		(void) snprintf(name, sizeof(name), "%s/%s/%s", d, val, slash);
194 		if (!virtdir_find(tp, name, strlen(name))) {
195 			virtdir_add(tp, name, strlen(name), 'l', key + 1,
196 				strlen(key + 1));
197 		}
198 	}
199 }
200 
201 int
main(int argc,char ** argv)202 main(int argc, char **argv)
203 {
204 	char	 name[MAXPATHLEN];
205 	int	 i;
206 	DB	*db;
207 
208 	while ((i = getopt(argc, argv, "p:v")) != -1) {
209 		switch(i) {
210 		case 'p':
211 			prefix = optarg;
212 			break;
213 		case 'v':
214 			verbose = 1;
215 			break;
216 		}
217 	}
218 	bt.lorder = 4321;
219 	(void) snprintf(name, sizeof(name), "%s/%s", (prefix) ? prefix : "/usr/music", ".id3.db");
220 	if ((db = dbopen(name, O_RDONLY, 0666, DB_BTREE, &bt)) == NULL) {
221 		warn("null id3 database");
222 	}
223 	build_id3_tree(db, &id3);
224 	return fuse_main(argc, argv, &id3fs_oper, NULL);
225 }
226