summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKjetil Ørbekk <orbekk@pvv.ntnu.no>2008-08-15 21:54:18 +0200
committerKjetil Ørbekk <orbekk@pvv.ntnu.no>2008-08-15 21:54:18 +0200
commitd554386b01ba7edbb4fc8547d6f0bc6dcaec15c3 (patch)
tree2546b1850d80dcf9191552fa7aad0e0201feba3b
parentc054405a1e256e9cf41ed2121e7dabeca518b592 (diff)
parentaaccd1929a253e6e687f50a810877bb9eb4ea8df (diff)
Merge branch 'config'
-rwxr-xr-xREADME6
-rw-r--r--dbschema.sql5
-rw-r--r--include/musicfs.h10
-rw-r--r--initialize.sh17
-rw-r--r--src/mfs_subr.c166
-rwxr-xr-xsrc/mfs_vnops.c198
6 files changed, 367 insertions, 35 deletions
diff --git a/README b/README
index 07fe6e4..a32a6e2 100755
--- a/README
+++ b/README
@@ -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);