Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Newer
Older
100644 304 lines (264 sloc) 10.132 kb
98a57256 »
2012-09-08 o Start implementation. Just a basic forwarding filesystem for
1 // Copyright (C) 2012 Henner Zeller <h.zeller@acm.org>
2 //
3 // This program is free software; you can redistribute it and/or modify
4 // it under the terms of the GNU General Public License as published by
5 // the Free Software Foundation; either version 3 of the License, or
6 // (at your option) any later version.
7 //
8 // This program is distributed in the hope that it will be useful,
9 // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 // GNU General Public License for more details.
12 //
13 // You should have received a copy of the GNU General Public License
14 // along with this program. If not, see <http://www.gnu.org/licenses/>.
15
16 // Use latest version.
17 #define FUSE_USE_VERSION 26
18 #include <fuse.h>
a9d3e538 »
2012-09-15 o Found a project name: "Folve". Some renamings because of that.
19
98a57256 »
2012-09-08 o Start implementation. Just a basic forwarding filesystem for
20 #include <dirent.h>
21 #include <errno.h>
b6988530 »
2012-09-15 o README updates.
22 #include <fcntl.h>
98a57256 »
2012-09-08 o Start implementation. Just a basic forwarding filesystem for
23 #include <limits.h>
b6988530 »
2012-09-15 o README updates.
24 #include <stdio.h>
98a57256 »
2012-09-08 o Start implementation. Just a basic forwarding filesystem for
25 #include <stdlib.h>
b6988530 »
2012-09-15 o README updates.
26 #include <string.h>
27 #include <sys/stat.h>
28 #include <sys/time.h>
49eca7f9 »
2012-09-16 o add syslog as preparation for parameter handling.
29 #include <syslog.h>
b6988530 »
2012-09-15 o README updates.
30 #include <unistd.h>
98a57256 »
2012-09-08 o Start implementation. Just a basic forwarding filesystem for
31
a9d3e538 »
2012-09-15 o Found a project name: "Folve". Some renamings because of that.
32 #include "folve-filesystem.h"
8d1fbe7c »
2012-09-13 o Move fuse-convolve.c to fuse-convolve.cc. Make filter-interface
33 #include "status-server.h"
e9c07dd6 »
2012-09-08 o add documentation
34
6c6dedb8 »
2012-09-16 o Some readme tweaks and readability improvements.
35 // Compilation unit variables to communicate with the fuse callbacks.
27c44cd1 »
2012-09-17 o Use fuse option handling to extract our flags and options.
36 static struct FolveRuntime {
ee675fea »
2012-09-17 o Provide a way to select between different filter diretories.
37 FolveRuntime() : fs(NULL), mount_point(NULL), status_port(-1) {}
0330f769 »
2012-09-16 o Only start status server after we're daemonized, otherwise
38 FolveFilesystem *fs;
27c44cd1 »
2012-09-17 o Use fuse option handling to extract our flags and options.
39 const char *mount_point;
0330f769 »
2012-09-16 o Only start status server after we're daemonized, otherwise
40 int status_port;
ee675fea »
2012-09-17 o Provide a way to select between different filter diretories.
41 } folve_rt;
98a57256 »
2012-09-08 o Start implementation. Just a basic forwarding filesystem for
42
7c7bda6f »
2012-09-10 o attempt to create a sndfile for every file, if that fails, fall
43 static int has_suffix_string (const char *str, const char *suffix) {
44 if (!str || !suffix)
45 return 0;
46 size_t str_len = strlen(str);
47 size_t suffix_len = strlen(suffix);
48 if (suffix_len > str_len)
49 return 0;
50 return strncmp(str + str_len - suffix_len, suffix, suffix_len) == 0;
51 }
52
53 static char *concat_path(char *buf, const char *a, const char *b) {
54 strcpy(buf, a);
55 strcat(buf, b);
56 return buf;
57 }
58
98a57256 »
2012-09-08 o Start implementation. Just a basic forwarding filesystem for
59 // Given a relative path from the root of the mounted file-system, get the
60 // original file from the source filesystem.
0aee3bb1 »
2012-09-15 o Show base dir that is mounted.
61 // TODO(hzeller): move the ogg.fuse.flac logic into convolver-filesystem.
98a57256 »
2012-09-08 o Start implementation. Just a basic forwarding filesystem for
62 static const char *assemble_orig_path(char *buf, const char *path) {
ee675fea »
2012-09-17 o Provide a way to select between different filter diretories.
63 char *result = concat_path(buf, folve_rt.fs->underlying_dir().c_str(), path);
7c7bda6f »
2012-09-10 o attempt to create a sndfile for every file, if that fails, fall
64 static const char magic_ogg_rewrite[] = ".ogg.fuse.flac";
65 if (has_suffix_string(result, magic_ogg_rewrite)) {
66 *(result + strlen(result) - strlen(".fuse.flac")) = '\0';
67 }
68 return result;
98a57256 »
2012-09-08 o Start implementation. Just a basic forwarding filesystem for
69 }
70
7c7bda6f »
2012-09-10 o attempt to create a sndfile for every file, if that fails, fall
71 // Essentially lstat(). Just forward to the original filesystem (this
73093dcf »
2012-09-08 o Keep open file-descriptor.
72 // will by lying: our convolved files are of different size...)
0330f769 »
2012-09-16 o Only start status server after we're daemonized, otherwise
73 static int folve_getattr(const char *path, struct stat *stbuf) {
9a8ea565 »
2012-09-12 o add infrastructure to provide Stat() output of currently open
74 // If this is a currently open filename, we might be able to output a better
75 // estimate.
ee675fea »
2012-09-17 o Provide a way to select between different filter diretories.
76 int result = folve_rt.fs->StatByFilename(path, stbuf);
9a8ea565 »
2012-09-12 o add infrastructure to provide Stat() output of currently open
77 if (result == 0) return result;
78
98a57256 »
2012-09-08 o Start implementation. Just a basic forwarding filesystem for
79 char path_buf[PATH_MAX];
9a8ea565 »
2012-09-12 o add infrastructure to provide Stat() output of currently open
80 result = lstat(assemble_orig_path(path_buf, path), stbuf);
98a57256 »
2012-09-08 o Start implementation. Just a basic forwarding filesystem for
81 if (result == -1)
82 return -errno;
83
84 return 0;
85 }
86
73093dcf »
2012-09-08 o Keep open file-descriptor.
87 // readdir(). Just forward to original filesystem.
0330f769 »
2012-09-16 o Only start status server after we're daemonized, otherwise
88 static int folve_readdir(const char *path, void *buf, fuse_fill_dir_t filler,
89 off_t offset, struct fuse_file_info *fi) {
98a57256 »
2012-09-08 o Start implementation. Just a basic forwarding filesystem for
90 DIR *dp;
91 struct dirent *de;
92 char path_buf[PATH_MAX];
93
94 dp = opendir(assemble_orig_path(path_buf, path));
95 if (dp == NULL)
96 return -errno;
97
7c7bda6f »
2012-09-10 o attempt to create a sndfile for every file, if that fails, fall
98 char ogg_rewrite_buffer[PATH_MAX];
99
98a57256 »
2012-09-08 o Start implementation. Just a basic forwarding filesystem for
100 while ((de = readdir(dp)) != NULL) {
101 struct stat st;
102 memset(&st, 0, sizeof(st));
103 st.st_ino = de->d_ino;
104 st.st_mode = de->d_type << 12;
7c7bda6f »
2012-09-10 o attempt to create a sndfile for every file, if that fails, fall
105 const char *entry_name = de->d_name;
106 if (has_suffix_string(entry_name, ".ogg")) {
107 // For ogg files, we pretend they actually end with 'flac', because
108 // we transparently rewrite them.
109 entry_name = concat_path(ogg_rewrite_buffer, entry_name, ".fuse.flac");
110 }
111 if (filler(buf, entry_name, &st, 0))
98a57256 »
2012-09-08 o Start implementation. Just a basic forwarding filesystem for
112 break;
113 }
114
115 closedir(dp);
116 return 0;
117 }
118
73093dcf »
2012-09-08 o Keep open file-descriptor.
119 // readlink(): forward to original filesystem.
0330f769 »
2012-09-16 o Only start status server after we're daemonized, otherwise
120 static int folve_readlink(const char *path, char *buf, size_t size) {
98a57256 »
2012-09-08 o Start implementation. Just a basic forwarding filesystem for
121 char path_buf[PATH_MAX];
122 const int result = readlink(assemble_orig_path(path_buf, path),
123 buf, size - 1);
124 if (result == -1)
125 return -errno;
126
127 buf[result] = '\0';
128 return 0;
129 }
130
0330f769 »
2012-09-16 o Only start status server after we're daemonized, otherwise
131 static int folve_open(const char *path, struct fuse_file_info *fi) {
8b18938f »
2012-09-09 o some comment changes. Ready to do some flac handling.
132 // We want to be allowed to only return part of the requested data in read().
133 // That way, we can separate reading the ID3-tags from
134 // decoding of the music stream - that way indexing should be fast.
135 // Setting the flag 'direct_io' allows us to return partial results.
136 fi->direct_io = 1;
137
e9c07dd6 »
2012-09-08 o add documentation
138 // The file-handle has the neat property to be 64 bit - so we can actually
b6988530 »
2012-09-15 o README updates.
139 // stuff a pointer to our file handler object in there :)
8b18938f »
2012-09-09 o some comment changes. Ready to do some flac handling.
140 // (Yay, someone was thinking while developing that API).
15b305a6 »
2012-09-13 o Build infrastructure to re-use file handler objects. Files seem to
141 char path_buf[PATH_MAX];
142 const char *orig_path = assemble_orig_path(path_buf, path);
ee675fea »
2012-09-17 o Provide a way to select between different filter diretories.
143 FileHandler *handler = folve_rt.fs->CreateHandler(path, orig_path);
680f5909 »
2012-09-13 o report opening error.
144 if (handler == NULL)
145 return -errno;
146 fi->fh = (uint64_t) handler;
147 return 0;
98a57256 »
2012-09-08 o Start implementation. Just a basic forwarding filesystem for
148 }
149
0330f769 »
2012-09-16 o Only start status server after we're daemonized, otherwise
150 static int folve_read(const char *path, char *buf, size_t size, off_t offset,
151 struct fuse_file_info *fi) {
8d1fbe7c »
2012-09-13 o Move fuse-convolve.c to fuse-convolve.cc. Make filter-interface
152 return reinterpret_cast<FileHandler *>(fi->fh)->Read(buf, size, offset);
98a57256 »
2012-09-08 o Start implementation. Just a basic forwarding filesystem for
153 }
154
0330f769 »
2012-09-16 o Only start status server after we're daemonized, otherwise
155 static int folve_release(const char *path, struct fuse_file_info *fi) {
ee675fea »
2012-09-17 o Provide a way to select between different filter diretories.
156 folve_rt.fs->Close(path, reinterpret_cast<FileHandler *>(fi->fh));
8d1fbe7c »
2012-09-13 o Move fuse-convolve.c to fuse-convolve.cc. Make filter-interface
157 return 0;
9a8ea565 »
2012-09-12 o add infrastructure to provide Stat() output of currently open
158 }
159
0330f769 »
2012-09-16 o Only start status server after we're daemonized, otherwise
160 static int folve_fgetattr(const char *path, struct stat *result,
161 struct fuse_file_info *fi) {
8d1fbe7c »
2012-09-13 o Move fuse-convolve.c to fuse-convolve.cc. Make filter-interface
162 return reinterpret_cast<FileHandler *>(fi->fh)->Stat(result);
73093dcf »
2012-09-08 o Keep open file-descriptor.
163 }
98a57256 »
2012-09-08 o Start implementation. Just a basic forwarding filesystem for
164
0330f769 »
2012-09-16 o Only start status server after we're daemonized, otherwise
165 static void *folve_init(struct fuse_conn_info *conn) {
166 // If we're running in the foreground, we like to be seen on stderr as well.
167 const int ident_len = 20;
168 char *ident = (char*) malloc(ident_len); // openlog() keeps reference. Leaks.
27c44cd1 »
2012-09-17 o Use fuse option handling to extract our flags and options.
169 snprintf(ident, ident_len, "folve[%d]", getpid());
0330f769 »
2012-09-16 o Only start status server after we're daemonized, otherwise
170 openlog(ident, LOG_CONS|LOG_PERROR, LOG_USER);
ee675fea »
2012-09-17 o Provide a way to select between different filter diretories.
171 syslog(LOG_INFO, "Version " FOLVE_VERSION " started. "
172 "Serving '%s' on mount point '%s'",
173 folve_rt.fs->underlying_dir().c_str(), folve_rt.mount_point);
5830c5a6 »
2012-09-17 o Switch logging to syslog()
174 if (folve_rt.fs->IsDebugMode()) {
175 syslog(LOG_INFO, "Debug logging enabled (-D)");
176 }
0330f769 »
2012-09-16 o Only start status server after we're daemonized, otherwise
177
ee675fea »
2012-09-17 o Provide a way to select between different filter diretories.
178 if (folve_rt.status_port > 0) {
0330f769 »
2012-09-16 o Only start status server after we're daemonized, otherwise
179 // Need to start status server after we're daemonized.
ee675fea »
2012-09-17 o Provide a way to select between different filter diretories.
180 StatusServer *status_server = new StatusServer(folve_rt.fs);
181 if (status_server->Start(folve_rt.status_port)) {
0330f769 »
2012-09-16 o Only start status server after we're daemonized, otherwise
182 syslog(LOG_INFO, "HTTP status server on port %d",
ee675fea »
2012-09-17 o Provide a way to select between different filter diretories.
183 folve_rt.status_port);
0330f769 »
2012-09-16 o Only start status server after we're daemonized, otherwise
184 } else {
185 syslog(LOG_ERR, "Couldn't start HTTP server on port %d\n",
ee675fea »
2012-09-17 o Provide a way to select between different filter diretories.
186 folve_rt.status_port);
0330f769 »
2012-09-16 o Only start status server after we're daemonized, otherwise
187 }
188 }
ee675fea »
2012-09-17 o Provide a way to select between different filter diretories.
189
190 // Some sanity checks.
191 if (folve_rt.fs->config_dirs().size() == 1) {
192 syslog(LOG_NOTICE, "No filter configuration directories given. "
193 "Any files will be just passed through verbatim.");
194 }
195 if (folve_rt.fs->config_dirs().size() > 2 && folve_rt.status_port < 0) {
196 syslog(LOG_WARNING, "Multiple filter configurations given, but no HTTP "
197 "status port. You only can switch filters via the HTTP interface; "
198 "add -p <port>");
199 }
0330f769 »
2012-09-16 o Only start status server after we're daemonized, otherwise
200 return NULL;
201 }
98a57256 »
2012-09-08 o Start implementation. Just a basic forwarding filesystem for
202
0a3400db »
2012-09-16 o Write when we're exiting.
203 static void folve_destroy(void *) {
db66f7df »
2012-09-17 o print which directory is serviced.
204 syslog(LOG_INFO, "Exiting.");
0a3400db »
2012-09-16 o Write when we're exiting.
205 }
206
b6988530 »
2012-09-15 o README updates.
207 static int usage(const char *prg) {
5830c5a6 »
2012-09-17 o Switch logging to syslog()
208 printf("usage: %s [options] <original-dir> <mount-point>\n", prg);
209 printf("Options: (in sequence of usefulness)\n"
210 "\t-c <cfg-dir> : Configuration directory.\n"
211 "\t You can supply this option multiple times;\n"
212 "\t you'll get a drop-down select on the HTTP "
213 "status page.\n"
214 "\t-p <port> : Port to run the HTTP status server on.\n"
215 "\t-D : Moderate volume Folve debug messages.\n"
216 "\t-f : Operate in foreground; useful for debugging.\n"
217 "\t-o <mnt-opt> : other generic mount parameters passed to fuse.\n"
218 "\t-d : High volume fuse debug log. Implies -f.\n");
8b18938f »
2012-09-09 o some comment changes. Ready to do some flac handling.
219 return 1;
98a57256 »
2012-09-08 o Start implementation. Just a basic forwarding filesystem for
220 }
221
27c44cd1 »
2012-09-17 o Use fuse option handling to extract our flags and options.
222 struct FolveConfig {
223 FolveConfig() : base_dir(NULL), config_dir(NULL), port(-1) {}
224 const char *base_dir;
225 const char *mount_point;
226 const char *config_dir;
227 int port;
228 };
229
230 enum {
231 FOLVE_OPT_PORT = 42,
232 FOLVE_OPT_CONFIG,
5830c5a6 »
2012-09-17 o Switch logging to syslog()
233 FOLVE_OPT_DEBUG,
27c44cd1 »
2012-09-17 o Use fuse option handling to extract our flags and options.
234 };
235
236 int FolveOptionHandling(void *data, const char *arg, int key,
237 struct fuse_args *outargs) {
ee675fea »
2012-09-17 o Provide a way to select between different filter diretories.
238 FolveRuntime *rt = (FolveRuntime*) data;
27c44cd1 »
2012-09-17 o Use fuse option handling to extract our flags and options.
239 switch (key) {
240 case FUSE_OPT_KEY_NONOPT:
ee675fea »
2012-09-17 o Provide a way to select between different filter diretories.
241 // First non-opt: our underlying dir.
242 if (rt->fs->underlying_dir().empty()) {
243 rt->fs->set_underlying_dir(arg);
244 return 0; // we consumed this.
27c44cd1 »
2012-09-17 o Use fuse option handling to extract our flags and options.
245 } else {
ee675fea »
2012-09-17 o Provide a way to select between different filter diretories.
246 rt->mount_point = strdup(arg); // remmber as FYI
247 return 1; // .. but leave it to fuse
27c44cd1 »
2012-09-17 o Use fuse option handling to extract our flags and options.
248 }
249 case FOLVE_OPT_PORT:
ee675fea »
2012-09-17 o Provide a way to select between different filter diretories.
250 rt->status_port = atoi(arg + 2); // strip "-p"
27c44cd1 »
2012-09-17 o Use fuse option handling to extract our flags and options.
251 return 0;
252 case FOLVE_OPT_CONFIG:
ee675fea »
2012-09-17 o Provide a way to select between different filter diretories.
253 rt->fs->add_config_dir(arg + 2); // strip "-c"
27c44cd1 »
2012-09-17 o Use fuse option handling to extract our flags and options.
254 return 0;
5830c5a6 »
2012-09-17 o Switch logging to syslog()
255 case FOLVE_OPT_DEBUG:
256 rt->fs->SetDebugMode(true);
257 return 0;
27c44cd1 »
2012-09-17 o Use fuse option handling to extract our flags and options.
258 }
259 return 1;
260 }
261
98a57256 »
2012-09-08 o Start implementation. Just a basic forwarding filesystem for
262 int main(int argc, char *argv[]) {
1e9ff217 »
2012-09-15 o main: report if parameters are not directories.
263 const char *progname = argv[0];
8b18938f »
2012-09-09 o some comment changes. Ready to do some flac handling.
264 if (argc < 4) {
1e9ff217 »
2012-09-15 o main: report if parameters are not directories.
265 return usage(progname);
98a57256 »
2012-09-08 o Start implementation. Just a basic forwarding filesystem for
266 }
49eca7f9 »
2012-09-16 o add syslog as preparation for parameter handling.
267
ee675fea »
2012-09-17 o Provide a way to select between different filter diretories.
268 folve_rt.fs = new FolveFilesystem();
269
27c44cd1 »
2012-09-17 o Use fuse option handling to extract our flags and options.
270 static struct fuse_opt folve_options[] = {
5830c5a6 »
2012-09-17 o Switch logging to syslog()
271 FUSE_OPT_KEY("-p ", FOLVE_OPT_PORT),
272 FUSE_OPT_KEY("-c ", FOLVE_OPT_CONFIG),
273 FUSE_OPT_KEY("-D", FOLVE_OPT_DEBUG),
27c44cd1 »
2012-09-17 o Use fuse option handling to extract our flags and options.
274 FUSE_OPT_END
275 };
276 struct fuse_args args = FUSE_ARGS_INIT(argc, argv);
ee675fea »
2012-09-17 o Provide a way to select between different filter diretories.
277 fuse_opt_parse(&args, &folve_rt, folve_options, FolveOptionHandling);
27c44cd1 »
2012-09-17 o Use fuse option handling to extract our flags and options.
278
ee675fea »
2012-09-17 o Provide a way to select between different filter diretories.
279 if (!folve_rt.fs->CheckInitialized()) {
1e9ff217 »
2012-09-15 o main: report if parameters are not directories.
280 return usage(progname);
281 }
0330f769 »
2012-09-16 o Only start status server after we're daemonized, otherwise
282
283 struct fuse_operations folve_operations;
284 memset(&folve_operations, 0, sizeof(folve_operations));
8d1fbe7c »
2012-09-13 o Move fuse-convolve.c to fuse-convolve.cc. Make filter-interface
285
0a3400db »
2012-09-16 o Write when we're exiting.
286 // Start/stop. Will write to syslog and start auxiliary http service.
0330f769 »
2012-09-16 o Only start status server after we're daemonized, otherwise
287 folve_operations.init = folve_init;
0a3400db »
2012-09-16 o Write when we're exiting.
288 folve_operations.destroy = folve_destroy;
8d1fbe7c »
2012-09-13 o Move fuse-convolve.c to fuse-convolve.cc. Make filter-interface
289
290 // Basic operations to make navigation work.
0330f769 »
2012-09-16 o Only start status server after we're daemonized, otherwise
291 folve_operations.readdir = folve_readdir;
292 folve_operations.readlink = folve_readlink;
8d1fbe7c »
2012-09-13 o Move fuse-convolve.c to fuse-convolve.cc. Make filter-interface
293
294 // open() and close() file.
0330f769 »
2012-09-16 o Only start status server after we're daemonized, otherwise
295 folve_operations.open = folve_open;
296 folve_operations.release = folve_release;
8d1fbe7c »
2012-09-13 o Move fuse-convolve.c to fuse-convolve.cc. Make filter-interface
297
298 // Actual workhorse: reading a file and returning predicted file-size
0330f769 »
2012-09-16 o Only start status server after we're daemonized, otherwise
299 folve_operations.read = folve_read;
300 folve_operations.fgetattr = folve_fgetattr;
301 folve_operations.getattr = folve_getattr;
98a57256 »
2012-09-08 o Start implementation. Just a basic forwarding filesystem for
302
27c44cd1 »
2012-09-17 o Use fuse option handling to extract our flags and options.
303 return fuse_main(args.argc, args.argv, &folve_operations, NULL);
98a57256 »
2012-09-08 o Start implementation. Just a basic forwarding filesystem for
304 }
Something went wrong with that request. Please try again.