Skip to content

Commit

Permalink
Merge pull request #262 from Gottox/improve/parent_link_is_ref
Browse files Browse the repository at this point in the history
file: use the inode reference for the parent directory.
  • Loading branch information
Gottox authored Jun 7, 2024
2 parents 8d3dfe4 + 1581a8e commit dd5cc41
Show file tree
Hide file tree
Showing 8 changed files with 88 additions and 103 deletions.
34 changes: 12 additions & 22 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_INODE_REF_NULL UINT64_MAX

/**
* @brief The file type implementation
*/
Expand Down Expand Up @@ -249,8 +251,7 @@ struct SqshFile {
struct SqshArchive *archive;
const struct SqshInodeImpl *impl;
enum SqshFileType type;
bool has_dir_inode;
uint32_t dir_inode;
uint64_t parent_inode_ref;
};

/**
Expand All @@ -271,35 +272,24 @@ SQSH_NO_EXPORT SQSH_NO_UNUSED int sqsh__file_init(

/**
* @memberof SqshFile
* @brief returns whether the file is an extended structure.
* @brief sets the parent inode reference.
*
* @param[in] context The file context.
* @param[in] dir_inode The inode of the parent directory.
*
* @return int 0 on success, less than 0 on error.
* @param[in] parent_inode_ref The inode reference of the parent directory.
*/
SQSH_NO_EXPORT SQSH_NO_UNUSED int
sqsh__file_set_dir_inode(struct SqshFile *context, uint32_t dir_inode);
SQSH_NO_EXPORT void sqsh__file_set_parent_inode_ref(
struct SqshFile *context, uint64_t parent_inode_ref);

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

/**
* @internal
* @memberof SqshFile
* @brief Retrieves if the inode of the parent directory is set.
* @param[in] context The file context.
* @param[out] err Pointer to an int where the error code will be stored.
*
* @param context The file context.
* @return true if the dir_inode is set, false otherwise.
* @return int 0 on success, less than 0 on error.
*/
SQSH_NO_EXPORT bool sqsh__file_has_dir_inode(const struct SqshFile *context);
uint64_t sqsh__file_parent_inode_ref(struct SqshFile *context, int *err);

/**
* @internal
Expand Down
8 changes: 3 additions & 5 deletions libsqsh/src/archive/inode_map.c
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,6 @@
#include <stdlib.h>
#include <string.h>

#define EMPTY_INODE_REF UINT64_MAX

// Funfact: In older versions of this library, the inode map used `0` as the
// sentinal value for empty inodes. It turned out that this was a bad idea,
// because `0` is a valid inode_ref (even if it is an invalid inode number
Expand Down Expand Up @@ -145,7 +143,7 @@ dyn_map_get(const struct SqshInodeMap *map, uint32_t inode_number, int *err) {
goto out;
}
inode_ref = ~inner_inode_refs[inner_index];
if (inode_ref == EMPTY_INODE_REF) {
if (inode_ref == SQSH_INODE_REF_NULL) {
rv = -SQSH_ERROR_NO_SUCH_ELEMENT;
inode_ref = 0;
goto out;
Expand All @@ -167,7 +165,7 @@ dyn_map_set(
struct SqshInodeMap *map, uint32_t inode_number, uint64_t inode_ref) {
int rv = 0;

if (inode_ref == EMPTY_INODE_REF) {
if (inode_ref == SQSH_INODE_REF_NULL) {
return -SQSH_ERROR_INVALID_ARGUMENT;
} else if (inode_number == 0 || inode_number - 1 >= map->inode_count) {
return -SQSH_ERROR_OUT_OF_BOUNDS;
Expand All @@ -191,7 +189,7 @@ dyn_map_set(
} else {
const uint64_t old_value = ~inner_inode_refs[inner_index];
inner_inode_refs[inner_index] = ~inode_ref;
if (old_value != EMPTY_INODE_REF && old_value != inode_ref) {
if (old_value != SQSH_INODE_REF_NULL && old_value != inode_ref) {
rv = -SQSH_ERROR_INODE_MAP_IS_INCONSISTENT;
goto out;
}
Expand Down
7 changes: 2 additions & 5 deletions libsqsh/src/directory/directory_iterator.c
Original file line number Diff line number Diff line change
Expand Up @@ -406,18 +406,15 @@ sqsh_directory_iterator_open_file(
int rv = 0;
struct SqshFile *file = NULL;
const uint64_t inode_ref = sqsh_directory_iterator_inode_ref(iterator);
const uint32_t dir_inode = sqsh_file_inode(iterator->file);
const uint64_t parent_inode_ref = sqsh_file_inode_ref(iterator->file);
struct SqshArchive *archive = iterator->file->archive;

file = sqsh_open_by_ref(archive, inode_ref, &rv);
if (rv < 0) {
goto out;
}

rv = sqsh__file_set_dir_inode(file, dir_inode);
if (rv < 0) {
goto out;
}
sqsh__file_set_parent_inode_ref(file, parent_inode_ref);

rv = check_file_consistency(iterator, file);

Expand Down
105 changes: 59 additions & 46 deletions libsqsh/src/file/file.c
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,6 @@
* @file file.c
*/

#include <assert.h>
#include <sqsh_file_private.h>

#include <cextras/memory.h>
Expand Down Expand Up @@ -187,13 +186,7 @@ sqsh__file_init(
goto out;
}

if (sqsh_file_type(inode) == SQSH_FILE_TYPE_DIRECTORY) {
uint32_t parent_inode = sqsh_file_directory_parent_inode(inode);
rv = sqsh__file_set_dir_inode(inode, parent_inode);
if (rv < 0) {
goto out;
}
}
inode->parent_inode_ref = SQSH_INODE_REF_NULL;

out:
if (rv < 0) {
Expand All @@ -207,42 +200,48 @@ sqsh_open_by_ref(struct SqshArchive *archive, uint64_t inode_ref, int *err) {
SQSH_NEW_IMPL(sqsh__file_init, struct SqshFile, archive, inode_ref);
}

int
sqsh__file_set_dir_inode(struct SqshFile *file, uint32_t dir_inode) {
if (sqsh_file_inode(file) == dir_inode) {
return -SQSH_ERROR_INODE_PARENT_MISMATCH;
void
sqsh__file_set_parent_inode_ref(
struct SqshFile *file, uint64_t parent_inode_ref) {
file->parent_inode_ref = parent_inode_ref;
}

uint64_t
sqsh__file_parent_inode_ref(struct SqshFile *file, int *err) {
uint64_t parent_inode_ref = SQSH_INODE_REF_NULL;
int rv = 0;
if (file->parent_inode_ref != SQSH_INODE_REF_NULL) {
parent_inode_ref = file->parent_inode_ref;
goto out;
}

if (sqsh_file_type(file) == SQSH_FILE_TYPE_DIRECTORY) {
const uint32_t parent_inode = sqsh_file_directory_parent_inode(file);
if (parent_inode != dir_inode) {
return -SQSH_ERROR_INODE_PARENT_MISMATCH;
}

if (dir_inode == 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;
}
}
if (sqsh_file_type(file) != SQSH_FILE_TYPE_DIRECTORY) {
rv = -SQSH_ERROR_INODE_PARENT_UNSET;
goto out;
}

file->dir_inode = dir_inode;
file->has_dir_inode = true;
return 0;
}
struct SqshInodeMap *inode_map;
rv = sqsh_archive_inode_map(file->archive, &inode_map);
if (rv < 0) {
goto out;
}

bool
sqsh__file_has_dir_inode(const struct SqshFile *context) {
return context->has_dir_inode;
}
const uint32_t dir_inode = sqsh_file_directory_parent_inode(file);
parent_inode_ref = sqsh_inode_map_get2(inode_map, dir_inode, &rv);
if (rv == -SQSH_ERROR_NO_SUCH_ELEMENT) {
rv = -SQSH_ERROR_INODE_PARENT_UNSET;
goto out;
} else if (rv < 0) {
goto out;
}

uint32_t
sqsh__file_dir_inode(const struct SqshFile *context) {
assert(sqsh__file_has_dir_inode(context));
file->parent_inode_ref = parent_inode_ref;
out:
if (err != NULL) {
*err = rv;
}

return context->dir_inode;
return parent_inode_ref;
}

bool
Expand Down Expand Up @@ -358,25 +357,40 @@ sqsh_file_type(const struct SqshFile *context) {
return context->type;
}

static int
apply_parent(struct SqshFile *file, struct SqshPathResolver *resolver) {
int rv = sqsh_path_resolver_up(resolver);
if (rv == -SQSH_ERROR_WALKER_CANNOT_GO_UP) {
sqsh__file_set_parent_inode_ref(file, SQSH_INODE_REF_NULL);
} else if (rv < 0) {
return rv;
} else {
uint64_t new_parent_ref = sqsh_path_resolver_inode_ref(resolver);
sqsh__file_set_parent_inode_ref(file, new_parent_ref);
}
return 0;
}

static int
symlink_resolve(struct SqshFile *context, bool follow_symlinks) {
int rv = 0;
struct SqshPathResolver resolver = {0};

if (sqsh_file_type(context) != SQSH_FILE_TYPE_SYMLINK) {
return -SQSH_ERROR_NOT_A_SYMLINK;
}

if (sqsh__file_has_dir_inode(context) == false) {
return -SQSH_ERROR_INODE_PARENT_UNSET;
const uint64_t old_parent_ref = sqsh__file_parent_inode_ref(context, &rv);
if (rv < 0) {
goto out;
}

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

uint32_t old_dir_inode = sqsh__file_dir_inode(context);
rv = sqsh__path_resolver_to_inode(&resolver, old_dir_inode);
rv = sqsh__path_resolver_to_ref(&resolver, old_parent_ref);
if (rv < 0) {
goto out;
}
Expand All @@ -390,13 +404,13 @@ symlink_resolve(struct SqshFile *context, bool follow_symlinks) {
}

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);
if (rv < 0) {
goto out;
}
rv = sqsh__file_set_dir_inode(context, dir_inode);

rv = apply_parent(context, &resolver);
if (rv < 0) {
goto out;
}
Expand Down Expand Up @@ -509,8 +523,7 @@ open_file(
goto out;
}

const uint32_t dir_inode = sqsh_path_resolver_dir_inode(&resolver);
rv = sqsh__file_set_dir_inode(inode, dir_inode);
rv = apply_parent(inode, &resolver);
if (rv < 0) {
goto out;
}
Expand Down
17 changes: 6 additions & 11 deletions libsqsh/src/tree/path_resolver.c
Original file line number Diff line number Diff line change
Expand Up @@ -313,17 +313,16 @@ sqsh_path_resolver_open_file(
const struct SqshPathResolver *resolver, int *err) {
int rv = 0;
struct SqshFile *file = NULL;
uint32_t dir_inode = sqsh_path_resolver_dir_inode(resolver);
uint64_t inode_ref = resolver->current_inode_ref;
file = sqsh_open_by_ref(resolver->archive, inode_ref, &rv);
if (rv < 0) {
goto out;
}
rv = sqsh__file_set_dir_inode(file, dir_inode);
if (rv < 0) {
goto out;
}

if (!is_beginning(resolver)) {
uint64_t parent_inode_ref = sqsh_file_inode_ref(&resolver->cwd);
sqsh__file_set_parent_inode_ref(file, parent_inode_ref);
}
out:
if (rv < 0) {
sqsh__file_cleanup(file);
Expand Down Expand Up @@ -353,8 +352,8 @@ sqsh__path_resolver_follow_symlink(struct SqshPathResolver *resolver) {
}
resolver->current_symlink_depth++;

uint64_t inode_ref = sqsh_directory_iterator_inode_ref(&resolver->iterator);
uint32_t dir_inode = sqsh_path_resolver_dir_inode(resolver);
const uint64_t inode_ref =
sqsh_directory_iterator_inode_ref(&resolver->iterator);

rv = update_inode_from_cwd(resolver);
if (rv < 0) {
Expand All @@ -366,10 +365,6 @@ sqsh__path_resolver_follow_symlink(struct SqshPathResolver *resolver) {
if (rv < 0) {
goto out;
}
rv = sqsh__file_set_dir_inode(&file, dir_inode);
if (rv < 0) {
goto out;
}

const char *target = sqsh_file_symlink(&file);
size_t target_size = sqsh_file_symlink_size(&file);
Expand Down
15 changes: 5 additions & 10 deletions libsqsh/src/tree/traversal.c
Original file line number Diff line number Diff line change
Expand Up @@ -79,17 +79,15 @@ push_stack(struct SqshTreeTraversal *traversal) {
traversal->stack = element;

struct SqshArchive *archive = traversal->base_file->archive;
const uint32_t dir_inode = sqsh_file_inode(traversal->current_file);
const uint64_t parent_inode_ref =
sqsh_file_inode_ref(traversal->current_file);
const uint64_t inode_ref =
sqsh_directory_iterator_inode_ref(traversal->current_iterator);
rv = sqsh__file_init(&element->file, archive, inode_ref);
if (rv < 0) {
goto out;
}
rv = sqsh__file_set_dir_inode(&element->file, dir_inode);
if (rv < 0) {
goto out;
}
sqsh__file_set_parent_inode_ref(&element->file, parent_inode_ref);
traversal->current_file = &element->file;
traversal->state = SQSH_TREE_TRAVERSAL_STATE_DIRECTORY_BEGIN;
out:
Expand Down Expand Up @@ -348,11 +346,8 @@ sqsh_tree_traversal_open_file(
if (rv < 0) {
goto out;
}
if (sqsh__file_has_dir_inode(traversal->base_file)) {
const uint32_t dir_inode =
sqsh__file_dir_inode(traversal->base_file);
rv = sqsh__file_set_dir_inode(file, dir_inode);
}
sqsh__file_set_parent_inode_ref(
file, traversal->base_file->parent_inode_ref);
} else {
file = sqsh_directory_iterator_open_file(
traversal->current_iterator, &rv);
Expand Down
3 changes: 1 addition & 2 deletions test/libsqsh/file/file.c
Original file line number Diff line number Diff line change
Expand Up @@ -152,8 +152,7 @@ UTEST(file, resolve_unkown_dir_inode) {
struct SqshFile *symlink = sqsh_lopen(&archive, "/src", &rv);
ASSERT_EQ(0, rv);
ASSERT_EQ(SQSH_FILE_TYPE_SYMLINK, sqsh_file_type(symlink));
symlink->dir_inode = 0;
symlink->has_dir_inode = false;
symlink->parent_inode_ref = UINT64_MAX;

rv = sqsh_file_symlink_resolve(symlink);
ASSERT_EQ(-SQSH_ERROR_INODE_PARENT_UNSET, rv);
Expand Down
2 changes: 0 additions & 2 deletions test/libsqsh/tree/traversal.c
Original file line number Diff line number Diff line change
Expand Up @@ -74,8 +74,6 @@ UTEST(traversal, test_recursive_directory) {
struct SqshFile file = {0};
rv = sqsh__file_init(&file, &archive, 0);
ASSERT_EQ(0, rv);
rv = sqsh__file_set_dir_inode(&file, 2);
ASSERT_EQ(0, rv);

struct SqshTreeTraversal traversal = {0};
rv = sqsh__tree_traversal_init(&traversal, &file);
Expand Down

0 comments on commit dd5cc41

Please sign in to comment.