1 /*
2 * uadefs decodes Amiga songs transparently into WAV files
3 *
4 * The code was forked from fusexmp example.
5 *
6 * Copyright (C) 2001-2007 Miklos Szeredi <miklos@szeredi.hu>
7 * Copyright (C) 2008 Heikki Orsila <heikki.orsila@iki.fi>
8 *
9 * This program can be distributed under the terms of the GNU GPL.
10 * See the file COPYING.
11 */
12
13 #define _GNU_SOURCE
14
15 #define FUSE_USE_VERSION 26
16
17 #ifdef HAVE_CONFIG_H
18 #include <config.h>
19 #endif
20
21 #ifdef linux
22 /* For pread()/pwrite() */
23 #define _XOPEN_SOURCE 500
24 #endif
25
26 #include <pthread.h>
27 #include <fuse.h>
28 #include <stdio.h>
29 #include <string.h>
30 #include <unistd.h>
31 #include <fcntl.h>
32 #include <dirent.h>
33 #include <errno.h>
34 #include <sys/time.h>
35 #ifdef HAVE_SETXATTR
36 #include <sys/xattr.h>
37 #endif
38 #include <sys/types.h>
39 #include <sys/wait.h>
40 #include <signal.h>
41 #include <string.h>
42 #include <strings.h>
43 #include <stdlib.h>
44 #include <stdio.h>
45 #include <sys/types.h>
46 #include <sys/stat.h>
47 #include <assert.h>
48 #include <time.h>
49
50 #include "uadeconf.h"
51 #include "uadestate.h"
52 #include "eagleplayer.h"
53 #include "songdb.h"
54 #include "uadeconfig.h"
55 #include "ossupport.h"
56
57
58 #define WAV_HEADER_LEN 44
59
60 #define CACHE_BLOCK_SHIFT 12 /* 4096 bytes per cache block */
61 #define CACHE_BLOCK_SIZE (1 << CACHE_BLOCK_SHIFT)
62 #define CACHE_LSB_MASK (CACHE_BLOCK_SIZE - 1)
63 #define CACHE_SECONDS 512
64 #define SND_PER_SECOND (44100 * 4)
65
66 #define NSTASHES 4
67 #define STASH_CACHE_BLOCKS 2
68 #define STASH_SIZE (CACHE_BLOCK_SIZE * STASH_CACHE_BLOCKS)
69 #define STASH_TIME 30
70
71 #define DEBUG(fmt, args...) if (debugmode) { fprintf(stderr, fmt, ## args); }
72
73 #define LOG(fmt, args...) if (debugfd != -1) { \
74 char debugmsg[4096]; \
75 int debuglen; \
76 DEBUG(fmt, ## args); \
77 debuglen = snprintf(debugmsg, sizeof debugmsg, fmt, ## args); \
78 xwrite(debugfd, debugmsg, debuglen); \
79 }
80
81 #define DIE(fmt, args...) do {fprintf(stderr, fmt, ## args); exit(1); } while (0)
82
83 #define LOGDIE(fmt, args...) do {LOG(fmt, ## args); abort();} while (0)
84
85 #define MAX(x, y) (x >= y) ? (x) : (y)
86 #define MIN(x, y) (x <= y) ? (x) : (y)
87
88
89 struct cacheblock {
90 unsigned int bytes; /* 0 <= bytes <= CACHE_BLOCK_SIZE */
91 void *data;
92 };
93
94 struct sndctx {
95 int normalfile; /* if non-zero, the file is not decoded */
96 int pipefd; /* pipefd from which to read sound data */
97 pid_t pid; /* pid of the decoding process */
98 char fname[PATH_MAX]; /* filename of the song being played */
99
100 size_t nblocks;
101 size_t end_bi;
102 struct cacheblock *blocks;
103 };
104
105 struct stash {
106 /* Add time invalidation */
107 char fname[PATH_MAX]; /* File name for the stash */
108 char data[STASH_SIZE];
109 time_t created; /* Timestamp for validity checks */
110 };
111
112
113 static char *srcdir = NULL;
114 static int debugfd = -1;
115 static int debugmode;
116 static struct uade_state uadestate;
117 static time_t mtime = 0;
118 static pthread_mutex_t readmutex = PTHREAD_MUTEX_INITIALIZER;
119
120 int nextstash;
121 struct stash stashes[NSTASHES];
122
123
124 static ssize_t get_file_size(const char *path);
125
126 /*
127 * xread() is the same as the read(), but it automatically restarts read()
128 * operations with a recoverable error (EAGAIN and EINTR). xread()
129 * DOES NOT GUARANTEE that "len" bytes is read even if the data is available.
130 */
xread(int fd,void * buf,size_t count)131 static ssize_t xread(int fd, void *buf, size_t count)
132 {
133 ssize_t nr;
134 while (1) {
135 nr = read(fd, buf, count);
136 if ((nr < 0) && (errno == EAGAIN || errno == EINTR))
137 continue;
138 return nr;
139 }
140 }
141
xwrite(int fd,const void * buf,size_t count)142 static ssize_t xwrite(int fd, const void *buf, size_t count)
143 {
144 ssize_t nr;
145 while (1) {
146 nr = write(fd, buf, count);
147 if ((nr < 0) && (errno == EAGAIN || errno == EINTR))
148 continue;
149 return nr;
150 }
151 }
152
read_in_full(int fd,void * buf,size_t count)153 ssize_t read_in_full(int fd, void *buf, size_t count)
154 {
155 char *p = buf;
156 ssize_t total = 0;
157
158 while (count > 0) {
159 ssize_t loaded = xread(fd, p, count);
160 if (loaded <= 0)
161 return total ? total : loaded;
162 count -= loaded;
163 p += loaded;
164 total += loaded;
165 }
166
167 return total;
168 }
169
uadefs_get_path(int * isuade,const char * path)170 static char *uadefs_get_path(int *isuade, const char *path)
171 {
172 char *realpath;
173 char *sep;
174 struct stat st;
175
176 if (isuade)
177 *isuade = 0;
178
179 if (asprintf(&realpath, "%s%s", srcdir, path) < 0)
180 LOGDIE("No memory for path name: %s\n", path);
181
182 if (!lstat(realpath, &st))
183 goto out;
184
185 /* File doesn't exist */
186 sep = strrchr(realpath, '.');
187 if (sep == NULL || strcmp(sep, ".wav") != 0)
188 goto out;
189
190 *sep = 0;
191
192 if (uade_is_our_file(realpath, 1, &uadestate)) {
193 if (isuade)
194 *isuade = 1;
195 } else {
196 /* Not an UADE file -> restore .wav postfix */
197 *sep = '.';
198 }
199 out:
200 return realpath;
201 }
202
spawn_uade(struct sndctx * ctx)203 static int spawn_uade(struct sndctx *ctx)
204 {
205 int fds[2];
206
207 LOG("Spawn UADE %s\n", ctx->fname);
208
209 if (pipe(fds)) {
210 LOG("Can not create a pipe\n");
211 return -errno;
212 }
213
214 ctx->pid = fork();
215 if (ctx->pid == 0) {
216 char *argv[] = {"uade123", "-c", "-k0", "--stderr", "-v",
217 ctx->fname, NULL};
218 int fd;
219
220 close(0);
221 close(2);
222 close(fds[0]);
223
224 fd = open("/dev/null", O_RDWR);
225 if (fd < 0)
226 LOGDIE("Can not open /dev/null\n");
227
228 dup2(fd, 0);
229 dup2(fds[1], 1);
230 dup2(fd, 2);
231
232 DEBUG("Execute %s\n", UADENAME);
233
234 execv(UADENAME, argv);
235
236 LOGDIE("Could not execute %s\n", UADENAME);
237 } else if (ctx->pid == -1) {
238 LOG("Can not fork\n");
239 close(fds[0]);
240 close(fds[1]);
241 return -errno;
242 }
243
244 ctx->pipefd = fds[0];
245 close(fds[1]);
246
247 return 0;
248 }
249
cache_block_read(struct sndctx * ctx,char * buf,size_t offset,size_t size)250 static ssize_t cache_block_read(struct sndctx *ctx, char *buf, size_t offset,
251 size_t size)
252 {
253 size_t toread;
254 size_t offset_bi;
255 size_t lsb;
256 struct cacheblock *cb;
257
258 offset_bi = offset >> CACHE_BLOCK_SHIFT;
259
260 if (offset_bi >= ctx->nblocks) {
261 LOG("Too much sound data: %zu >= %zu: %s\n", offset_bi, ctx->nblocks, ctx->fname);
262 return 0;
263 }
264
265 cb = &ctx->blocks[offset_bi];
266
267 if (!cb->bytes)
268 return -1;
269
270 lsb = offset & CACHE_LSB_MASK;
271
272 if ((lsb + size) > CACHE_BLOCK_SIZE)
273 LOGDIE("lsb + size (%zd) failed: %zd %zd\n", lsb + size, offset, size);
274
275 if (lsb >= cb->bytes)
276 return 0;
277
278 toread = MIN(size, cb->bytes - lsb);
279
280 memcpy(buf, ((char *) cb->data) + lsb, toread);
281
282 return toread;
283 }
284
cache_init(struct sndctx * ctx)285 static void cache_init(struct sndctx *ctx)
286 {
287 ctx->end_bi = 0;
288 ctx->nblocks = (SND_PER_SECOND * CACHE_SECONDS + CACHE_BLOCK_SIZE - 1) >> CACHE_BLOCK_SHIFT;
289 ctx->blocks = calloc(1, ctx->nblocks * sizeof(ctx->blocks[0]));
290 if (ctx->blocks == NULL)
291 LOGDIE("No memory for cache\n");
292 }
293
cache_read(struct sndctx * ctx,char * buf,size_t offset,size_t size)294 static size_t cache_read(struct sndctx *ctx, char *buf, size_t offset,
295 size_t size)
296 {
297 size_t offset_bi;
298 struct cacheblock *cb;
299 ssize_t res;
300
301 offset_bi = offset >> CACHE_BLOCK_SHIFT;
302
303 if (offset_bi >= STASH_CACHE_BLOCKS && ctx->pid == -1) {
304 char buf[CACHE_BLOCK_SIZE];
305 int i;
306
307 if (spawn_uade(ctx))
308 return 0;
309
310 for (i = 0; i < STASH_CACHE_BLOCKS; i++) {
311 res = read_in_full(ctx->pipefd, buf, sizeof buf);
312 if (res < sizeof buf)
313 return 0;
314 }
315 }
316
317 /* The requested block is already in cache, copy it directly */
318 res = cache_block_read(ctx, buf, offset, size);
319 if (res >= 0)
320 return (size_t) res;
321
322 if (offset_bi >= ctx->nblocks) {
323 LOG("Too much sound data: %s\n", ctx->fname);
324 return 0;
325 }
326
327 /*
328 * Read cache blocks in sequence until the requested cache block
329 * has been read. ctx->end_bi is increased every time a new block
330 * is read. ctx->end_bi points to the first block that is not cached.
331 */
332 while (ctx->end_bi <= offset_bi) {
333 cb = &ctx->blocks[ctx->end_bi];
334
335 cb->data = malloc(CACHE_BLOCK_SIZE);
336 if (cb->data == NULL) {
337 LOG("Out of memory: %s\n", ctx->fname);
338 break;
339 }
340
341 res = read_in_full(ctx->pipefd, cb->data, CACHE_BLOCK_SIZE);
342 if (res <= 0) {
343 free(cb->data);
344 cb->data = NULL;
345 DEBUG("Read code %d at %zd: %s\n", (int) res, ctx->end_bi << CACHE_BLOCK_SHIFT, ctx->fname);
346 break;
347 }
348
349 cb->bytes = res;
350
351 ctx->end_bi++;
352
353 if (res < CACHE_BLOCK_SIZE)
354 break;
355 }
356
357 res = cache_block_read(ctx, buf, offset, size);
358 if (res >= 0)
359 return (size_t) res;
360
361 return 0;
362 }
363
cache_prefill(struct sndctx * ctx,char * data)364 int cache_prefill(struct sndctx *ctx, char *data)
365 {
366 int i;
367
368 if (data == NULL)
369 LOGDIE("Prefill segfault: %s\n", ctx->fname);
370
371 ctx->end_bi = STASH_CACHE_BLOCKS;
372
373 for (i = 0; i < STASH_CACHE_BLOCKS; i++) {
374 ctx->blocks[i].data = malloc(CACHE_BLOCK_SIZE);
375 if (ctx->blocks[i].data == NULL) {
376 LOG("Prefill OOM: %s\n", ctx->fname);
377 break;
378 }
379 ctx->blocks[i].bytes = CACHE_BLOCK_SIZE;
380 memcpy(ctx->blocks[i].data, data, CACHE_BLOCK_SIZE);
381 data += CACHE_BLOCK_SIZE;
382 }
383
384 if (i < STASH_CACHE_BLOCKS) {
385 /* Free cache blocks from the beginning to the first NULL */
386 for (i = 0; i < STASH_CACHE_BLOCKS; i++) {
387 if (ctx->blocks[i].data == NULL)
388 break;
389 free(ctx->blocks[i].data);
390 ctx->blocks[i].data = NULL;
391 }
392 return -1;
393 }
394
395 return 0;
396 }
397
write_le_32(char * data,int32_t v)398 static void write_le_32(char *data, int32_t v)
399 {
400 data[0] = v & 0xff;
401 data[1] = (v >> 8) & 0xff;
402 data[2] = (v >> 16) & 0xff;
403 data[3] = (v >> 24) & 0xff;
404 }
405
cache_invasive_write(struct sndctx * ctx,size_t offset,char * data,size_t len)406 static void cache_invasive_write(struct sndctx *ctx, size_t offset,
407 char *data, size_t len)
408 {
409 size_t offset_bi = offset >> CACHE_BLOCK_SHIFT;
410 size_t lsbpos = offset & CACHE_LSB_MASK;
411 struct cacheblock *cb;
412
413 if (offset_bi >= ctx->end_bi) {
414 LOG("Invasive cache write: %zu\n", offset);
415 return;
416 }
417
418 cb = &ctx->blocks[offset_bi];
419
420 if ((lsbpos + len) <= cb->bytes)
421 memcpy(((char *) cb->data) + lsbpos, data, len);
422 }
423
create_ctx(const char * path)424 static struct sndctx *create_ctx(const char *path)
425 {
426 struct sndctx *ctx;
427
428 ctx = calloc(1, sizeof ctx[0]);
429 if (ctx == NULL)
430 return NULL;
431
432 strlcpy(ctx->fname, path, sizeof ctx->fname);
433
434 ctx->pipefd = -1;
435 ctx->pid = -1;
436
437 return ctx;
438 }
439
destroy_cache(struct sndctx * ctx)440 static void destroy_cache(struct sndctx *ctx)
441 {
442 size_t cbi;
443
444 if (ctx->blocks != NULL) {
445 for (cbi = 0; cbi < ctx->nblocks; cbi++) {
446 ctx->blocks[cbi].bytes = 0;
447 free(ctx->blocks[cbi].data);
448 ctx->blocks[cbi].data = NULL;
449 }
450
451 free(ctx->blocks);
452 ctx->blocks = NULL;
453 ctx->end_bi = 0;
454 ctx->nblocks = 0;
455 }
456 }
457
kill_child(struct sndctx * ctx)458 static void kill_child(struct sndctx *ctx)
459 {
460 if (ctx->pid != -1) {
461 kill(ctx->pid, SIGINT);
462 while (waitpid(ctx->pid, NULL, 0) <= 0);
463 ctx->pid = -1;
464 }
465 }
466
set_no_snd_file(struct sndctx * ctx)467 static void set_no_snd_file(struct sndctx *ctx)
468 {
469 ctx->normalfile = 1;
470
471 destroy_cache(ctx);
472
473 kill_child(ctx);
474
475 close(ctx->pipefd);
476 ctx->pipefd = -1;
477 }
478
destroy_ctx(struct sndctx * ctx)479 static void destroy_ctx(struct sndctx *ctx)
480 {
481 ctx->fname[0] = 0;
482
483 if (ctx->normalfile == 0)
484 set_no_snd_file(ctx);
485
486 free(ctx);
487 }
488
get_uadefs_file(struct fuse_file_info * fi)489 static inline struct sndctx *get_uadefs_file(struct fuse_file_info *fi)
490 {
491 return (struct sndctx *) (uintptr_t) fi->fh;
492 }
493
check_stash(const char * fname,struct stash * stash,time_t t)494 static int check_stash(const char *fname, struct stash *stash, time_t t)
495 {
496 if (strcmp(fname, stash->fname) != 0)
497 return 0;
498
499 /* Reject old stashes */
500 if (t >= (stash->created + STASH_TIME))
501 return 0;
502
503 return 1;
504 }
505
warm_up_cache(struct sndctx * ctx)506 int warm_up_cache(struct sndctx *ctx)
507 {
508 char crapbuf[STASH_SIZE];
509 ssize_t s;
510 int i;
511 struct stash *stash;
512 size_t offs;
513 time_t created;
514
515 created = time(NULL);
516 if (created == ((time_t) -1)) {
517 LOG("Clock failed\n");
518 created = 0;
519 }
520
521 for (i = 0; i < NSTASHES; i++) {
522 if (check_stash(ctx->fname, &stashes[i], created)) {
523 LOG("Found stash for %s\n", ctx->fname);
524 if (cache_prefill(ctx, stashes[i].data))
525 return -EIO;
526 break;
527 }
528 }
529
530 /* Start uade iff no stash found */
531 if (i == NSTASHES) {
532 int ret = spawn_uade(ctx);
533 if (ret)
534 return ret;
535 }
536
537 for (offs = 0; offs < sizeof crapbuf; offs += CACHE_BLOCK_SIZE) {
538 if (cache_read(ctx, &crapbuf[offs], offs, CACHE_BLOCK_SIZE) < CACHE_BLOCK_SIZE) {
539 DEBUG("File is not playable: %s\n", ctx->fname);
540 set_no_snd_file(ctx);
541 return -EIO;
542 }
543 }
544
545 s = get_file_size(ctx->fname);
546 if (s > 0 &&
547 memcmp(&crapbuf[0], "RIFF", 4) == 0 &&
548 memcmp(&crapbuf[8], "WAVE", 4) == 0 ) {
549 /* Fix WAV header */
550 char data[4];
551
552 write_le_32(data, (int32_t) (s - 8));
553 cache_invasive_write(ctx, 4, data, 4);
554
555 write_le_32(data, (int32_t) (s - 44));
556 cache_invasive_write(ctx, 40, data, 4);
557 }
558
559 if (i == NSTASHES) {
560 /* We found no stash -> create one from crapbuf */
561 stash = &stashes[nextstash++];
562 if (nextstash >= NSTASHES)
563 nextstash = 0;
564
565 if (sizeof(stash->data) != sizeof(crapbuf))
566 LOGDIE("Stash data != crapbuf\n");
567
568 stash->created = created;
569 strlcpy(stash->fname, ctx->fname, sizeof stash->fname);
570 memcpy(stash->data, crapbuf, sizeof stash->data);
571
572 LOG("Allocated stash for %s\n", ctx->fname);
573 }
574
575 return 0;
576 }
577
open_file(int * success,const char * path,int isuade)578 static struct sndctx *open_file(int *success, const char *path, int isuade)
579 {
580 int ret;
581 struct sndctx *ctx;
582 struct stat st;
583
584 ctx = create_ctx(path);
585 if (ctx == NULL) {
586 ret = -ENOMEM;
587 goto err;
588 }
589
590 if (stat(path, &st)) {
591 ret = -errno;
592 goto err;
593 }
594
595 if (!S_ISREG(st.st_mode) || !isuade) {
596 set_no_snd_file(ctx);
597 goto out;
598 }
599
600 cache_init(ctx);
601
602 ret = warm_up_cache(ctx);
603 if (ret < 0)
604 goto err;
605 out:
606 *success = 0;
607 return ctx;
608
609 err:
610 if (ctx)
611 destroy_ctx(ctx);
612
613 *success = ret;
614 return NULL;
615 }
616
load_content_db(void)617 static void load_content_db(void)
618 {
619 struct stat st;
620 char name[PATH_MAX] = "";
621 char *home;
622 int ret;
623
624 home = getenv("HOME");
625 if (home)
626 snprintf(name, sizeof name, "%s/.uade2/contentdb", home);
627
628 /* User database has priority over global database, so we read it
629 * first */
630 if (name[0]) {
631 if (stat(name, &st) == 0) {
632 if (mtime < st.st_mtime) {
633 ret = uade_read_content_db(name);
634 if (stat(name, &st) == 0)
635 mtime = st.st_mtime;
636 if (ret)
637 return;
638 }
639 } else {
640 FILE *f = fopen(name, "w");
641 if (f)
642 fclose(f);
643 uade_read_content_db(name);
644 }
645 }
646
647 snprintf(name, sizeof name, "%s/contentdb.conf", uadestate.config.basedir.name);
648 if (stat(name, &st) == 0 && mtime < st.st_mtime) {
649 uade_read_content_db(name);
650 if (stat(name, &st) == 0)
651 mtime = st.st_mtime;
652 }
653 }
654
655 /*
656 * If the file is an uade song, return a heuristic wav file size, a positive
657 * integer. Otherwise, return zero.
658 */
get_file_size(const char * path)659 static ssize_t get_file_size(const char *path)
660 {
661 int64_t msecs;
662
663 if (!uade_is_our_file(path, 1, &uadestate))
664 return 0;
665
666 /*
667 * HACK HACK. Use playlength stored in the content database
668 * or lie about the time.
669 */
670 load_content_db();
671 if (!uade_alloc_song(&uadestate, path))
672 return -1;
673
674 msecs = uadestate.song->playtime;
675 uade_unalloc_song(&uadestate);
676
677 if (msecs > 3600000)
678 return -1;
679
680 if (msecs <= 0)
681 msecs = 1000 * CACHE_SECONDS;
682
683 return WAV_HEADER_LEN + (((msecs * SND_PER_SECOND) / 1000) & ~0x3);
684 }
685
uadefs_getattr(const char * fpath,struct stat * stbuf)686 static int uadefs_getattr(const char *fpath, struct stat *stbuf)
687 {
688 int res;
689 char *path = uadefs_get_path(NULL, fpath);
690 ssize_t s;
691
692 res = lstat(path, stbuf);
693 if (res == -1) {
694 free(path);
695 return -errno;
696 }
697
698 s = get_file_size(path);
699
700 free(path);
701 path = NULL;
702
703 if (s > 0) {
704 stbuf->st_size = s; /* replace the lstat() value */
705 stbuf->st_blocks = stbuf->st_size / 512;
706 } else if (s < 0) {
707 return -ENOMEM;
708 }
709 /* For s == 0, the result of lstat() is returned */
710 return 0;
711 }
712
uadefs_access(const char * fpath,int mask)713 static int uadefs_access(const char *fpath, int mask)
714 {
715 int res;
716 char *path = uadefs_get_path(NULL, fpath);
717
718 res = access(path, mask);
719
720 free(path);
721
722 if (res == -1)
723 return -errno;
724
725 return 0;
726 }
727
uadefs_readlink(const char * fpath,char * buf,size_t size)728 static int uadefs_readlink(const char *fpath, char *buf, size_t size)
729 {
730 int res;
731 char *path = uadefs_get_path(NULL, fpath);
732
733 res = readlink(path, buf, size - 1);
734
735 free(path);
736
737 if (res == -1)
738 return -errno;
739
740 buf[res] = '\0';
741 return 0;
742 }
743
744
gen_uade_name(char * name,size_t maxname,mode_t mode,const char * dirname,const char * filename)745 static void gen_uade_name(char *name, size_t maxname, mode_t mode,
746 const char *dirname, const char *filename)
747 {
748 char fullname[PATH_MAX];
749
750 snprintf(name, maxname, "%s", filename);
751
752 if (!S_ISREG(mode))
753 return;
754
755 snprintf(fullname, sizeof fullname, "%s/%s", dirname, filename);
756
757 if (!uade_is_our_file(fullname, 1, &uadestate))
758 return;
759
760 snprintf(name, maxname, "%s.wav", filename);
761 }
762
763
uadefs_readdir(const char * fpath,void * buf,fuse_fill_dir_t filler,off_t offset,struct fuse_file_info * fi)764 static int uadefs_readdir(const char *fpath, void *buf, fuse_fill_dir_t filler,
765 off_t offset, struct fuse_file_info *fi)
766 {
767 DIR *dp;
768 struct dirent *de;
769 char *path = uadefs_get_path(NULL, fpath);
770 char name[256];
771 char fullname[PATH_MAX];
772
773 (void) offset;
774 (void) fi;
775
776 dp = opendir(path);
777
778 if (dp == NULL) {
779 free(path);
780 return -errno;
781 }
782
783 while ((de = readdir(dp)) != NULL) {
784 struct stat st;
785 memset(&st, 0, sizeof(st));
786 st.st_ino = de->d_ino;
787 st.st_mode = de->d_type << 12;
788 if (st.st_mode == 0) {
789 /* de->d_type not supported -> use stat() */
790 struct stat oldst;
791 snprintf(fullname, sizeof fullname, "%s/%s", path, de->d_name);
792 if (!stat(fullname, &oldst))
793 st.st_mode = oldst.st_mode & ~0777;
794 }
795
796 gen_uade_name(name, sizeof name, st.st_mode, path, de->d_name);
797
798 if (filler(buf, name, &st, 0))
799 break;
800 }
801
802 free(path);
803 closedir(dp);
804 return 0;
805 }
806
uadefs_mknod(const char * fpath,mode_t mode,dev_t rdev)807 static int uadefs_mknod(const char *fpath, mode_t mode, dev_t rdev)
808 {
809 (void) mode;
810 (void) fpath;
811 (void) rdev;
812 return -EACCES;
813 }
814
uadefs_mkdir(const char * fpath,mode_t mode)815 static int uadefs_mkdir(const char *fpath, mode_t mode)
816 {
817 int res;
818 char *path = uadefs_get_path(NULL, fpath);
819
820 res = mkdir(path, mode);
821
822 free(path);
823
824 if (res == -1)
825 return -errno;
826
827 return 0;
828 }
829
uadefs_unlink(const char * fpath)830 static int uadefs_unlink(const char *fpath)
831 {
832 int res;
833 char *path = uadefs_get_path(NULL, fpath);
834
835 res = unlink(path);
836
837 free(path);
838
839 if (res == -1)
840 return -errno;
841
842 return 0;
843 }
844
uadefs_rmdir(const char * fpath)845 static int uadefs_rmdir(const char *fpath)
846 {
847 int res;
848 char *path = uadefs_get_path(NULL, fpath);
849
850 res = rmdir(path);
851
852 free(path);
853
854 if (res == -1)
855 return -errno;
856
857 return 0;
858 }
859
uadefs_symlink(const char * ffrom,const char * fto)860 static int uadefs_symlink(const char *ffrom, const char *fto)
861 {
862 int res;
863 char *from = uadefs_get_path(NULL, ffrom);
864 char *to = uadefs_get_path(NULL, fto);
865
866 res = symlink(from, to);
867
868 free(from);
869 free(to);
870
871 if (res == -1)
872 return -errno;
873
874 return 0;
875 }
876
uadefs_rename(const char * ffrom,const char * fto)877 static int uadefs_rename(const char *ffrom, const char *fto)
878 {
879 int res;
880 char *from = uadefs_get_path(NULL, ffrom);
881 char *to = uadefs_get_path(NULL, fto);
882
883 res = rename(from, to);
884
885 free(from);
886 free(to);
887
888 if (res == -1)
889 return -errno;
890
891 return 0;
892 }
893
uadefs_link(const char * ffrom,const char * fto)894 static int uadefs_link(const char *ffrom, const char *fto)
895 {
896 int res;
897 char *from = uadefs_get_path(NULL, ffrom);
898 char *to = uadefs_get_path(NULL, fto);
899
900 res = link(from, to);
901
902 free(from);
903 free(to);
904
905 if (res == -1)
906 return -errno;
907
908 return 0;
909 }
910
uadefs_chmod(const char * fpath,mode_t mode)911 static int uadefs_chmod(const char *fpath, mode_t mode)
912 {
913 int res;
914 char *path = uadefs_get_path(NULL, fpath);
915
916 res = chmod(path, mode);
917
918 free(path);
919
920 if (res == -1)
921 return -errno;
922
923 return 0;
924 }
925
uadefs_chown(const char * fpath,uid_t uid,gid_t gid)926 static int uadefs_chown(const char *fpath, uid_t uid, gid_t gid)
927 {
928 int res;
929 char *path = uadefs_get_path(NULL, fpath);
930
931 res = lchown(path, uid, gid);
932
933 free(path);
934
935 if (res == -1)
936 return -errno;
937
938 return 0;
939 }
940
uadefs_truncate(const char * fpath,off_t size)941 static int uadefs_truncate(const char *fpath, off_t size)
942 {
943 (void) fpath;
944 (void) size;
945
946 return -EIO;
947 }
948
uadefs_utimens(const char * fpath,const struct timespec ts[2])949 static int uadefs_utimens(const char *fpath, const struct timespec ts[2])
950 {
951 int res;
952 struct timeval tv[2];
953 char *path = uadefs_get_path(NULL, fpath);
954
955 tv[0].tv_sec = ts[0].tv_sec;
956 tv[0].tv_usec = ts[0].tv_nsec / 1000;
957 tv[1].tv_sec = ts[1].tv_sec;
958 tv[1].tv_usec = ts[1].tv_nsec / 1000;
959
960 res = utimes(path, tv);
961
962 free(path);
963
964 if (res == -1)
965 return -errno;
966
967 return 0;
968 }
969
uadefs_open(const char * fpath,struct fuse_file_info * fi)970 static int uadefs_open(const char *fpath, struct fuse_file_info *fi)
971 {
972 int ret;
973 struct sndctx *ctx;
974 int isuade;
975 char *path = uadefs_get_path(&isuade, fpath);
976
977 if (fi->flags & O_CREAT) {
978 free(path);
979 return -EPERM;
980 }
981
982 ctx = open_file(&ret, path, isuade);
983
984 free(path);
985
986 if (ctx == NULL)
987 return ret;
988
989 fi->direct_io = 1;
990 fi->fh = (uint64_t) (uintptr_t) ctx;
991
992 DEBUG("Opened %s as %s file\n", ctx->fname, ctx->normalfile ? "normal" : "UADE");
993 return 0;
994 }
995
uadefs_read(const char * fpath,char * buf,size_t size,off_t off,struct fuse_file_info * fi)996 static int uadefs_read(const char *fpath, char *buf, size_t size, off_t off,
997 struct fuse_file_info *fi)
998 {
999 int fd;
1000 size_t res;
1001 struct sndctx *ctx = get_uadefs_file(fi);
1002 ssize_t totalread = 0;
1003 size_t bsize;
1004
1005 if (ctx->normalfile) {
1006 char *path = uadefs_get_path(NULL, fpath);
1007
1008 fd = open(path, O_RDONLY);
1009
1010 free(path);
1011
1012 if (fd == -1)
1013 return -errno;
1014
1015 totalread = pread(fd, buf, size, off);
1016 if (totalread == -1)
1017 totalread = -errno;
1018
1019 close(fd);
1020
1021 return totalread;
1022 }
1023
1024 pthread_mutex_lock(&readmutex);
1025
1026 while (size > 0) {
1027 bsize = MIN(CACHE_BLOCK_SIZE - (off & CACHE_LSB_MASK), size);
1028 res = cache_read(ctx, buf, off, bsize);
1029 if (res == 0)
1030 break;
1031
1032 totalread += res;
1033 buf += res;
1034 off += res;
1035 size -= res;
1036 }
1037
1038 DEBUG("read() returns %zd\n", totalread);
1039 pthread_mutex_unlock(&readmutex);
1040
1041 return totalread;
1042 }
1043
uadefs_write(const char * fpath,const char * buf,size_t size,off_t offset,struct fuse_file_info * fi)1044 static int uadefs_write(const char *fpath, const char *buf, size_t size,
1045 off_t offset, struct fuse_file_info *fi)
1046 {
1047 (void) fpath;
1048 (void) buf;
1049 (void) size;
1050 (void) offset;
1051 (void) fi;
1052
1053 return -EIO;
1054 }
1055
uadefs_statfs(const char * fpath,struct statvfs * stbuf)1056 static int uadefs_statfs(const char *fpath, struct statvfs *stbuf)
1057 {
1058 int res;
1059 char *path = uadefs_get_path(NULL, fpath);
1060
1061 res = statvfs(path, stbuf);
1062
1063 free(path);
1064
1065 if (res == -1)
1066 return -errno;
1067
1068 return 0;
1069 }
1070
uadefs_flush(const char * fpath,struct fuse_file_info * fi)1071 static int uadefs_flush(const char *fpath, struct fuse_file_info *fi)
1072 {
1073 (void) fi;
1074 (void) fpath;
1075 return 0;
1076 }
1077
uadefs_release(const char * fpath,struct fuse_file_info * fi)1078 static int uadefs_release(const char *fpath, struct fuse_file_info *fi)
1079 {
1080 destroy_ctx(get_uadefs_file(fi));
1081
1082 DEBUG("release %s\n", fpath);
1083
1084 return 0;
1085 }
1086
uadefs_fsync(const char * fpath,int isdatasync,struct fuse_file_info * fi)1087 static int uadefs_fsync(const char *fpath, int isdatasync,
1088 struct fuse_file_info *fi)
1089 {
1090 /* Just a stub. This method is optional and can safely be left
1091 unimplemented */
1092
1093 (void) fpath;
1094 (void) isdatasync;
1095 (void) fi;
1096 return 0;
1097 }
1098
1099 #ifdef HAVE_SETXATTR
1100 /* xattr operations are optional and can safely be left unimplemented */
uadefs_setxattr(const char * fpath,const char * name,const char * value,size_t size,int flags)1101 static int uadefs_setxattr(const char *fpath, const char *name, const char *value,
1102 size_t size, int flags)
1103 {
1104 char *path = uadefs_get_path(NULL, fpath);
1105 int res;
1106
1107 res = lsetxattr(path, name, value, size, flags);
1108
1109 free(path);
1110
1111 if (res == -1)
1112 return -errno;
1113 return 0;
1114 }
1115
uadefs_getxattr(const char * fpath,const char * name,char * value,size_t size)1116 static int uadefs_getxattr(const char *fpath, const char *name, char *value,
1117 size_t size)
1118 {
1119 char *path = uadefs_get_path(NULL, fpath);
1120 int res;
1121
1122 res = lgetxattr(path, name, value, size);
1123
1124 free(path);
1125
1126 if (res == -1)
1127 return -errno;
1128 return res;
1129 }
1130
uadefs_listxattr(const char * fpath,char * list,size_t size)1131 static int uadefs_listxattr(const char *fpath, char *list, size_t size)
1132 {
1133 char *path = uadefs_get_path(NULL, fpath);
1134 int res;
1135
1136 res = llistxattr(path, list, size);
1137
1138 free(path);
1139
1140 if (res == -1)
1141 return -errno;
1142 return res;
1143 }
1144
uadefs_removexattr(const char * fpath,const char * name)1145 static int uadefs_removexattr(const char *fpath, const char *name)
1146 {
1147 char *path = uadefs_get_path(NULL, fpath);
1148 int res;
1149
1150 res = lremovexattr(path, name);
1151
1152 free(path);
1153
1154 if (res == -1)
1155 return -errno;
1156 return 0;
1157 }
1158 #endif /* HAVE_SETXATTR */
1159
1160 static struct fuse_operations uadefs_oper = {
1161 .getattr = uadefs_getattr,
1162 .access = uadefs_access,
1163 .readlink = uadefs_readlink,
1164 .readdir = uadefs_readdir,
1165 .mknod = uadefs_mknod,
1166 .mkdir = uadefs_mkdir,
1167 .symlink = uadefs_symlink,
1168 .unlink = uadefs_unlink,
1169 .rmdir = uadefs_rmdir,
1170 .rename = uadefs_rename,
1171 .link = uadefs_link,
1172 .chmod = uadefs_chmod,
1173 .chown = uadefs_chown,
1174 .truncate = uadefs_truncate,
1175 .utimens = uadefs_utimens,
1176 .open = uadefs_open,
1177 .read = uadefs_read,
1178 .write = uadefs_write,
1179 .statfs = uadefs_statfs,
1180 .flush = uadefs_flush,
1181 .release = uadefs_release,
1182 .fsync = uadefs_fsync,
1183 #ifdef HAVE_SETXATTR
1184 .setxattr = uadefs_setxattr,
1185 .getxattr = uadefs_getxattr,
1186 .listxattr = uadefs_listxattr,
1187 .removexattr = uadefs_removexattr,
1188 #endif
1189 };
1190
usage(const char * progname)1191 static void usage(const char *progname)
1192 {
1193 fprintf(stderr,
1194 "usage: %s musicdir mountpoint [options]\n"
1195 "\n"
1196 "general options:\n"
1197 " -o opt,[opt...] mount options\n"
1198 " -h --help print help\n"
1199 " -V --version print version\n"
1200 "\n", progname);
1201 }
1202
1203 enum {
1204 KEY_HELP,
1205 KEY_VERSION,
1206 KEY_FOREGROUND,
1207 };
1208
1209 static struct fuse_opt uadefs_opts[] = {
1210 FUSE_OPT_KEY("-V", KEY_VERSION),
1211 FUSE_OPT_KEY("--version", KEY_VERSION),
1212 FUSE_OPT_KEY("-h", KEY_HELP),
1213 FUSE_OPT_KEY("--help", KEY_HELP),
1214 FUSE_OPT_KEY("debug", KEY_FOREGROUND),
1215 FUSE_OPT_KEY("-d", KEY_FOREGROUND),
1216 FUSE_OPT_KEY("-f", KEY_FOREGROUND),
1217 FUSE_OPT_END
1218 };
1219
uadefs_fuse_main(struct fuse_args * args)1220 static int uadefs_fuse_main(struct fuse_args *args)
1221 {
1222 #if FUSE_VERSION >= 26
1223 return fuse_main(args->argc, args->argv, &uadefs_oper, NULL);
1224 #else
1225 return fuse_main(args->argc, args->argv, &uadefs_oper);
1226 #endif
1227 }
1228
uadefs_opt_proc(void * data,const char * arg,int key,struct fuse_args * outargs)1229 static int uadefs_opt_proc(void *data, const char *arg, int key,
1230 struct fuse_args *outargs)
1231 {
1232 (void) data;
1233 char dname[4096];
1234
1235 switch (key) {
1236 case FUSE_OPT_KEY_OPT:
1237 return 1;
1238
1239 case FUSE_OPT_KEY_NONOPT:
1240 if (!srcdir) {
1241 if (arg[0] == '/') {
1242 srcdir = strdup(arg);
1243 if (srcdir == NULL)
1244 DIE("No memory for srcdir\n");
1245 } else {
1246 if (getcwd(dname, sizeof dname) == NULL)
1247 DIE("getcwd() failed\n");
1248
1249 if (asprintf(&srcdir, "%s/%s", dname, arg) == -1)
1250 DIE("asprintf() failed\n");
1251 }
1252
1253 while (1) {
1254 size_t l = strlen(srcdir);
1255
1256 if (l == 1 && srcdir[0] == '/')
1257 break;
1258
1259 if (srcdir[l - 1] != '/')
1260 break;
1261
1262 srcdir[l - 1] = 0;
1263 }
1264
1265 return 0;
1266 }
1267 return 1;
1268
1269 case KEY_HELP:
1270 usage(outargs->argv[0]);
1271 fuse_opt_add_arg(outargs, "-ho");
1272 uadefs_fuse_main(outargs);
1273 exit(1);
1274
1275 case KEY_VERSION:
1276 fprintf(stderr, "uadefs version %s\n", UADE_VERSION);
1277 #if FUSE_VERSION >= 25
1278 fuse_opt_add_arg(outargs, "--version");
1279 uadefs_fuse_main(outargs);
1280 #endif
1281 exit(0);
1282
1283 case KEY_FOREGROUND:
1284 debugmode = 1;
1285 return 1;
1286
1287 default:
1288 fprintf(stderr, "internal error\n");
1289 abort();
1290 }
1291
1292 return 0;
1293 }
1294
init_uade(void)1295 static void init_uade(void)
1296 {
1297 char uadeconfname[4096];
1298
1299 (void) uade_load_initial_config(uadeconfname, sizeof uadeconfname,
1300 &uadestate.config, NULL);
1301
1302 load_content_db();
1303 }
1304
1305
main(int argc,char * argv[])1306 int main(int argc, char *argv[])
1307 {
1308 struct fuse_args args = FUSE_ARGS_INIT(argc, argv);
1309
1310 if (fuse_opt_parse(&args, NULL, uadefs_opts, uadefs_opt_proc) == -1)
1311 exit(1);
1312
1313 DEBUG("srcdir: %s\n", srcdir);
1314
1315 if (getenv("HOME")) {
1316 int flags = O_WRONLY | O_TRUNC | O_APPEND | O_CREAT;
1317 int fmode = S_IRUSR | S_IWUSR;
1318 char logfname[4096];
1319
1320 snprintf(logfname, sizeof logfname, "%s/.uade2/uadefs.log", getenv("HOME"));
1321 debugfd = open(logfname, flags, fmode);
1322 }
1323
1324 init_uade();
1325
1326 umask(0);
1327 return uadefs_fuse_main(&args);
1328 }
1329