summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndreas Baumann <abaumann@yahoo.com>2012-04-26 11:31:20 +0200
committerAndreas Baumann <abaumann@yahoo.com>2012-04-26 11:31:20 +0200
commitdc9bd214c6bcfae631a19ff4b56bb25a6a4b41b0 (patch)
tree85fc3ed548c288875274a9b21f50793ba74a50bb
parentc6a269743bcbb4870aa4695094a667c93df36889 (diff)
downloadpgfuse-dc9bd214c6bcfae631a19ff4b56bb25a6a4b41b0.tar.gz
pgfuse-dc9bd214c6bcfae631a19ff4b56bb25a6a4b41b0.tar.bz2
normal file renames and moves between directories work
fixed some memory problems in error cases fixed location of read_only check (always after checking metadata of the manipulated objects in order to have proper error messages)
-rw-r--r--BUGS1
-rw-r--r--pgfuse.12
-rw-r--r--pgfuse.c88
-rw-r--r--pgsql.c59
-rw-r--r--pgsql.h3
5 files changed, 135 insertions, 18 deletions
diff --git a/BUGS b/BUGS
index 540743a..e6dcae4 100644
--- a/BUGS
+++ b/BUGS
@@ -1,5 +1,6 @@
- no hard-links
- no mknod support
+- no access right checks
- no rename supported
- no support for extended attributes and ACLs
- tested on Linux only currently
diff --git a/pgfuse.1 b/pgfuse.1
index 12c715d..a80c90a 100644
--- a/pgfuse.1
+++ b/pgfuse.1
@@ -78,6 +78,8 @@ where to store the files to. Populate the initial schema with:
.TP
- no mknod support
.TP
+- no access right checks
+.TP
- no rename supported
.TP
- no support for extended attributes and ACLs
diff --git a/pgfuse.c b/pgfuse.c
index c7e8108..10fe80b 100644
--- a/pgfuse.c
+++ b/pgfuse.c
@@ -898,17 +898,17 @@ static int pgfuse_ftruncate( const char *path, off_t offset, struct fuse_file_in
PSQL_ROLLBACK( conn ); RELEASE( conn );
return -EBADF;
}
-
- if( data->read_only ) {
- PSQL_ROLLBACK( conn ); RELEASE( conn );
- return -EROFS;
- }
res = psql_read_meta( conn, fi->fh, path, &meta );
if( res < 0 ) {
PSQL_ROLLBACK( conn ); RELEASE( conn );
return res;
}
+
+ if( data->read_only ) {
+ PSQL_ROLLBACK( conn ); RELEASE( conn );
+ return -EROFS;
+ }
res = psql_truncate( conn, fi->fh, path, offset );
if( res < 0 ) {
@@ -974,7 +974,7 @@ static int pgfuse_chmod( const char *path, mode_t mode )
path, (unsigned int)mode, data->mountpoint,
THREAD_ID );
}
-
+
ACQUIRE( conn );
PSQL_BEGIN( conn );
@@ -983,7 +983,12 @@ static int pgfuse_chmod( const char *path, mode_t mode )
PSQL_ROLLBACK( conn ); RELEASE( conn );
return id;
}
-
+
+ if( data->read_only ) {
+ PSQL_ROLLBACK( conn ); RELEASE( conn );
+ return -EROFS;
+ }
+
meta.mode = mode;
res = psql_write_meta( conn, id, path, meta );
@@ -1019,6 +1024,11 @@ static int pgfuse_chown( const char *path, uid_t uid, gid_t gid )
PSQL_ROLLBACK( conn ); RELEASE( conn );
return id;
}
+
+ if( data->read_only ) {
+ PSQL_ROLLBACK( conn ); RELEASE( conn );
+ return -EROFS;
+ }
meta.uid = uid;
meta.gid = gid;
@@ -1054,11 +1064,6 @@ static int pgfuse_symlink( const char *from, const char *to )
ACQUIRE( conn );
PSQL_BEGIN( conn );
- if( data->read_only ) {
- PSQL_ROLLBACK( conn ); RELEASE( conn );
- return -EROFS;
- }
-
copy_to = strdup( to );
if( copy_to == NULL ) {
syslog( LOG_ERR, "Out of memory in Symlink '%s'!", to );
@@ -1086,12 +1091,17 @@ static int pgfuse_symlink( const char *from, const char *to )
free( copy_to );
copy_to = strdup( to );
if( copy_to == NULL ) {
- free( parent_path );
syslog( LOG_ERR, "Out of memory in Symlink '%s'!", to );
PSQL_ROLLBACK( conn ); RELEASE( conn );
return -ENOMEM;
}
-
+
+ if( data->read_only ) {
+ free( copy_to );
+ PSQL_ROLLBACK( conn ); RELEASE( conn );
+ return -EROFS;
+ }
+
symlink = basename( copy_to );
meta.size = strlen( from ); /* size = length of path */
@@ -1125,6 +1135,7 @@ static int pgfuse_symlink( const char *from, const char *to )
}
if( res != strlen( from ) ) {
+ free( copy_to );
PSQL_ROLLBACK( conn ); RELEASE( conn );
return -EIO;
}
@@ -1145,6 +1156,11 @@ static int pgfuse_rename( const char *from, const char *to )
int to_id;
PgMeta from_meta;
PgMeta to_meta;
+ char *copy_to;
+ char *parent_path;
+ int to_parent_id;
+ PgMeta to_parent_meta;
+ char *rename_to;
if( data->verbose ) {
syslog( LOG_INFO, "Renaming '%s' to '%s' on '%s', thread #%u",
@@ -1185,8 +1201,50 @@ static int pgfuse_rename( const char *from, const char *to )
S_ISLNK( from_meta.mode ) ) {
return -EINVAL;
}
+
+ copy_to = strdup( to );
+ if( copy_to == NULL ) {
+ syslog( LOG_ERR, "Out of memory in Rename '%s'!", to );
+ PSQL_ROLLBACK( conn ); RELEASE( conn );
+ return -ENOMEM;
+ }
- res = psql_rename( conn, from, to );
+ parent_path = dirname( copy_to );
+
+ to_parent_id = psql_read_meta_from_path( conn, parent_path, &to_parent_meta );
+ if( to_parent_id < 0 ) {
+ free( copy_to );
+ PSQL_ROLLBACK( conn ); RELEASE( conn );
+ return to_parent_id;
+ }
+
+ if( !S_ISDIR( to_parent_meta.mode ) ) {
+ syslog( LOG_ERR, "Weird situation in Rename, '%s' expected to be a directory!",
+ parent_path );
+ free( copy_to );
+ PSQL_ROLLBACK( conn ); RELEASE( conn );
+ return -EIO;
+ }
+
+ free( copy_to );
+ copy_to = strdup( to );
+ if( copy_to == NULL ) {
+ syslog( LOG_ERR, "Out of memory in Rename '%s'!", to );
+ PSQL_ROLLBACK( conn ); RELEASE( conn );
+ return -ENOMEM;
+ }
+
+ if( data->read_only ) {
+ free( copy_to );
+ PSQL_ROLLBACK( conn ); RELEASE( conn );
+ return -EROFS;
+ }
+
+ rename_to = basename( copy_to );
+
+ res = psql_rename( conn, from_id, from_meta.parent_id, to_parent_id, rename_to, from, to );
+
+ free( copy_to );
PSQL_COMMIT( conn ); RELEASE( conn );
diff --git a/pgsql.c b/pgsql.c
index 7d90721..6d5b673 100644
--- a/pgsql.c
+++ b/pgsql.c
@@ -166,7 +166,7 @@ int psql_read_meta( PGconn *conn, const int id, const char *path, PgMeta *meta )
int binary[1] = { 1 };
param1 = htonl( id );
- res = PQexecParams( conn, "SELECT size, mode, uid, gid, ctime, mtime, atime FROM dir WHERE id = $1::int4",
+ res = PQexecParams( conn, "SELECT size, mode, uid, gid, ctime, mtime, atime, parent_id FROM dir WHERE id = $1::int4",
1, NULL, values, lengths, binary, 1 );
if( PQresultStatus( res ) != PGRES_TUPLES_OK ) {
@@ -213,6 +213,10 @@ int psql_read_meta( PGconn *conn, const int id, const char *path, PgMeta *meta )
idx = PQfnumber( res, "atime" );
data = PQgetvalue( res, 0, idx );
meta->atime = convert_from_timestamp( *( (uint64_t *)data ) );
+
+ idx = PQfnumber( res, "parent_id" );
+ data = PQgetvalue( res, 0, idx );
+ meta->parent_id = ntohl( *( (uint32_t *)data ) );
PQclear( res );
@@ -794,7 +798,58 @@ int psql_rollback( PGconn *conn )
return 0;
}
-int psql_rename( PGconn *conn, const char *from, const char *to )
+int psql_rename( PGconn *conn, const int from_id, const int from_parent_id, const int to_parent_id, const char *rename_to, const char *from, const char *to )
{
+ PgMeta from_parent_meta;
+ PgMeta to_parent_meta;
+ int id;
+ int param1 = htonl( to_parent_id );
+ int param3 = htonl( from_id );
+ const char *values[3] = { (const char *)&param1, rename_to, (const char *)&param3 };
+ int lengths[3] = { sizeof( param1 ), strlen( rename_to ), sizeof( param3 ) };
+ int binary[3] = { 1, 0, 1 };
+ PGresult *res;
+
+ id = psql_read_meta( conn, from_parent_id, from, &from_parent_meta );
+ if( id < 0 ) {
+ return id;
+ }
+
+ if( !S_ISDIR( from_parent_meta.mode ) ) {
+ syslog( LOG_ERR, "Expecting parent with id '%d' of '%s' (id '%d') to be a directory in psql_rename, but mode is '%o'!",
+ from_parent_id, from, from_id, from_parent_meta.mode );
+ return -EIO;
+ }
+
+ id = psql_read_meta( conn, to_parent_id, to, &to_parent_meta );
+ if( id < 0 ) {
+ return id;
+ }
+
+ if( !S_ISDIR( to_parent_meta.mode ) ) {
+ syslog( LOG_ERR, "Expecting parent with id '%d' of '%s' to be a directory in psql_rename, but mode is '%o'!",
+ to_parent_id, to, to_parent_meta.mode );
+ return -EIO;
+ }
+
+ res = PQexecParams( conn, "UPDATE dir SET parent_id=$1::int4, name=$2::varchar WHERE id=$3::int4",
+ 3, NULL, values, lengths, binary, 1 );
+
+ if( PQresultStatus( res ) != PGRES_COMMAND_OK ) {
+ syslog( LOG_ERR, "Error in psql_rename for '%s' to '%s': %s",
+ from, to, PQerrorMessage( conn ) );
+ PQclear( res );
+ return -EIO;
+ }
+
+ if( atoi( PQcmdTuples( res ) ) != 1 ) {
+ syslog( LOG_ERR, "Expecting one new row in psql_rename from '%s' to '%s', not %d!",
+ from, to, atoi( PQcmdTuples( res ) ) );
+ PQclear( res );
+ return -EIO;
+ }
+
+ PQclear( res );
+
return 0;
}
diff --git a/pgsql.h b/pgsql.h
index 17f7c62..0b9c96c 100644
--- a/pgsql.h
+++ b/pgsql.h
@@ -36,6 +36,7 @@ typedef struct PgMeta {
struct timespec ctime; /* last status change time */
struct timespec mtime; /* last modification time */
struct timespec atime; /* last access time */
+ int parent_id; /* id/inode_no of parenting directory */
} PgMeta;
/* --- transaction management and policies --- */
@@ -92,6 +93,6 @@ int psql_write_buf( PGconn *conn, const int id, const char *path, const char *bu
int psql_truncate( PGconn *conn, const int id, const char *path, const off_t offset );
-int psql_rename( PGconn *conn, const char *from, const char *to );
+int psql_rename( PGconn *conn, const int from_id, const int from_parent_id, const int to_parent_id, const char *rename_to, const char *from, const char *to );
#endif