Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Newer
Older
100644 296 lines (254 sloc) 9.249 kb
98a5725 @hzeller o Start implementation. Just a basic forwarding filesystem for
authored
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>
a9d3e53 @hzeller o Found a project name: "Folve". Some renamings because of that.
authored
19
98a5725 @hzeller o Start implementation. Just a basic forwarding filesystem for
authored
20 #include <dirent.h>
21 #include <errno.h>
b698853 @hzeller o README updates.
authored
22 #include <fcntl.h>
98a5725 @hzeller o Start implementation. Just a basic forwarding filesystem for
authored
23 #include <limits.h>
b698853 @hzeller o README updates.
authored
24 #include <stdio.h>
98a5725 @hzeller o Start implementation. Just a basic forwarding filesystem for
authored
25 #include <stdlib.h>
b698853 @hzeller o README updates.
authored
26 #include <string.h>
27 #include <sys/stat.h>
28 #include <sys/time.h>
49eca7f @hzeller o add syslog as preparation for parameter handling.
authored
29 #include <syslog.h>
b698853 @hzeller o README updates.
authored
30 #include <unistd.h>
98a5725 @hzeller o Start implementation. Just a basic forwarding filesystem for
authored
31
a9d3e53 @hzeller o Found a project name: "Folve". Some renamings because of that.
authored
32 #include "folve-filesystem.h"
8d1fbe7 @hzeller o Move fuse-convolve.c to fuse-convolve.cc. Make filter-interface
authored
33 #include "status-server.h"
e9c07dd @hzeller o add documentation
authored
34
41ef6b5 @hzeller o Generate version identifier from git.
authored
35 #ifndef FOLVE_VERSION
36 #define FOLVE_VERSION "[unknown version - compile from git]"
37 #endif
a9d3e53 @hzeller o Found a project name: "Folve". Some renamings because of that.
authored
38
6c6dedb @hzeller o Some readme tweaks and readability improvements.
authored
39 // Compilation unit variables to communicate with the fuse callbacks.
27c44cd @hzeller o Use fuse option handling to extract our flags and options.
authored
40 static struct FolveRuntime {
41 FolveRuntime() : fs(NULL), status_port(-1) {}
0330f76 @hzeller o Only start status server after we're daemonized, otherwise
authored
42 FolveFilesystem *fs;
27c44cd @hzeller o Use fuse option handling to extract our flags and options.
authored
43 const char *mount_point;
0330f76 @hzeller o Only start status server after we're daemonized, otherwise
authored
44 int status_port;
45 } folve;
98a5725 @hzeller o Start implementation. Just a basic forwarding filesystem for
authored
46
7c7bda6 @hzeller o attempt to create a sndfile for every file, if that fails, fall
authored
47 static int has_suffix_string (const char *str, const char *suffix) {
48 if (!str || !suffix)
49 return 0;
50 size_t str_len = strlen(str);
51 size_t suffix_len = strlen(suffix);
52 if (suffix_len > str_len)
53 return 0;
54 return strncmp(str + str_len - suffix_len, suffix, suffix_len) == 0;
55 }
56
57 static char *concat_path(char *buf, const char *a, const char *b) {
58 strcpy(buf, a);
59 strcat(buf, b);
60 return buf;
61 }
62
98a5725 @hzeller o Start implementation. Just a basic forwarding filesystem for
authored
63 // Given a relative path from the root of the mounted file-system, get the
64 // original file from the source filesystem.
0aee3bb @hzeller o Show base dir that is mounted.
authored
65 // TODO(hzeller): move the ogg.fuse.flac logic into convolver-filesystem.
98a5725 @hzeller o Start implementation. Just a basic forwarding filesystem for
authored
66 static const char *assemble_orig_path(char *buf, const char *path) {
0330f76 @hzeller o Only start status server after we're daemonized, otherwise
authored
67 char *result = concat_path(buf, folve.fs->underlying_dir(), path);
7c7bda6 @hzeller o attempt to create a sndfile for every file, if that fails, fall
authored
68 static const char magic_ogg_rewrite[] = ".ogg.fuse.flac";
69 if (has_suffix_string(result, magic_ogg_rewrite)) {
70 *(result + strlen(result) - strlen(".fuse.flac")) = '\0';
71 }
72 return result;
98a5725 @hzeller o Start implementation. Just a basic forwarding filesystem for
authored
73 }
74
7c7bda6 @hzeller o attempt to create a sndfile for every file, if that fails, fall
authored
75 // Essentially lstat(). Just forward to the original filesystem (this
73093dc @hzeller o Keep open file-descriptor.
authored
76 // will by lying: our convolved files are of different size...)
0330f76 @hzeller o Only start status server after we're daemonized, otherwise
authored
77 static int folve_getattr(const char *path, struct stat *stbuf) {
9a8ea56 @hzeller o add infrastructure to provide Stat() output of currently open
authored
78 // If this is a currently open filename, we might be able to output a better
79 // estimate.
0330f76 @hzeller o Only start status server after we're daemonized, otherwise
authored
80 int result = folve.fs->StatByFilename(path, stbuf);
9a8ea56 @hzeller o add infrastructure to provide Stat() output of currently open
authored
81 if (result == 0) return result;
82
98a5725 @hzeller o Start implementation. Just a basic forwarding filesystem for
authored
83 char path_buf[PATH_MAX];
9a8ea56 @hzeller o add infrastructure to provide Stat() output of currently open
authored
84 result = lstat(assemble_orig_path(path_buf, path), stbuf);
98a5725 @hzeller o Start implementation. Just a basic forwarding filesystem for
authored
85 if (result == -1)
86 return -errno;
87
88 return 0;
89 }
90
73093dc @hzeller o Keep open file-descriptor.
authored
91 // readdir(). Just forward to original filesystem.
0330f76 @hzeller o Only start status server after we're daemonized, otherwise
authored
92 static int folve_readdir(const char *path, void *buf, fuse_fill_dir_t filler,
93 off_t offset, struct fuse_file_info *fi) {
98a5725 @hzeller o Start implementation. Just a basic forwarding filesystem for
authored
94 DIR *dp;
95 struct dirent *de;
96 char path_buf[PATH_MAX];
97
98 dp = opendir(assemble_orig_path(path_buf, path));
99 if (dp == NULL)
100 return -errno;
101
7c7bda6 @hzeller o attempt to create a sndfile for every file, if that fails, fall
authored
102 char ogg_rewrite_buffer[PATH_MAX];
103
98a5725 @hzeller o Start implementation. Just a basic forwarding filesystem for
authored
104 while ((de = readdir(dp)) != NULL) {
105 struct stat st;
106 memset(&st, 0, sizeof(st));
107 st.st_ino = de->d_ino;
108 st.st_mode = de->d_type << 12;
7c7bda6 @hzeller o attempt to create a sndfile for every file, if that fails, fall
authored
109 const char *entry_name = de->d_name;
110 if (has_suffix_string(entry_name, ".ogg")) {
111 // For ogg files, we pretend they actually end with 'flac', because
112 // we transparently rewrite them.
113 entry_name = concat_path(ogg_rewrite_buffer, entry_name, ".fuse.flac");
114 }
115 if (filler(buf, entry_name, &st, 0))
98a5725 @hzeller o Start implementation. Just a basic forwarding filesystem for
authored
116 break;
117 }
118
119 closedir(dp);
120 return 0;
121 }
122
73093dc @hzeller o Keep open file-descriptor.
authored
123 // readlink(): forward to original filesystem.
0330f76 @hzeller o Only start status server after we're daemonized, otherwise
authored
124 static int folve_readlink(const char *path, char *buf, size_t size) {
98a5725 @hzeller o Start implementation. Just a basic forwarding filesystem for
authored
125 char path_buf[PATH_MAX];
126 const int result = readlink(assemble_orig_path(path_buf, path),
127 buf, size - 1);
128 if (result == -1)
129 return -errno;
130
131 buf[result] = '\0';
132 return 0;
133 }
134
0330f76 @hzeller o Only start status server after we're daemonized, otherwise
authored
135 static int folve_open(const char *path, struct fuse_file_info *fi) {
8b18938 @hzeller o some comment changes. Ready to do some flac handling.
authored
136 // We want to be allowed to only return part of the requested data in read().
137 // That way, we can separate reading the ID3-tags from
138 // decoding of the music stream - that way indexing should be fast.
139 // Setting the flag 'direct_io' allows us to return partial results.
140 fi->direct_io = 1;
141
e9c07dd @hzeller o add documentation
authored
142 // The file-handle has the neat property to be 64 bit - so we can actually
b698853 @hzeller o README updates.
authored
143 // stuff a pointer to our file handler object in there :)
8b18938 @hzeller o some comment changes. Ready to do some flac handling.
authored
144 // (Yay, someone was thinking while developing that API).
15b305a @hzeller o Build infrastructure to re-use file handler objects. Files seem to
authored
145 char path_buf[PATH_MAX];
146 const char *orig_path = assemble_orig_path(path_buf, path);
0330f76 @hzeller o Only start status server after we're daemonized, otherwise
authored
147 FileHandler *handler = folve.fs->CreateHandler(path, orig_path);
680f590 @hzeller o report opening error.
authored
148 if (handler == NULL)
149 return -errno;
150 fi->fh = (uint64_t) handler;
151 return 0;
98a5725 @hzeller o Start implementation. Just a basic forwarding filesystem for
authored
152 }
153
0330f76 @hzeller o Only start status server after we're daemonized, otherwise
authored
154 static int folve_read(const char *path, char *buf, size_t size, off_t offset,
155 struct fuse_file_info *fi) {
8d1fbe7 @hzeller o Move fuse-convolve.c to fuse-convolve.cc. Make filter-interface
authored
156 return reinterpret_cast<FileHandler *>(fi->fh)->Read(buf, size, offset);
98a5725 @hzeller o Start implementation. Just a basic forwarding filesystem for
authored
157 }
158
0330f76 @hzeller o Only start status server after we're daemonized, otherwise
authored
159 static int folve_release(const char *path, struct fuse_file_info *fi) {
160 folve.fs->Close(path);
8d1fbe7 @hzeller o Move fuse-convolve.c to fuse-convolve.cc. Make filter-interface
authored
161 return 0;
9a8ea56 @hzeller o add infrastructure to provide Stat() output of currently open
authored
162 }
163
0330f76 @hzeller o Only start status server after we're daemonized, otherwise
authored
164 static int folve_fgetattr(const char *path, struct stat *result,
165 struct fuse_file_info *fi) {
8d1fbe7 @hzeller o Move fuse-convolve.c to fuse-convolve.cc. Make filter-interface
authored
166 return reinterpret_cast<FileHandler *>(fi->fh)->Stat(result);
73093dc @hzeller o Keep open file-descriptor.
authored
167 }
98a5725 @hzeller o Start implementation. Just a basic forwarding filesystem for
authored
168
0330f76 @hzeller o Only start status server after we're daemonized, otherwise
authored
169 static void *folve_init(struct fuse_conn_info *conn) {
170 // If we're running in the foreground, we like to be seen on stderr as well.
171 const int ident_len = 20;
172 char *ident = (char*) malloc(ident_len); // openlog() keeps reference. Leaks.
27c44cd @hzeller o Use fuse option handling to extract our flags and options.
authored
173 snprintf(ident, ident_len, "folve[%d]", getpid());
0330f76 @hzeller o Only start status server after we're daemonized, otherwise
authored
174 openlog(ident, LOG_CONS|LOG_PERROR, LOG_USER);
27c44cd @hzeller o Use fuse option handling to extract our flags and options.
authored
175 syslog(LOG_INFO, "Started. Serving %s on mount point %s",
176 folve.fs->underlying_dir(), folve.mount_point);
0330f76 @hzeller o Only start status server after we're daemonized, otherwise
authored
177
178 if (folve.status_port > 0) {
179 // Need to start status server after we're daemonized.
180 StatusServer *status_server = new StatusServer(folve.fs);
181 if (status_server->Start(folve.status_port)) {
182 syslog(LOG_INFO, "HTTP status server on port %d",
183 folve.status_port);
184 } else {
185 syslog(LOG_ERR, "Couldn't start HTTP server on port %d\n",
186 folve.status_port);
187 }
188 }
189 return NULL;
190 }
98a5725 @hzeller o Start implementation. Just a basic forwarding filesystem for
authored
191
0a3400d @hzeller o Write when we're exiting.
authored
192 static void folve_destroy(void *) {
db66f7d @hzeller o print which directory is serviced.
authored
193 syslog(LOG_INFO, "Exiting.");
0a3400d @hzeller o Write when we're exiting.
authored
194 }
195
b698853 @hzeller o README updates.
authored
196 static int usage(const char *prg) {
197 fprintf(stderr, "usage: %s <config-dir> <original-dir> <mount-point>\n", prg);
8b18938 @hzeller o some comment changes. Ready to do some flac handling.
authored
198 return 1;
98a5725 @hzeller o Start implementation. Just a basic forwarding filesystem for
authored
199 }
200
1e9ff21 @hzeller o main: report if parameters are not directories.
authored
201 static bool IsDirectory(const char *path) {
27c44cd @hzeller o Use fuse option handling to extract our flags and options.
authored
202 if (path == NULL)
203 return false;
1e9ff21 @hzeller o main: report if parameters are not directories.
authored
204 struct stat st;
205 if (stat(path, &st) != 0)
206 return false;
207 return (st.st_mode & S_IFMT) == S_IFDIR;
208 }
209
27c44cd @hzeller o Use fuse option handling to extract our flags and options.
authored
210 struct FolveConfig {
211 FolveConfig() : base_dir(NULL), config_dir(NULL), port(-1) {}
212 const char *base_dir;
213 const char *mount_point;
214 const char *config_dir;
215 int port;
216 };
217
218 enum {
219 FOLVE_OPT_PORT = 42,
220 FOLVE_OPT_CONFIG,
221 };
222
223 int FolveOptionHandling(void *data, const char *arg, int key,
224 struct fuse_args *outargs) {
225 FolveConfig *cfg = (FolveConfig*) data;
226 switch (key) {
227 case FUSE_OPT_KEY_NONOPT:
228 // First non-opt: our base mounting dir.
229 if (cfg->base_dir == NULL) {
230 cfg->base_dir = strdup(arg);
231 return 0;
232 } else {
233 cfg->mount_point = strdup(arg); // remmber as FYI
234 return 1; // Leave it to fuse
235 }
236 case FOLVE_OPT_PORT:
237 cfg->port = atoi(arg + 2); // strip "-p"
238 return 0;
239 case FOLVE_OPT_CONFIG:
240 cfg->config_dir = strdup(arg + 2); // strip "-c"
241 return 0;
242 }
243 return 1;
244 }
245
98a5725 @hzeller o Start implementation. Just a basic forwarding filesystem for
authored
246 int main(int argc, char *argv[]) {
1e9ff21 @hzeller o main: report if parameters are not directories.
authored
247 const char *progname = argv[0];
8b18938 @hzeller o some comment changes. Ready to do some flac handling.
authored
248 if (argc < 4) {
1e9ff21 @hzeller o main: report if parameters are not directories.
authored
249 return usage(progname);
98a5725 @hzeller o Start implementation. Just a basic forwarding filesystem for
authored
250 }
49eca7f @hzeller o add syslog as preparation for parameter handling.
authored
251
27c44cd @hzeller o Use fuse option handling to extract our flags and options.
authored
252 FolveConfig cfg;
253 static struct fuse_opt folve_options[] = {
254 FUSE_OPT_KEY("-p ", FOLVE_OPT_PORT),
255 FUSE_OPT_KEY("-c ", FOLVE_OPT_CONFIG),
256 FUSE_OPT_END
257 };
258 struct fuse_args args = FUSE_ARGS_INIT(argc, argv);
259 fuse_opt_parse(&args, &cfg, folve_options, FolveOptionHandling);
260
261 if (!IsDirectory(cfg.config_dir)) {
262 fprintf(stderr, "<config-dir>: %s not a directory.\n", cfg.config_dir);
1e9ff21 @hzeller o main: report if parameters are not directories.
authored
263 return usage(progname);
264 }
27c44cd @hzeller o Use fuse option handling to extract our flags and options.
authored
265 if (!IsDirectory(cfg.base_dir)) {
266 fprintf(stderr, "<underlying-dir>: %s not a directory.\n", cfg.base_dir);
1e9ff21 @hzeller o main: report if parameters are not directories.
authored
267 return usage(progname);
268 }
db66f7d @hzeller o print which directory is serviced.
authored
269
27c44cd @hzeller o Use fuse option handling to extract our flags and options.
authored
270 folve.fs = new FolveFilesystem(FOLVE_VERSION, cfg.base_dir, cfg.config_dir);
271 folve.status_port = cfg.port;
272 folve.mount_point = cfg.mount_point;
0330f76 @hzeller o Only start status server after we're daemonized, otherwise
authored
273
274 struct fuse_operations folve_operations;
275 memset(&folve_operations, 0, sizeof(folve_operations));
8d1fbe7 @hzeller o Move fuse-convolve.c to fuse-convolve.cc. Make filter-interface
authored
276
0a3400d @hzeller o Write when we're exiting.
authored
277 // Start/stop. Will write to syslog and start auxiliary http service.
0330f76 @hzeller o Only start status server after we're daemonized, otherwise
authored
278 folve_operations.init = folve_init;
0a3400d @hzeller o Write when we're exiting.
authored
279 folve_operations.destroy = folve_destroy;
8d1fbe7 @hzeller o Move fuse-convolve.c to fuse-convolve.cc. Make filter-interface
authored
280
281 // Basic operations to make navigation work.
0330f76 @hzeller o Only start status server after we're daemonized, otherwise
authored
282 folve_operations.readdir = folve_readdir;
283 folve_operations.readlink = folve_readlink;
8d1fbe7 @hzeller o Move fuse-convolve.c to fuse-convolve.cc. Make filter-interface
authored
284
285 // open() and close() file.
0330f76 @hzeller o Only start status server after we're daemonized, otherwise
authored
286 folve_operations.open = folve_open;
287 folve_operations.release = folve_release;
8d1fbe7 @hzeller o Move fuse-convolve.c to fuse-convolve.cc. Make filter-interface
authored
288
289 // Actual workhorse: reading a file and returning predicted file-size
0330f76 @hzeller o Only start status server after we're daemonized, otherwise
authored
290 folve_operations.read = folve_read;
291 folve_operations.fgetattr = folve_fgetattr;
292 folve_operations.getattr = folve_getattr;
98a5725 @hzeller o Start implementation. Just a basic forwarding filesystem for
authored
293
27c44cd @hzeller o Use fuse option handling to extract our flags and options.
authored
294 return fuse_main(args.argc, args.argv, &folve_operations, NULL);
98a5725 @hzeller o Start implementation. Just a basic forwarding filesystem for
authored
295 }
Something went wrong with that request. Please try again.