diff options
author | Andreas Baumann <abaumann@yahoo.com> | 2012-04-06 16:01:04 +0200 |
---|---|---|
committer | Andreas Baumann <abaumann@yahoo.com> | 2012-04-06 16:01:04 +0200 |
commit | 5e01f9c1b7738cecac65d3ab9d6a0d3b81a7da2a (patch) | |
tree | 1956104e384183aab457d0fec453aaf2beb8167c | |
parent | 27be13723862113873a2b52462ab71d47317fae5 (diff) | |
download | pgfuse-5e01f9c1b7738cecac65d3ab9d6a0d3b81a7da2a.tar.gz pgfuse-5e01f9c1b7738cecac65d3ab9d6a0d3b81a7da2a.tar.bz2 |
a very first DB select on mkdir
-rw-r--r-- | Makefile | 6 | ||||
-rw-r--r-- | pgfuse.c | 115 | ||||
-rw-r--r-- | test.sql | 38 |
3 files changed, 146 insertions, 13 deletions
@@ -16,9 +16,11 @@ clean: rm -f pgfuse pgfuse.o test: pgfuse - -./pgfuse "" mnt + -./pgfuse -v "" mnt mount | grep pgfuse - -ls mnt + -mkdir mnt/dir + -mkdir mnt/dir/dir2 + -ls -al mnt fusermount -u mnt pgfuse: pgfuse.o @@ -23,6 +23,9 @@ #include <libgen.h> /* for basename */ #include <syslog.h> /* for openlog, syslog */ #include <errno.h> /* for ENOENT and friends */ +#include <sys/types.h> +#include <sys/stat.h> +#include <arpa/inet.h> /* for htonl, ntohl */ #include <fuse.h> /* for user-land filesystem */ #include <fuse_opt.h> /* fuse command line parser */ @@ -32,30 +35,40 @@ /* --- fuse callbacks --- */ typedef struct PgFuseData { - char *conninfo; - char *mountpoint; - PGconn *conn; + int verbose; /* whether we should be verbose */ + char *conninfo; /* connection info as used in PQconnectdb */ + char *mountpoint; /* where we mount the virtual filesystem */ + PGconn *conn; /* the database handle to operate on */ } PgFuseData; static void *pgfuse_init( struct fuse_conn_info *conn ) { PgFuseData *data = (PgFuseData *)fuse_get_context( )->private_data; - syslog( LOG_INFO, "Mounting file system on '%s' (%s)", - data->mountpoint, data->conninfo ); + + if( data->verbose ) { + syslog( LOG_INFO, "Mounting file system on '%s' (%s)", + data->mountpoint, data->conninfo ); + } + return data; } static void pgfuse_destroy( void *userdata ) { - PgFuseData *data = (PgFuseData *)userdata; - syslog( LOG_INFO, "Unmounting file system on '%s' (%s)", - data->mountpoint, data->conninfo ); + PgFuseData *data = (PgFuseData *)userdata; + if( data->verbose ) { + syslog( LOG_INFO, "Unmounting file system on '%s' (%s)", + data->mountpoint, data->conninfo ); + } } static int pgfuse_getattr( const char *path, struct stat *stbuf ) { PgFuseData *data = (PgFuseData *)fuse_get_context( )->private_data; - syslog( LOG_INFO, "GetAttrs '%s' on '%s'", path, data->mountpoint ); + + if( data->verbose ) { + syslog( LOG_INFO, "GetAttrs '%s' on '%s'", path, data->mountpoint ); + } memset( stbuf, 0, sizeof( struct stat ) ); @@ -64,6 +77,11 @@ static int pgfuse_getattr( const char *path, struct stat *stbuf ) stbuf->st_mode = S_IFDIR | 0755; stbuf->st_nlink = 2; return 0; + } else if( strcmp( path, "/README" ) == 0 ) { + stbuf->st_mode = S_IFREG | 0444; + stbuf->st_nlink = 1; + stbuf->st_size = strlen( "This is a PgFuse mount point" ); + return 0; } else { return -ENOENT; } @@ -72,7 +90,80 @@ static int pgfuse_getattr( const char *path, struct stat *stbuf ) static int pgfuse_readdir( const char *path, void *buf, fuse_fill_dir_t filler, off_t offset, struct fuse_file_info *fi ) { - syslog( LOG_INFO, "Readdir '%s'", path ); + PgFuseData *data = (PgFuseData *)fuse_get_context( )->private_data; + + if( data->verbose ) { + syslog( LOG_INFO, "Readdir '%s'", path ); + } + + filler( buf, ".", NULL, 0 ); + filler( buf, "..", NULL, 0 ); + filler( buf, "README", NULL, 0 ); + + return 0; +} + +static int psql_get_parent_id( PGconn *conn, const char *path ) +{ + PGresult *res; + int i_fnum; + char *iptr; + int parent_id; + + const char *values[1] = { path }; + int lengths[1] = { strlen( path ) }; + int binary[1] = { 1 }; + + res = PQexecParams( conn, "SELECT parent_id FROM dir WHERE path = $1::varchar", + 1, NULL, values, lengths, binary, 1 ); + + if( PQresultStatus( res ) != PGRES_TUPLES_OK ) { + syslog( LOG_ERR, "Error in psql_get_parent_id for path '%s'", path ); + return -EIO; + } + + if( PQntuples( res ) != 1 ) { + syslog( LOG_ERR, "Expecting exactly one inode for path '%s' in psql_get_parent_id, data inconsistent!", path ); + return -EIO; + } + + i_fnum = PQfnumber( res, "parent_id" ); + iptr = PQgetvalue( res, 0, i_fnum ); + parent_id = ntohl( *( (uint32_t *)iptr ) ); + + return parent_id; +} + +static int pgfuse_mkdir( const char *path, mode_t mode ) +{ + PgFuseData *data = (PgFuseData *)fuse_get_context( )->private_data; + char *parent_path; + int parent_id; + + if( data->verbose ) { + syslog( LOG_INFO, "Mkdir '%s' in mode '%o'", path, (unsigned int)mode ); + } + + parent_path = strdup( path ); + if( parent_path == NULL ) { + syslog( LOG_ERR, "Out of memory in Mkdir '%s'!", path ); + return -EIO; + } + + dirname( parent_path ); + + parent_id = psql_get_parent_id( data->conn, parent_path ); + if( parent_id < 0 ) { + return parent_id; + } + + if( data->verbose ) { + syslog( LOG_INFO, "Parent_id for new dir '%s' is %d", path, parent_id ); + } + + + free( parent_path ); + return 0; } @@ -80,7 +171,7 @@ static struct fuse_operations pgfuse_oper = { .getattr = pgfuse_getattr, .readlink = NULL, .mknod = NULL, - .mkdir = NULL, + .mkdir = pgfuse_mkdir, .unlink = NULL, .rmdir = NULL, .symlink = NULL, @@ -257,9 +348,11 @@ int main( int argc, char *argv[] ) openlog( basename( argv[0] ), LOG_PID, LOG_USER ); + memset( &userdata, 0, sizeof( PgFuseData ) ); userdata.conninfo = pgfuse.conninfo; userdata.conn = conn; userdata.mountpoint = pgfuse.mountpoint; + userdata.verbose = pgfuse.verbose; res = fuse_main( args.argc, args.argv, &pgfuse_oper, &userdata ); diff --git a/test.sql b/test.sql new file mode 100644 index 0000000..380f472 --- /dev/null +++ b/test.sql @@ -0,0 +1,38 @@ +DROP TABLE dir; +DROP TABLE inode; +DROP TABLE data; + +CREATE TABLE data ( + id SERIAL PRIMARY KEY, + data BYTEA +); + +CREATE TABLE inode ( + id SERIAL PRIMARY KEY, + data_id INTEGER REFERENCES data( id ), + mode INTEGER NOT NULL DEFAULT 0, + uid INTEGER NOT NULL DEFAULT 0, + gid INTEGER NOT NULL DEFAULT 0, + ctime TIMESTAMP WITH TIME ZONE, + mtime TIMESTAMP WITH TIME ZONE, + atime TIMESTAMP WITH TIME ZONE, + size INTEGER DEFAULT 0 +); + +CREATE TABLE dir ( + id SERIAL PRIMARY KEY, + parent_id INTEGER REFERENCES dir( id ), + name TEXT, + depth INTEGER, + path TEXT, + UNIQUE( name, parent_id ), + UNIQUE( path ) +); + +-- empty data field for indoes without data +-- e.g. directories +INSERT INTO data(data) values( '' ); + +-- self-referencing anchor for root directory +INSERT INTO dir values( 0, 0, '/', 0, '/' ); + |