Кода стана твърде дълъг, все пак ще се опитам да го постна. Използва libid3tag и libspfs от проекта npfs на sourceforge (писан от колега-булгар).
Програмата се пуска:
mp3fs srcdir
Остава в background и чака на порт 1234 (може да се промени с опция -p). Файловата система се монтира:
mount -t 9p 127.0.0.1 /mnt/mp3 -o port=1234
GeSHi (C):
- #include <stdarg.h> 
- #include <stdio.h> 
- #include <stdlib.h> 
- #include <string.h> 
- #include <unistd.h> 
- #include <sys/stat.h> 
- #include <sys/types.h> 
- #include <fcntl.h> 
- #include <time.h> 
- #include <errno.h> 
- #include <dirent.h> 
- #include <id3tag.h> 
- #include <spfs.h> 
-   
- Spfile *createfile(Spfile *parent, char *name, u32 mode, void *ops, void *aux); 
- Spfile *findfile(Spfile *parent, char *name); 
- Spfile *dirfirst(Spfile *dir); 
- Spfile *dirnext(Spfile *dir, Spfile *prevchild); 
- int fileread(Spfilefid *, u64, u32, u8 *, Spreq *); 
- int fileopenfid(Spfilefid *); 
- void fileclosefid(Spfilefid *); 
-   
- Spdirops dops = { 
- 	.first = dirfirst, 
- 	.next = dirnext, 
- }; 
-   
- Spfileops fops = { 
- 	.read = fileread, 
- 	.openfid = fileopenfid, 
- 	.closefid = fileclosefid, 
- }; 
-   
- Spsrv *srv; 
- Spfile *root; 
- Spuser *user; 
- int nextid; 
-   
- void 
- sysfatal(char *fmt, ...) 
- { 
- 	va_list ap; 
-   
- 	va_start(ap, fmt); 
- 	vfprintf(stderr, fmt, ap); 
- 	va_end(ap); 
- 	exit(1); 
- } 
-   
- char * 
- getid(struct id3_tag *tag, char *id) 
- { 
- 	struct id3_frame *frm; 
- 	id3_ucs4_t const *str; 
- 	char *ret; 
-   
- 	frm = id3_tag_findframe(tag, id, 0); 
- 	if (!frm) 
- 		return NULL; 
-   
- 	if (strcmp(id, ID3_FRAME_COMMENT) == 0) 
- 		str = id3_field_getfullstring(&frm->fields[3]); 
- 	else 
- 		str = id3_field_getstrings(&frm->fields[1], 0); 
-   
- 	if (!str) 
- 		return NULL; 
-   
- 	ret = id3_ucs4_utf8duplicate(str); 
- 	return ret; 
- } 
-   
- char * 
- gettitle(struct id3_tag *tag) 
- { 
- 	return getid(tag, ID3_FRAME_TITLE); 
- } 
-   
- char * 
- getartist(struct id3_tag *tag) 
- { 
- 	return getid(tag, ID3_FRAME_ARTIST); 
- } 
-   
- char * 
- getalbum(struct id3_tag *tag) 
- { 
- 	return getid(tag, ID3_FRAME_ALBUM); 
- } 
-   
- int 
- process(char *fname) 
- { 
- 	char *fn, *artist, *album, *title; 
- 	struct stat st; 
- 	DIR *d; 
- 	struct dirent *de; 
- 	struct id3_file *f; 
- 	struct id3_tag *t; 
- 	Spfile *artdir, *albdir; 
-   
- 	if (stat(fname, &st) < 0) 
- 		sysfatal("cannot stat %s", fname); 
-   
- 	if (S_ISDIR(st.st_mode)) { 
- 		d = opendir(fname); 
- 		if (!d) 
- 			sysfatal("cannot open directory %s", fname); 
-   
- 		while ((de = readdir(d)) != NULL) { 
- 			if (de->d_name[0] == '.' && (de->d_name[1] == '.' || 
- 				de->d_name[1] == '\0')) 
- 				continue; 
-   
- 			fn = malloc(strlen(fname) + strlen(de->d_name) + 2); 
- 			sprintf(fn, "%s/%s", fname, de->d_name); 
- 			process(fn); 
- 			free(fn); 
- 		} 
- 		closedir(d); 
- 	} 
-   
- 	if (!S_ISREG(st.st_mode)) 
- 		return 0; 
-   
- 	f = id3_file_open(fname, ID3_FILE_MODE_READONLY); 
- 	if (!f) 
- 		sysfatal("cannot open file %s", fname); 
-   
- 	t = id3_file_tag(f); 
- 	if (!t) 
- 		sysfatal("cannot get tag"); 
-   
- 	artist = getartist(t); 
- 	album = getalbum(t); 
- 	title = gettitle(t); 
-   
- 	if (!artist) 
- 		artist = strdup("Unknown Artist"); 
-   
- 	artdir = findfile(root, artist); 
- 	if (!artdir) 
- 		artdir = createfile(root, artist, 0555 | Dmdir, &dops, NULL); 
-   
- 	if (!album) 
- 		album = strdup("Unknown Album"); 
-   
- 	albdir = findfile(artdir, album); 
- 	if (!albdir) 
- 		albdir = createfile(artdir, album, 0555 | Dmdir, &dops, NULL); 
-   
- 	if (!title) { 
- 		title = malloc(64); 
- 		snprintf(title, 64, "Track%d", nextid); 
- 	} 
-   
- 	fprintf(stderr, "process %s\n", fname); 
- 	createfile(albdir, title, 0444, &fops, strdup(fname)); 
- 	id3_file_close(f); 
-   
- 	return 0; 
- } 
-   
- Spfile * 
- findfile(Spfile *parent, char *name) 
- { 
- 	Spfile *f; 
-   
- 	for(f = parent->dirfirst; f != NULL; f = f->next) 
- 		if (strcmp(f->name, name) == 0) 
- 			return f; 
-   
- 	return NULL; 
- } 
-   
- Spfile * 
- createfile(Spfile *parent, char *name, u32 mode, void *ops, void *aux) 
- { 
- 	Spfile *ret; 
-   
- 	ret = spfile_alloc(parent, name, mode, nextid++, ops, aux); 
- 	if (parent->dirlast) { 
- 		parent->dirlast->next = ret; 
- 		ret->prev = parent->dirlast; 
- 	} else 
- 		parent->dirfirst = ret; 
-   
- 	parent->dirlast = ret; 
- 	ret->atime = ret->mtime = time(NULL); 
- 	ret->uid = ret->muid = user; 
- 	ret->gid = user->dfltgroup; 
- 	spfile_incref(ret); 
- 	return ret; 
- } 
-   
- Spfile* 
- dirfirst(Spfile *dir) 
- { 
- 	spfile_incref(dir->dirfirst); 
- 	return dir->dirfirst; 
- } 
-   
- Spfile* 
- dirnext(Spfile *dir, Spfile *prevchild) 
- { 
- 	spfile_incref(prevchild->next); 
- 	return prevchild->next; 
- } 
-   
- int 
- fileread(Spfilefid *fid, u64 offset, u32 count, u8 *data, Spreq *req) 
- { 
- 	int n, fd; 
-   
- 	fd = (int) fid->aux; 
- 	n = pread(fd, data, count, offset); 
- 	if (n < 0) 
- 		sp_uerror(errno); 
-   
- 	return n; 
- } 
-   
- int 
- fileopenfid(Spfilefid *fid) 
- { 
- 	int fd; 
- 	char *fname; 
- 	Spfile *f; 
-   
- 	f = fid->file; 
- 	fname = (char *) f->aux; 
- 	fd = open(fname, O_RDONLY); 
- 	if (fd < 0) { 
- 		sp_uerror(errno); 
- 		return 0; 
- 	} 
-   
- 	fid->aux = (void *) fd; 
- 	return 1; 
- } 
-   
- void 
- fileclosefid(Spfilefid *fid) 
- { 
- 	int fd; 
-   
- 	fd = (int) fid->aux; 
- 	close(fd); 
- } 
-   
- void 
- usage(void) 
- { 
- 	fprintf(stderr, "mp3fs -d -p port srcdir\n"); 
- 	exit(1); 
- } 
-   
- int 
- main(int argc, char *argv[]) 
- { 
- 	int port, ecode, c, debuglevel; 
- 	pid_t pid; 
- 	char *s, *ename; 
-   
- 	user = sp_uid2user(geteuid()); 
- 	root = spfile_alloc(NULL, "", 0555 | Dmdir, 0, &dops, NULL); 
- 	root->parent = root; 
- 	spfile_incref(root); 
- 	root->atime = root->mtime = time(NULL); 
- 	root->uid = root->muid = user; 
- 	root->gid = user->dfltgroup; 
- 	port = 1234; 
-   
- 	while ((c = getopt(argc, argv, "dp:")) != -1) { 
- 		switch (c) { 
- 		case 'd': 
- 			debuglevel = 1; 
- 			break; 
-   
- 		case 'p': 
- 			port = strtol(optarg, &s, 10); 
- 			if (*s != '\0') 
- 				usage(); 
- 			break; 
-   
- 		case 'h': 
- 		default: 
- 			usage(); 
- 		} 
- 	} 
-   
- 	if (optind >= argc) 
- 		usage(); 
-   
- 	process(argv[optind]); 
- 	srv = sp_socksrv_create_tcp(&port); 
- 	if (!srv) 
- 		goto error; 
-   
- 	srv->debuglevel = debuglevel; 
- 	spfile_init_srv(srv, root); 
- 	sp_srv_start(srv); 
- 	if (!debuglevel) { 
- 		close(0); 
- 		open("/dev/null", O_RDONLY); 
- 		close(1); 
- 		open("/dev/null", O_WRONLY); 
- 		close(2); 
- 		open("/dev/null", O_WRONLY); 
-   
- 		pid = fork(); 
- 		if (pid < 0) { 
- 			fprintf(stderr, "cannot fork\n"); 
- 			return -1; 
- 		} 
-   
- 		if (pid != 0) { 
- 			/* parent */ 
- 			return 0; 
- 		} 
-   
- 		/* child */ 
- 		setsid(); 
- 		chdir("/"); 
- 	} 
- 	fprintf(stderr, "start listening\n"); 
- 	sp_poll_loop(); 
-   
- 	return 0; 
-   
- error: 
- 	sp_rerror(&ename, &ecode); 
- 	fprintf(stderr, "Error: %s\n", ename); 
- 	return -1; 
- }