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