diff options
author | Andreas Baumann <abaumann@yahoo.com> | 2012-04-26 11:31:20 +0200 |
---|---|---|
committer | Andreas Baumann <abaumann@yahoo.com> | 2012-04-26 11:31:20 +0200 |
commit | dc9bd214c6bcfae631a19ff4b56bb25a6a4b41b0 (patch) | |
tree | 85fc3ed548c288875274a9b21f50793ba74a50bb | |
parent | c6a269743bcbb4870aa4695094a667c93df36889 (diff) | |
download | pgfuse-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-- | BUGS | 1 | ||||
-rw-r--r-- | pgfuse.1 | 2 | ||||
-rw-r--r-- | pgfuse.c | 88 | ||||
-rw-r--r-- | pgsql.c | 59 | ||||
-rw-r--r-- | pgsql.h | 3 |
5 files changed, 135 insertions, 18 deletions
@@ -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 @@ -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 @@ -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 ); @@ -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 *)¶m1, rename_to, (const char *)¶m3 }; + 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; } @@ -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 |