Skip to content

Commit

Permalink
Merge pull request #237 from Gottox/improve/path-resolution-cleanup
Browse files Browse the repository at this point in the history
Improve/path resolution cleanup
  • Loading branch information
Gottox committed May 28, 2024
2 parents 6985e1f + 3c87326 commit a657fad
Show file tree
Hide file tree
Showing 12 changed files with 573 additions and 377 deletions.
2 changes: 1 addition & 1 deletion .Mk.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ configure:
- -Dfuse-old=enabled
- -Db_coverage=true
- -Db_sanitize=address,undefined
- -Dtest=extended
#- -Dtest=extended
#- -Dfuzzer=true
#- -Dfuzzer_timeout=10
default:
Expand Down
14 changes: 14 additions & 0 deletions include/sqsh_file.h
Original file line number Diff line number Diff line change
Expand Up @@ -265,6 +265,20 @@ enum SqshFileType {
SQSH_NO_UNUSED struct SqshFile *
sqsh_open(struct SqshArchive *archive, const char *path, int *err);

/**
* @memberof SqshFile
* @brief Initialize the file context from a path. This function is identical to
* `sqsh_open()` but if the path is a symlink, the symlink target not resolved.
*
* @param[in] archive The sqsh archive context.
* @param[in] path The path the file or directory.
* @param[out] err Pointer to an int where the error code will be stored.
*
* @return 0 on success, less than 0 on error.
*/
SQSH_NO_UNUSED struct SqshFile *
sqsh_lopen(struct SqshArchive *archive, const char *path, int *err);

/**
* @memberof SqshFile
* @brief Initializes a file context in heap
Expand Down
12 changes: 12 additions & 0 deletions libsqsh/include/sqsh_file_private.h
Original file line number Diff line number Diff line change
Expand Up @@ -207,6 +207,8 @@ SQSH_NO_EXPORT int sqsh__file_reader_cleanup(struct SqshFileReader *reader);
* file/file.c
*/

#define SQSH_AUTO_DIR_INODE UINT32_MAX

/**
* @brief The file type implementation
*/
Expand Down Expand Up @@ -270,6 +272,16 @@ SQSH_NO_EXPORT SQSH_NO_UNUSED int sqsh__file_init(
struct SqshFile *context, struct SqshArchive *sqsh, uint64_t inode_ref,
uint32_t dir_inode);

/**
* @internal
* @memberof SqshFile
* @brief Retrieves the inode of the parent directory.
*
* @param context The file context.
* @return uint32_t The inode number.
*/
SQSH_NO_EXPORT uint32_t sqsh__file_dir_inode(const struct SqshFile *context);

/**
* @internal
* @memberof SqshFile
Expand Down
87 changes: 27 additions & 60 deletions libsqsh/include/sqsh_tree_private.h
Original file line number Diff line number Diff line change
Expand Up @@ -54,76 +54,43 @@ struct SqshPathResolver {
/**
* @privatesection
*/
uint64_t root_inode_ref;
uint64_t current_inode_ref;
struct SqshArchive *archive;
struct SqshInodeMap *inode_map;
size_t max_symlink_depth;
size_t current_symlink_depth;
struct SqshFile cwd;
struct SqshDirectoryIterator iterator;
size_t max_symlink_depth;
struct SqshArchive *archive;
struct SqshInodeMap *inode_map;
uint64_t current_inode_ref;
uint64_t root_inode_ref;
};

/**
* @internal
* @memberof SqshPathResolver
* @brief Initializes a SqshPathResolver struct using the inode_ref as the start
* directory.
*
* @param[out] walker The file walker to initialize.
* @param[in] archive The archive to used
* @param[in] inode_ref The inode reference to start at
*
* @return 0 on success, less than 0 on error.
*/
SQSH_NO_EXPORT SQSH_NO_UNUSED int sqsh__path_resolver_init_from_inode_ref(
struct SqshPathResolver *walker, struct SqshArchive *archive,
uint64_t inode_ref);

/**
* @internal
* @memberof SqshPathResolver
* @brief Initializes a SqshPathResolver struct.
*
* @param[out] walker The file walker to initialize.
* @param[in] archive The archive to use
*
* @return 0 on success, less than 0 on error.
*/
SQSH_NO_EXPORT SQSH_NO_UNUSED int sqsh__path_resolver_init(
struct SqshPathResolver *walker, struct SqshArchive *archive);
struct SqshPathResolver *resolver, struct SqshArchive *archive);

/**
* @internal
* @memberof SqshPathResolver
* @brief Resolve a non-zero terminated path with the tree walker.
*
* This function will resolve the given path with the tree walker. The base is
* the current directory.
*
* @param[in,out] walker The walker to use
* @param[in] path The path to resolve.
* @param[in] path_len The length of the path.
* @param[in] follow_symlinks Whether to follow symlinks.
*
* @return the inode of the current entry.
*/
SQSH_NO_UNUSED int sqsh__path_resolver_resolve_len(
struct SqshPathResolver *walker, const char *path, size_t path_len,
SQSH_NO_EXPORT SQSH_NO_UNUSED int sqsh__path_resolver_to_ref(
struct SqshPathResolver *resolver, uint64_t inode_ref);

SQSH_NO_EXPORT SQSH_NO_UNUSED int sqsh__path_resolver_to_inode(
struct SqshPathResolver *resolver, uint32_t inode_number);

SQSH_NO_EXPORT enum SqshFileType
sqsh__path_resolver_type(const struct SqshPathResolver *resolver);

SQSH_NO_EXPORT SQSH_NO_UNUSED int
sqsh__path_resolver_follow_symlink(struct SqshPathResolver *resolver);

SQSH_NO_EXPORT SQSH_NO_UNUSED int
sqsh__path_resolver_follow_all_symlinks(struct SqshPathResolver *resolver);

SQSH_NO_EXPORT SQSH_NO_UNUSED int sqsh__path_resolver_resolve_nt(
struct SqshPathResolver *resolver, const char *path, size_t path_len,
bool follow_symlinks);

/**
* @internal
* @memberof SqshPathResolver
* @brief Frees the resources used by the file walker.
*
* @param walker The file walker to clean up.
*
* @return 0 on success, less than 0 on error.
*/
SQSH_NO_EXPORT int sqsh__path_resolver_cleanup(struct SqshPathResolver *walker);
SQSH_NO_EXPORT int
sqsh__path_resolver_cleanup(struct SqshPathResolver *resolver);

/***************************************
* tree/path_resolver.c
* tree/traversal.c
*/

/**
Expand Down
2 changes: 0 additions & 2 deletions libsqsh/src/easy/file.c
Original file line number Diff line number Diff line change
Expand Up @@ -35,9 +35,7 @@

#include <sqsh_easy.h>

#include <errno.h>
#include <pthread.h>
#include <stdatomic.h>
#include <stdlib.h>
#include <string.h>

Expand Down
102 changes: 65 additions & 37 deletions libsqsh/src/file/file.c
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,8 @@
#include <sqsh_tree_private.h>
#include <stdint.h>

#define SQSH_DEFAULT_MAX_SYMLINKS_FOLLOWED 100

static const struct SqshDataInode *
get_inode(const struct SqshFile *inode) {
return (const struct SqshDataInode *)sqsh__metablock_reader_data(
Expand Down Expand Up @@ -160,6 +162,14 @@ check_file_consistency(struct SqshFile *file) {
return -SQSH_ERROR_INODE_PARENT_MISMATCH;
}

if (sqsh__file_dir_inode(file) == 0) {
const struct SqshSuperblock *superblock =
sqsh_archive_superblock(file->archive);
if (file->inode_ref != sqsh_superblock_inode_root_ref(superblock)) {
return -SQSH_ERROR_INODE_PARENT_MISMATCH;
}
}

return 0;
}

Expand Down Expand Up @@ -204,11 +214,15 @@ sqsh__file_init(
goto out;
}

if (dir_inode == 0 && sqsh_file_type(inode) == SQSH_FILE_TYPE_DIRECTORY) {
inode->dir_inode = sqsh_file_directory_parent_inode(inode);
} else {
inode->dir_inode = dir_inode;
if (dir_inode == SQSH_AUTO_DIR_INODE) {
if (sqsh_file_type(inode) == SQSH_FILE_TYPE_DIRECTORY) {
dir_inode = sqsh_file_directory_parent_inode(inode);
} else {
rv = -SQSH_ERROR_NOT_A_DIRECTORY;
goto out;
}
}
inode->dir_inode = dir_inode;

rv = sqsh_archive_inode_map(archive, &inode_map);
if (rv < 0) {
Expand Down Expand Up @@ -245,6 +259,11 @@ sqsh_open_by_ref2(
sqsh__file_init, struct SqshFile, archive, inode_ref, dir_inode);
}

uint32_t
sqsh__file_dir_inode(const struct SqshFile *context) {
return context->dir_inode;
}

bool
sqsh_file_is_extended(const struct SqshFile *context) {
// Only extended inodes have pointers to the xattr table. Instead of relying
Expand Down Expand Up @@ -359,61 +378,53 @@ sqsh_file_type(const struct SqshFile *context) {
}

static int
symlink_resolve_inode_ref(
const struct SqshFile *context, uint64_t *inode_ref,
uint32_t *dir_inode) {
symlink_resolve(struct SqshFile *context, bool follow_symlinks) {
int rv = 0;
struct SqshPathResolver resolver = {0};
uint32_t old_dir_inode = context->dir_inode;
if (sqsh_file_type(context) != SQSH_FILE_TYPE_SYMLINK) {
rv = -SQSH_ERROR_NOT_A_SYMLINK;
goto out;
return -SQSH_ERROR_NOT_A_SYMLINK;
}

struct SqshInodeMap *inode_map = NULL;
rv = sqsh_archive_inode_map(context->archive, &inode_map);
struct SqshPathResolver resolver = {0};
rv = sqsh__path_resolver_init(&resolver, context->archive);
if (rv < 0) {
goto out;
}

uint64_t dir_inode_ref = sqsh_inode_map_get2(inode_map, old_dir_inode, &rv);

rv = sqsh__path_resolver_init_from_inode_ref(
&resolver, context->archive, dir_inode_ref);
uint32_t old_dir_inode = sqsh__file_dir_inode(context);
rv = sqsh__path_resolver_to_inode(&resolver, old_dir_inode);
if (rv < 0) {
goto out;
}

const char *target = sqsh_file_symlink(context);
size_t target_len = sqsh_file_symlink_size(context);
rv = sqsh__path_resolver_resolve_len(&resolver, target, target_len, true);
const size_t target_size = sqsh_file_symlink_size(context);
rv = sqsh__path_resolver_resolve_nt(
&resolver, target, target_size, follow_symlinks);
if (rv < 0) {
goto out;
}

const uint64_t inode_ref = sqsh_path_resolver_inode_ref(&resolver);
const uint32_t dir_inode = sqsh_path_resolver_dir_inode(&resolver);
sqsh__file_cleanup(context);
rv = sqsh__file_init(context, context->archive, inode_ref, dir_inode);
if (rv < 0) {
goto out;
}

*inode_ref = sqsh_path_resolver_inode_ref(&resolver);
*dir_inode = sqsh_path_resolver_dir_inode(&resolver);
out:
sqsh__path_resolver_cleanup(&resolver);
return rv;
}

int
sqsh_file_symlink_resolve(struct SqshFile *context) {
int rv = 0;
struct SqshArchive *archive = context->archive;
uint32_t dir_inode = 0;
uint64_t inode_ref = 0;
rv = symlink_resolve_inode_ref(context, &inode_ref, &dir_inode);
if (rv < 0) {
goto out;
}

sqsh__file_cleanup(context);
rv = sqsh__file_init(context, archive, inode_ref, dir_inode);
return symlink_resolve(context, false);
}

out:
return rv;
int
sqsh_file_symlink_resolve_all(struct SqshFile *context) {
return symlink_resolve(context, true);
}

const char *
Expand Down Expand Up @@ -482,8 +493,10 @@ sqsh__file_cleanup(struct SqshFile *inode) {
return sqsh__metablock_reader_cleanup(&inode->metablock);
}

struct SqshFile *
sqsh_open(struct SqshArchive *archive, const char *path, int *err) {
static struct SqshFile *
open_file(
struct SqshArchive *archive, const char *path, int *err,
bool follow_symlink) {
int rv;
struct SqshPathResolver resolver = {0};
struct SqshFile *inode = NULL;
Expand All @@ -492,7 +505,12 @@ sqsh_open(struct SqshArchive *archive, const char *path, int *err) {
goto out;
}

rv = sqsh_path_resolver_resolve(&resolver, path, true);
rv = sqsh_path_resolver_to_root(&resolver);
if (rv < 0) {
goto out;
}

rv = sqsh_path_resolver_resolve(&resolver, path, follow_symlink);
if (rv < 0) {
goto out;
}
Expand All @@ -510,6 +528,16 @@ sqsh_open(struct SqshArchive *archive, const char *path, int *err) {
return inode;
}

struct SqshFile *
sqsh_open(struct SqshArchive *archive, const char *path, int *err) {
return open_file(archive, path, err, true);
}

struct SqshFile *
sqsh_lopen(struct SqshArchive *archive, const char *path, int *err) {
return open_file(archive, path, err, false);
}

int
sqsh_close(struct SqshFile *file) {
SQSH_FREE_IMPL(sqsh__file_cleanup, file);
Expand Down
Loading

0 comments on commit a657fad

Please sign in to comment.