diff options
author | Andreas Baumann <mail@andreasbaumann.cc> | 2015-05-07 15:22:28 +0200 |
---|---|---|
committer | Andreas Baumann <mail@andreasbaumann.cc> | 2015-05-07 15:22:28 +0200 |
commit | da579f5153f7fa1108091fc18b0761e7a0581c33 (patch) | |
tree | ebcfceb3bd98cdd0a93f56eb7d6e38f013c11ad5 | |
parent | 8ac849f21ed34c447d7744cdaf76c3e10d8045cc (diff) | |
download | pgfuse-da579f5153f7fa1108091fc18b0761e7a0581c33.tar.gz pgfuse-da579f5153f7fa1108091fc18b0761e7a0581c33.tar.bz2 |
fixed the rename problem (EEXIST if the destination file exists is
wrong, the destination file should get all data and metadata from
the source file)
-rw-r--r-- | pgfuse.c | 17 | ||||
-rw-r--r-- | pgsql.c | 72 | ||||
-rw-r--r-- | pgsql.h | 2 | ||||
-rw-r--r-- | tests/Makefile | 6 |
4 files changed, 94 insertions, 3 deletions
@@ -1346,9 +1346,20 @@ static int pgfuse_rename( const char *from, const char *to ) PSQL_ROLLBACK( conn ); RELEASE( conn ); return 0; } else { - /* otherwise bail out */ - PSQL_ROLLBACK( conn ); RELEASE( conn ); - return -EEXIST; + /* otherwise make source file disappear and + * destination file contain the same data + * as the source one (preferably atomic because + * of rename/lockfile tricks) + */ + res = psql_rename_to_existing_file( conn, from_id, to_id, from, to ); + if( res < 0 ) { + PSQL_ROLLBACK( conn ); RELEASE( conn ); + return res; + } + + PSQL_COMMIT( conn ); RELEASE( conn ); + + return res; } } /* TODO: handle all other cases */ @@ -846,6 +846,78 @@ int psql_rollback( PGconn *conn ) return 0; } +int psql_rename_to_existing_file( PGconn *conn, const int64_t from_id, const int64_t to_id, const char *from_path, const char *to_path ) +{ + int64_t param1 = htobe64( to_id ); + int64_t param2 = htobe64( from_id ); + const char *values[2] = { (char *)¶m1, (char *)¶m2 }; + int lengths[2] = { sizeof( param1 ), sizeof( param2 ) }; + int binary[2] = { 1, 1 }; + PGresult *res; + + /* first delete the data of the destination file */ + res = PQexecParams( conn, "DELETE FROM data WHERE dir_id=$1::bigint", + 1, NULL, values, lengths, binary, 1 ); + + if( PQresultStatus( res ) != PGRES_COMMAND_OK ) { + syslog( LOG_ERR, "Error in psql_rename_to_existing_file to remove data of the destination file '%s': %s", + to_path, PQerrorMessage( conn ) ); + PQclear( res ); + return -EIO; + } + + /* the destination file should inherit the data from the source file, + avoid copying stupidly here */ + res = PQexecParams( conn, "UPDATE data SET dir_id=$1::bigint WHERE dir_id=$2::bigint", + 2, NULL, values, lengths, binary, 1 ); + + if( PQresultStatus( res ) != PGRES_COMMAND_OK ) { + syslog( LOG_ERR, "Error in psql_rename_to_existing_file to move data from '%s' to '%s': %s", + from_path, to_path, PQerrorMessage( conn ) ); + PQclear( res ); + return -EIO; + } + + PQclear( res ); + + /* We inherit automatically all metadata from the source + file for the destination file. But we would like to + have the new filename of the destination file. */ + values[0] = (char *)¶m2; + values[1] = to_path; + lengths[1] = strlen( to_path ); + binary[1] = 0; + + res = PQexecParams( conn, "UPDATE dir SET name=$2::varchar WHERE id=$1::bigint", + 2, NULL, values, lengths, binary, 1 ); + + if( PQresultStatus( res ) != PGRES_COMMAND_OK ) { + syslog( LOG_ERR, "Error in psql_rename_to_existing_file to set new name for '%s' to '%s': %s", + from_path, to_path, PQerrorMessage( conn ) ); + PQclear( res ); + return -EIO; + } + + PQclear( res ); + + /* finally we delete the inode entry for the source file */ + + values[0] = (char *)¶m2; + res = PQexecParams( conn, "DELETE FROM dir where id=$1::bigint", + 1, NULL, values, lengths, binary, 1 ); + + if( PQresultStatus( res ) != PGRES_COMMAND_OK ) { + syslog( LOG_ERR, "Error in psql_renamc_existing_file when deleting dir entry for path '%s': %s", + from_path, PQerrorMessage( conn ) ); + PQclear( res ); + return -EIO; + } + + PQclear( res ); + + return 0; +} + int psql_rename( PGconn *conn, const int64_t from_id, const int64_t from_parent_id, const int64_t to_parent_id, const char *rename_to, const char *from, const char *to ) { PgMeta from_parent_meta; @@ -96,6 +96,8 @@ int psql_truncate( PGconn *conn, const size_t block_size, const int64_t id, cons int psql_rename( PGconn *conn, const int64_t from_id, const int64_t from_parent_id, const int64_t to_parent_id, const char *rename_to, const char *from, const char *to ); +int psql_rename_to_existing_file( PGconn *conn, const int64_t from_id, const int64_t to_id, const char *from_path, const char *to_path ); + size_t psql_get_block_size( PGconn *conn, const size_t block_size ); int64_t psql_get_fs_blocks_used( PGconn *conn ); diff --git a/tests/Makefile b/tests/Makefile index 9170e79..21dedca 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -66,6 +66,12 @@ test: testfsync testpgsql testtypes testbigfile testopen -df -i mnt # test open/creat and flags -./testopen + # move test + -echo "afile" > mnt/afile + -echo "bfile" > mnt/bfile + -mv mnt/afile mnt/bfile + -cat mnt/bfile + -rm mnt/bfile # END: unmount FUSE file system fusermount -u mnt |