summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndreas Baumann <abaumann@yahoo.com>2012-04-07 14:19:22 +0200
committerAndreas Baumann <abaumann@yahoo.com>2012-04-07 14:19:22 +0200
commit14d26ae2ecbd06603b2ea4db2e0038bdf0a0c615 (patch)
tree85ee8b469bd86a760ad39b06136abe16dac76e3e
parentaf332b619b773ed265a27078fe8fb49962b21b2d (diff)
downloadpgfuse-14d26ae2ecbd06603b2ea4db2e0038bdf0a0c615.tar.gz
pgfuse-14d26ae2ecbd06603b2ea4db2e0038bdf0a0c615.tar.bz2
a working write
-rw-r--r--Makefile5
-rw-r--r--pgfuse.c66
-rw-r--r--test.sql33
3 files changed, 64 insertions, 40 deletions
diff --git a/Makefile b/Makefile
index c5c914a..1fa9e85 100644
--- a/Makefile
+++ b/Makefile
@@ -17,13 +17,14 @@ clean:
test: pgfuse
psql < test.sql
- -./pgfuse -v "" mnt
+ -./pgfuse -s -v "" mnt
mount | grep pgfuse
-mkdir mnt/dir
-mkdir mnt/dir/dir2
-echo "hello" > mnt/dir/dir2/afile
+ -cp Makefile mnt/dir/dir2/bfile
-ls -al mnt
- -ls -al mnt/dir/dir2/afile
+ -ls -al mnt/dir/dir2
fusermount -u mnt
pgfuse: pgfuse.o
diff --git a/pgfuse.c b/pgfuse.c
index 261b5f4..5d72ae8 100644
--- a/pgfuse.c
+++ b/pgfuse.c
@@ -52,6 +52,7 @@ typedef struct PgFuseFile {
char *buf; /* buffer containing data */
size_t size; /* current size of the buffer (malloc/realloc) */
size_t used; /* used size in the buffer */
+ int ref_count; /* reference counter (for double opens, dup, etc.) */
} PgFuseFile;
static PgFuseFile pgfuse_files[MAX_NOF_OPEN_FILES];
@@ -220,7 +221,8 @@ static int psql_create_file( PGconn *conn, const int parent_id, const char *path
3, NULL, values, lengths, binary, 1 );
if( PQresultStatus( res ) != PGRES_COMMAND_OK ) {
- syslog( LOG_ERR, "Error in psql_create_file for path '%s'", path );
+ syslog( LOG_ERR, "Error in psql_create_file for path '%s': %s",
+ path, PQerrorMessage( conn ) );
PQclear( res );
return -EIO;
}
@@ -240,6 +242,7 @@ static int pgfuse_create( const char *path, mode_t mode, struct fuse_file_info *
char *new_file;
int parent_id;
int res;
+ PgFuseFile *f;
if( data->verbose ) {
char *s = flags_to_string( fi->flags );
@@ -319,15 +322,17 @@ static int pgfuse_create( const char *path, mode_t mode, struct fuse_file_info *
return -EMFILE;
}
- pgfuse_files[id % MAX_NOF_OPEN_FILES].id = id;
- pgfuse_files[id % MAX_NOF_OPEN_FILES].size = STANDARD_BLOCK_SIZE;
- pgfuse_files[id % MAX_NOF_OPEN_FILES].used = 0;
- pgfuse_files[id % MAX_NOF_OPEN_FILES].buf = (char *)malloc( STANDARD_BLOCK_SIZE );
- if( pgfuse_files[id % MAX_NOF_OPEN_FILES].buf == NULL ) {
- pgfuse_files[id % MAX_NOF_OPEN_FILES].id = 0;
+ f = &pgfuse_files[id % MAX_NOF_OPEN_FILES];
+ f->id = id;
+ f->size = STANDARD_BLOCK_SIZE;
+ f->used = 0;
+ f->buf = (char *)malloc( f->size );
+ if( f->buf == NULL ) {
+ f->id = 0;
fi->fh = 0;
return -ENOMEM;
}
+ f->ref_count = 1;
free( copy_path );
@@ -362,7 +367,8 @@ static int psql_get_parent_id( PGconn *conn, const char *path )
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 );
+ syslog( LOG_ERR, "Error in psql_get_parent_id for path '%s': %s",
+ path, PQerrorMessage( conn ) );
PQclear( res );
return -EIO;
}
@@ -403,7 +409,8 @@ static int psql_readdir( PGconn *conn, const int parent_id, void *buf, fuse_fill
1, NULL, values, lengths, binary, 1 );
if( PQresultStatus( res ) != PGRES_TUPLES_OK ) {
- syslog( LOG_ERR, "Error in psql_readdir for dir with id '%d'", parent_id );
+ syslog( LOG_ERR, "Error in psql_readdir for dir with id '%d': %s",
+ parent_id, PQerrorMessage( conn ) );
PQclear( res );
return -EIO;
}
@@ -451,7 +458,7 @@ static int pgfuse_releasedir( const char *path, struct fuse_file_info *fi )
return 0;
}
-static int pgfuse_fsyncdir( const char *path, struct fuse_file_info *fi )
+static int pgfuse_fsyncdir( const char *path, int datasync, struct fuse_file_info *fi )
{
/* nothing to do, everything is done in pgfuse_readdir currently */
return 0;
@@ -469,7 +476,7 @@ static int psql_create_dir( PGconn *conn, const int parent_id, const char *path,
3, NULL, values, lengths, binary, 1 );
if( PQresultStatus( res ) != PGRES_COMMAND_OK ) {
- syslog( LOG_ERR, "Error in psql_create_dir for path '%s'", path );
+ syslog( LOG_ERR, "Error in psql_create_dir for path '%s': %s", path, PQerrorMessage( conn ) );
PQclear( res );
return -EIO;
}
@@ -537,11 +544,35 @@ static int pgfuse_flush( const char *path, struct fuse_file_info *fi )
return 0;
}
+static int psql_write_buf( PGconn *conn, const int id, const char *path, char *buf, size_t len )
+{
+ int param1 = htonl( id );
+ int param2 = htonl( (unsigned int)len );
+ const char *values[3] = { (char *)&param1, (char *)&param2, buf };
+ int lengths[3] = { sizeof( param1 ), sizeof( param2 ), len };
+ int binary[3] = { 1, 1, 1 };
+ PGresult *res;
+
+ res = PQexecParams( conn, "UPDATE dir SET data=$3::bytea,size=$2::int4 WHERE id=$1::int4",
+ 3, NULL, values, lengths, binary, 1 );
+
+ if( PQresultStatus( res ) != PGRES_COMMAND_OK ) {
+ syslog( LOG_ERR, "Error in psql_write_buf for file '%s': %s", path, PQerrorMessage( conn ) );
+ PQclear( res );
+ return -EIO;
+ }
+
+ PQclear( res );
+
+ return len;
+}
+
static int pgfuse_release( const char *path, struct fuse_file_info *fi )
{
PgFuseData *data = (PgFuseData *)fuse_get_context( )->private_data;
PgFuseFile *f;
-
+ int res;
+
if( data->verbose ) {
syslog( LOG_INFO, "Releasing '%s' on '%s'",
path, data->mountpoint );
@@ -553,12 +584,19 @@ static int pgfuse_release( const char *path, struct fuse_file_info *fi )
f = &pgfuse_files[fi->fh % MAX_NOF_OPEN_FILES];
+ f->ref_count--;
+ if( f->ref_count > 0 ) {
+ return 0;
+ }
+
+ res = psql_write_buf( data->conn, f->id, path, f->buf, f->used );
+
f->id = 0;
f->size = 0;
free( f->buf );
f->used = 0;
- return 0;
+ return res;
}
static int pgfuse_write( const char *path, const char *buf, size_t size,
@@ -579,7 +617,7 @@ static int pgfuse_write( const char *path, const char *buf, size_t size,
f = &pgfuse_files[fi->fh % MAX_NOF_OPEN_FILES];
if( offset + size > f->size ) {
- f->size *= 1.2;
+ f->size = ( ( ( offset + size ) / STANDARD_BLOCK_SIZE ) + 1 ) * STANDARD_BLOCK_SIZE;
if( f->size > MAX_FILE_SIZE ) {
f->id = 0;
free( f->buf );
diff --git a/test.sql b/test.sql
index 298e1cf..effb881 100644
--- a/test.sql
+++ b/test.sql
@@ -1,23 +1,4 @@
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,
@@ -26,13 +7,17 @@ CREATE TABLE dir (
path TEXT,
isdir BOOL,
UNIQUE( name, parent_id ),
- UNIQUE( path )
+ UNIQUE( path ),
+ 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,
+ data BYTEA
);
--- 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, '/', '/', true );