diff options
author | Kjetil Ørbekk <orbekk@pvv.ntnu.no> | 2008-08-15 21:54:18 +0200 |
---|---|---|
committer | Kjetil Ørbekk <orbekk@pvv.ntnu.no> | 2008-08-15 21:54:18 +0200 |
commit | d554386b01ba7edbb4fc8547d6f0bc6dcaec15c3 (patch) | |
tree | 2546b1850d80dcf9191552fa7aad0e0201feba3b | |
parent | c054405a1e256e9cf41ed2121e7dabeca518b592 (diff) | |
parent | aaccd1929a253e6e687f50a810877bb9eb4ea8df (diff) |
Merge branch 'config'
-rwxr-xr-x | README | 6 | ||||
-rw-r--r-- | dbschema.sql | 5 | ||||
-rw-r--r-- | include/musicfs.h | 10 | ||||
-rw-r--r-- | initialize.sh | 17 | ||||
-rw-r--r-- | src/mfs_subr.c | 166 | ||||
-rwxr-xr-x | src/mfs_vnops.c | 198 |
6 files changed, 367 insertions, 35 deletions
@@ -18,11 +18,15 @@ $ sqlite3 music.db < dbschema.sql 3. Run: -$ ./musicfs -d <music path> <mount path> +$ ./musicfs -d <mount path> On my computer, it only behaves correctly in debug mode (-d) due to a bug of some kind. I don't really know why :'( +4. Add music directory: + +Edit <mount path>/.config and follow the instructions. + Dependencies ~~~~~~~~~~~~ diff --git a/dbschema.sql b/dbschema.sql index 2fcf0c9..6d730d9 100644 --- a/dbschema.sql +++ b/dbschema.sql @@ -23,3 +23,8 @@ CREATE TABLE genre ( name varchar(200) NOT NULL, PRIMARY KEY(name) ); + +CREATE TABLE path ( + path varchar(255), + PRIMARY KEY(path) +); diff --git a/include/musicfs.h b/include/musicfs.h index 3da10da..8443198 100644 --- a/include/musicfs.h +++ b/include/musicfs.h @@ -22,10 +22,8 @@ #define _MP3FS_H_ struct fuse_args; -#define DBNAME "music.db" - int mfs_run(int, char **); -int mfs_initscan(char *); +int mfs_initscan(); /* @@ -33,7 +31,7 @@ int mfs_initscan(char *); * files, for instance scanning the collection. */ typedef void traverse_fn_t(char *); -void traverse_hierarchy(char *, traverse_fn_t); +void traverse_hierarchy(const char *, traverse_fn_t); traverse_fn_t mfs_scan; /* @@ -65,6 +63,8 @@ lookup_fn_t mfs_lookup_list; lookup_fn_t mfs_lookup_open; /* Lookup function stat'ing a file. */ lookup_fn_t mfs_lookup_stat; +/* Lookup function loading a path into DB */ +lookup_fn_t mfs_lookup_load_path; struct lookuphandle; @@ -78,6 +78,8 @@ void mfs_lookup_album(const char *, struct filler_data *); char *mfs_gettoken(const char *, int); int mfs_numtoken(const char *); int mfs_file_data_for_path(const char *, void *); +int mfs_reload_config(); +char *mfs_get_home_path(const char *); enum mfs_filetype mfs_get_filetype(const char *); #endif diff --git a/initialize.sh b/initialize.sh new file mode 100644 index 0000000..e167ee7 --- /dev/null +++ b/initialize.sh @@ -0,0 +1,17 @@ +#!/bin/bash + +sqlite3 $HOME/.mfs.db < dbschema.sql + +cat > $HOME/.mfsrc <<EOF +# This is the musicfs configuration file. Lines starting with "#"s are +# comments. +# +# So far, only musicpaths can be configured. Add one path on its own +# line for every music path you want musicfs to scan. Do not add +# anything on the line exept for the musicpath. +# +# Example: +# /home/orbekk/Music +EOF + +echo "./musicfs -d # to start musicfs" diff --git a/src/mfs_subr.c b/src/mfs_subr.c index ab847f7..d3d3c0b 100644 --- a/src/mfs_subr.c +++ b/src/mfs_subr.c @@ -38,6 +38,8 @@ #include <sqlite3.h> #include <debug.h> +#define MFS_HANDLE ((void*)-1) + struct lookuphandle { sqlite3 *handle; sqlite3_stmt *st; @@ -48,21 +50,151 @@ struct lookuphandle { lookup_fn_t *lookup; }; +char *db_path; sqlite3 *handle; +/* + * Returns the path to $HOME[/extra] + */ +char *mfs_get_home_path(const char *extra) +{ + int hlen, exlen = 0; + char *res; + const char *home = getenv("HOME"); + + hlen = strlen(home); + if (extra) + exlen = strlen(extra); + + res = malloc(sizeof(char) * (hlen + exlen + 2)); + strcpy(res, home); + + if (extra) { + res[hlen] = '/'; + strcpy(res + hlen + 1, extra); + } + + return (res); +} + +/* + * Insert a musicpath into the database. + */ int -mfs_initscan(char *musicpath) +mfs_insert_path(char *path, sqlite3 *handle) { - int error; + int res; + sqlite3_stmt *st; + /* Add path to registered paths in DB */ + res = sqlite3_prepare_v2(handle, + "SELECT path FROM path WHERE path LIKE ?", + -1, &st, NULL); + if (res != SQLITE_OK) { + warnx("Error preparing stamtement: %s\n", + sqlite3_errmsg(handle)); + return (-1); + } + sqlite3_bind_text(st, 1, path, -1, SQLITE_TRANSIENT); + res = sqlite3_step(st); + sqlite3_finalize(st); + + if (res == SQLITE_DONE) { + DEBUG("Inserting path '%s' to paths\n", path); + /* Doesn't exist. Insert it */ + res = sqlite3_prepare_v2(handle, + "INSERT INTO path(path) VALUES(?)", + -1, &st, NULL); + if (res != SQLITE_OK) { + warnx("Error preparing stamtement: %s\n", + sqlite3_errmsg(handle)); + return (-1); + } + sqlite3_bind_text(st, 1, path, -1, SQLITE_TRANSIENT); + res = sqlite3_step(st); + sqlite3_finalize(st); + if (res != SQLITE_DONE) { + warnx("Error inserting into database: %s\n", + sqlite3_errmsg(handle)); + return (-1); + } + } + return (0); +} + +/* + * Reload the configuration from $HOME/.mfsrc + * + */ +int +mfs_reload_config() +{ + int res, len; + char *mfsrc = mfs_get_home_path(".mfsrc"); + char line[4096]; + struct lookuphandle *lh; + sqlite3 *handle; + FILE *f = fopen(mfsrc, "r"); + + if (f == NULL) { + warnx("Couldn't open configuration file %s\n", + mfsrc); + return (-1); + } + + res = sqlite3_open(db_path, &handle); + if (res) { + warnx("Can't open database: %s\n", sqlite3_errmsg(handle)); + sqlite3_close(handle); + return (-1); + } + + /* XXX: Just adding the paths for now. queue.h for the rest*/ + + while (fgets(line, 4096, f) != NULL) { + len = strlen(line); + if (len > 0 && line[0] != '\n' && line[0] != '#') { + if (line[len-1] == '\n') + line[len-1] = '\0'; + + res = mfs_insert_path(line, handle); + DEBUG("inserted path %s, returned(%d)\n", line, res); + } + } + + free (mfsrc); + sqlite3_close(handle); + + /* Do the actual loading */ + lh = mfs_lookup_start(0, MFS_HANDLE, mfs_lookup_load_path, + "SELECT path FROM path"); + mfs_lookup_finish(lh); + + sqlite3_close(handle); + return (0); +} + +int +mfs_initscan() +{ + int error; + db_path = mfs_get_home_path(".mfs.db"); /* Open database. */ - error = sqlite3_open(DBNAME, &handle); + error = sqlite3_open(db_path, &handle); if (error) { warnx("Can't open database: %s\n", sqlite3_errmsg(handle)); sqlite3_close(handle); return (-1); } - traverse_hierarchy(musicpath, mfs_scan); + +/* error = mfs_insert_path(musicpath, handle); */ +/* if (error != 0) */ +/* return (error); */ + + error = mfs_reload_config(); + if (error != 0) + return (error); + sqlite3_close(handle); return (0); } @@ -73,8 +205,9 @@ mfs_initscan(char *musicpath) * sub-directories. */ void -traverse_hierarchy(char *dirpath, traverse_fn_t fileop) +traverse_hierarchy(const char *dirpath, traverse_fn_t fileop) { + DEBUG("traversing %s\n", dirpath); DIR *dirp; struct dirent *dp; char filepath[MAXPATHLEN]; @@ -304,15 +437,22 @@ mfs_lookup_start(int field, void *data, lookup_fn_t *fn, const char *query) return (NULL); lh->field = field; lh->lookup = fn; - lh->priv = data; + /* Open database. */ - error = sqlite3_open(DBNAME, &lh->handle); + error = sqlite3_open(db_path, &lh->handle); if (error) { warnx("Can't open database: %s\n", sqlite3_errmsg(lh->handle)); sqlite3_close(lh->handle); free(lh); return (NULL); } + + if (data == MFS_HANDLE) + /* Workaround to give access to the handle */ + lh->priv = lh->handle; + else + lh->priv = data; + ret = sqlite3_prepare_v2(lh->handle, query, -1, &lh->st, NULL); if (ret != SQLITE_OK) { free(lh); @@ -735,6 +875,18 @@ mfs_lookup_stat(void *data, const char *str) } /* + * Load a path into database + */ +int +mfs_lookup_load_path(void *data, const char *str) +{ + handle = (sqlite3 *)data; + traverse_hierarchy(str, mfs_scan); + + return (0); +} + +/* * Guess on a filetype for a path. * * Examples: diff --git a/src/mfs_vnops.c b/src/mfs_vnops.c index 60c9ad6..bfb4fe1 100755 --- a/src/mfs_vnops.c +++ b/src/mfs_vnops.c @@ -28,6 +28,7 @@ #include <err.h> #include <sys/types.h> +#include <sys/time.h> #include <dirent.h> #include <fuse.h> #include <sys/param.h> @@ -38,9 +39,6 @@ #include <musicfs.h> #include <debug.h> -char musicpath[MAXPATHLEN]; // = "/home/lulf/dev/musicfs/music"; -char *logpath = "/home/lulf/dev/musicfs/musicfs.log"; - static int mfs_getattr (const char *path, struct stat *stbuf) { struct file_data fd; @@ -50,12 +48,20 @@ static int mfs_getattr (const char *path, struct stat *stbuf) int status = 0; memset (stbuf, 0, sizeof (struct stat)); - if (strcmp (path, "/") == 0) { + if (strcmp(path, "/") == 0) { stbuf->st_mode = S_IFDIR | 0755; stbuf->st_nlink = 2; return 0; } + if (strcmp(path, "/.config") == 0) { + char *mfsrc = mfs_get_home_path(".mfsrc"); + int res = stat(mfsrc, stbuf); + DEBUG("stat result for %s: %d\n", mfsrc, res); + free(mfsrc); + return (res); + } + enum mfs_filetype type = mfs_get_filetype(path); switch (type) { case MFS_DIRECTORY: @@ -102,6 +108,7 @@ static int mfs_readdir (const char *path, void *buf, fuse_fill_dir_t filler, filler(buf, "Genres", NULL, 0); filler(buf, "Tracks", NULL, 0); filler(buf, "Albums", NULL, 0); + filler(buf, ".config", NULL, 0); return (0); } @@ -136,6 +143,9 @@ static int mfs_open (const char *path, struct fuse_file_info *fi) fd.fd = -1; fd.found = 0; + if (strcmp(path, "/.config") == 0) + return (0); + int status = mfs_file_data_for_path(path, &fd); if (status != 0) return (status); @@ -166,6 +176,18 @@ static int mfs_read (const char *path, char *buf, size_t size, off_t offset, fd.found = 0; size_t bytes; + DEBUG("read: path(%s) offset(%d) size(%d)\n", path, (int)offset, + (int)size); + if (strcmp(path, "/.config") == 0) { + char *mfsrc = mfs_get_home_path(".mfsrc"); + int fd = open(mfsrc, O_RDONLY); + free(mfsrc); + lseek(fd, offset, SEEK_CUR); + bytes = read(fd, buf, size); + close(fd); + return (bytes); + } + int status = mfs_file_data_for_path(path, &fd); if (status != 0) return (status); @@ -186,24 +208,159 @@ static int mfs_read (const char *path, char *buf, size_t size, off_t offset, */ } +static int mfs_write(const char *path, const char *buf, size_t size, + off_t offset, struct fuse_file_info *fi) +{ + size_t bytes; + + DEBUG("write: path(%s) offset(%d) size(%d)\n", path, (int)offset, + (int)size); + + if (strcmp(path, "/.config") == 0) { + char *mfsrc = mfs_get_home_path(".mfsrc"); + int fd = open(mfsrc, O_WRONLY); + free(mfsrc); + lseek(fd, offset, SEEK_CUR); + bytes = write(fd, buf, size); + close(fd); + return (bytes); + } + + return (-1); +} + +static int mfs_create(const char *path, mode_t mode, struct fuse_file_info *fi) +{ + DEBUG("create %s\n", path); + return (-1); +} + +static int mfs_mknod(const char *path, mode_t mode, dev_t rdev) +{ + DEBUG("mknod %s\n", path); + return (-1); +} + +static int mfs_truncate(const char *path, off_t size) +{ + char *mfsrc; + int res; + DEBUG("truncating %s to size %d\n", path, (int)size); + + if (strcmp(path, "/.config") == 0) { + mfsrc = mfs_get_home_path(".mfsrc"); + res = truncate(mfsrc, size); + DEBUG("truncated %s with result: %d\n", mfsrc, res) + free(mfsrc); + return (res); + } + + return (-1); +} + +static int mfs_flush(const char *path, struct fuse_file_info *fi) +{ + DEBUG("flushing path %s\n", path); + if (strcmp(path, "/.config") == 0) { + return (0); + } + + return (-1); +} + +static int mfs_fsync(const char *path, int datasync, + struct fuse_file_info *fi) +{ + DEBUG("fsync path %s\n", path); + return (0); +} + +static int mfs_release(const char *path, struct fuse_file_info *fi) +{ + DEBUG("release %s\n", path); + + if (strcmp(path, "/.config") == 0) { + /* Reload configuration file */ + mfs_reload_config(); + } + + return (0); +} + +static int mfs_chmod(const char *path, mode_t mode) +{ + char *mfsrc; + int ret; + + DEBUG("chmod %s, %d\n", path, (int)mode); + if (strcmp(path, "/.config") == 0) { + mfsrc = mfs_get_home_path(".mfsrc"); + ret = chmod(mfsrc, mode); + free(mfsrc); + return (ret); + } + + return (-1); +} + +static int mfs_utimens(const char *path, const struct timespec tv[2]) +{ + char *mfsrc; + int ret; + + DEBUG("utime %s\n", path); + + if (strcmp(path, "/.config") == 0) { + mfsrc = mfs_get_home_path(".mfsrc"); + ret = 0; /* utimes(mfsrc, tval); */ + free(mfsrc); + return (ret); + } + + return (-1); +} + +static int mfs_access(const char *path, int mask) +{ + DEBUG("access called for path %s\n", path); + return (0); +} + +static int mfs_setxattr(const char *path, const char *name, + const char *val, size_t size, int flags) +{ + DEBUG("setxattr on path %s: %s=%s\n", path, name, val); + return (0); +} + static struct fuse_operations mfs_ops = { - .getattr = mfs_getattr, - .readdir = mfs_readdir, - .open = mfs_open, - .read = mfs_read, + .getattr = mfs_getattr, + .readdir = mfs_readdir, + .open = mfs_open, + .read = mfs_read, + .write = mfs_write, + .mknod = mfs_mknod, + .create = mfs_create, + .truncate = mfs_truncate, + .fsync = mfs_fsync, + .chmod = mfs_chmod, + .release = mfs_release, + .utimens = mfs_utimens, + .setxattr = mfs_setxattr, }; static int musicfs_opt_proc (void *data, const char *arg, int key, struct fuse_args *outargs) { - static int musicpath_set = 0; + /* Using config now. This is how we added the additional parameter: */ + /* static int musicpath_set = 0; */ + /* if (key == FUSE_OPT_KEY_NONOPT && !musicpath_set) { */ + /* /\* The source directory isn't already set, let's do it *\/ */ + /* strcpy(musicpath, arg); */ + /* musicpath_set = 1; */ + /* return (0); */ + /* } */ - if (key == FUSE_OPT_KEY_NONOPT && !musicpath_set) { - /* The source directory isn't already set, let's do it */ - strcpy(musicpath, arg); - musicpath_set = 1; - return (0); - } return (1); } @@ -211,13 +368,9 @@ int mfs_run(int argc, char **argv) { int ret; - /* - * XXX: Build index of mp3's. - */ - /* Update tables. */ - if (argc < 2) { - fprintf(stderr, "Usage: %s <musicfolder> <mountpoint>\n", argv[0]); + if (argc < 1) { + fprintf(stderr, "Usage: %s <mountpoint>\n", argv[0]); return (-1); } @@ -226,8 +379,7 @@ mfs_run(int argc, char **argv) if (fuse_opt_parse(&args, NULL, NULL, musicfs_opt_proc) != 0) exit (1); - DEBUG("musicpath: %s\n", musicpath); - mfs_initscan(musicpath); + mfs_initscan(); ret = 0; ret = fuse_main(args.argc, args.argv, &mfs_ops, NULL); |