Skip to content

Commit

Permalink
Merge pull request #275 from Gottox/improve/doctest
Browse files Browse the repository at this point in the history
test: add doctest support
  • Loading branch information
Gottox authored Jul 30, 2024
2 parents da70b06 + b11d488 commit 34f7444
Show file tree
Hide file tree
Showing 4 changed files with 110 additions and 46 deletions.
118 changes: 75 additions & 43 deletions doc/guide.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,32 +7,30 @@
The @ref SqshArchive struct represents a squashfs archive. It is
created by calling
@ref SqshArchive::sqsh_archive_open "sqsh_archive_open()" and is destroyed by calling
@ref SqshArchive::sqsh_archive_close "sqsh_archive_close()". If you need better control
over the archive creation you can use the
@ref SqshArchive::sqsh_archive_open "sqsh_archive_open()" function, which accepts
a @ref SqshConfig struct that gives you more control over the archive and better
error reporting.
@ref SqshArchive::sqsh_archive_close "sqsh_archive_close()".

Opening:
```c
struct SqshArchive *archive = sqsh_archive_open("archive.squashfs");
```
Opening and cleaning up an archive is simple:
```c
struct SqshArchive *archive = sqsh_archive_open("archive.squashfs", NULL, NULL);
assert(archive != NULL);

Closing:
```c
sqsh_archive_close(archive);
```
Opening with more control:
```c
```c
int err = 0;
struct SqshConfig config = {
.max_symlink_depth = 10,
// ...
};
struct SqshArchive *archive = sqsh_archive_new("archive.sqsh", &config, &err);
struct SqshArchive *archive = sqsh_archive_open("archive.sqsh", &config, &err);
if (err != 0) {
sqsh_perror(err);
sqsh_perror(err, NULL);
exit(1);
}
sqsh_archive_close(archive);
```

# Reading files in the archive
Expand All @@ -42,15 +40,20 @@ if (err != 0) {
The simplest way to read a file in the archive is to use
@ref sqsh_easy_file_content "sqsh_easy_file_content()". This function
returns a pointer to the contents of the file in the archive. The pointer
is heap allocated and must be freed by the caller. The allocated buffer is
is heap allocated and must be free'd by the caller. The allocated buffer is
null terminated. If the file itself contains null bytes, you can get the
file size by calling @ref sqsh_easy_file_size "sqsh_easy_file_size()".

```c
char *content = sqsh_easy_file_content(archive, "/path/to/file.txt");
size_t size = sqsh_easy_file_size(archive, "/path/to/file.txt");
struct SqshArchive *archive = sqsh_archive_open("archive.squashfs", NULL, NULL);
assert(archive != NULL);

uint8_t *content = sqsh_easy_file_content(archive, "/path/to/file.txt", NULL);
size_t size = sqsh_easy_file_size(archive, "/path/to/file.txt", NULL);
fwrite(content, 1, size, stdout);
free(content);

sqsh_archive_close(archive);
```
## Advanced: File Iterators
Expand All @@ -61,27 +64,22 @@ in chunks, which is more efficient than reading the entire file into memory
at once.
```c
struct SqshArchive *archive = sqsh_archive_open("archive.squashfs", NULL, NULL);
int err = 0;
struct SqshInode *inode = sqsh_open(archive, "/path/to/file.txt", &err);
if (err != 0) {
sqsh_perror(err);
return;
}
struct SqshFileIterator *it = sqsh_file_iterator_new(archive, "/path/to/file.txt", &err);
if (err != 0) {
sqsh_perror(err);
return;
}
while ((err = sqsh_file_iterator_next(it)) > 0) {
struct SqshFile *file = sqsh_open(archive, "/path/to/file.txt", &err);
assert(err == 0);
struct SqshFileIterator *it = sqsh_file_iterator_new(file, &err);
assert(err == 0);
while ((err = sqsh_file_iterator_next(it, SIZE_MAX, &err)) > 0) {
const uint8_t *data = sqsh_file_iterator_data(it);
size_t size = sqsh_file_iterator_size(it);
fwrite(data, 1, size, stdout);
}
if (err != 0) {
sqsh_perror(err);
return;
}
assert(err == 0);
sqsh_file_iterator_free(it);
sqsh_close(file);
sqsh_archive_close(archive);
```

## Advanced: File Reader
Expand All @@ -91,23 +89,57 @@ the @ref SqshFileReader API. This API allows you to read arbitrary ranges from
the file.

```c
struct SqshArchive *archive = sqsh_archive_open("archive.squashfs", NULL, NULL);

int err = 0;
struct SqshFileReader *reader = sqsh_file_reader_new(archive, "/path/to/file.txt", &err);
if (err != 0) {
sqsh_perror(err);
return;
}
struct SqshFile *file = sqsh_open(archive, "/path/to/file.txt", &err);
assert(err == 0);
struct SqshFileReader *reader = sqsh_file_reader_new(file, &err);
assert(err == 0);
err = sqsh_file_reader_advance(reader, 0, 10);
if (err != 0) {
sqsh_perror(err);
return;
}
assert(err == 0);

const uint8_t *data = sqsh_file_reader_data(reader);
size_t size = sqsh_file_reader_size(reader);
fwrite(data, 1, size, stdout);

fwrite(data, 1, size, stdout);
sqsh_file_reader_free(reader);
sqsh_close(file);
sqsh_archive_close(archive);
```
This example reads the first 10 bytes of the file.
# Reading xattrs
`libsqsh` is able to handle handle xattrs of files in the archive.
## Simple
The simple way to get an xattr is to use @ref sqsh_easy_xattr_get "sqsh_easy_xattr_get()".
```c
int err = 0;
struct SqshArchive *archive = sqsh_archive_open("archive.squashfs", NULL, NULL);
assert(err == 0);
char *xattr = sqsh_easy_xattr_get(archive, "/path/to/file.txt", "user.myxattr", &err);
assert(err == 0);
puts(xattr);
free(xattr);
sqsh_archive_close(archive);
```

To get a list of all xattr on a file you can use sqsh_easy_xattr_list "sqsh_easy_xattr_list()".

```c
int err = 0;
struct SqshArchive *archive = sqsh_archive_open("archive.squashfs", NULL, NULL);
assert(err == 0);
char **list = sqsh_easy_xattr_keys(archive, "/path/to/file.txt", &err);
assert(err == 0);
for(int i = 0; list[i] != NULL; i++) {
puts(list[i]);
}
free(list);
sqsh_archive_close(archive);
```
4 changes: 1 addition & 3 deletions libsqsh/src/posix/mmap_mapper.c
Original file line number Diff line number Diff line change
Expand Up @@ -33,14 +33,12 @@

#define _LARGEFILE64_SOURCE

#include <sqsh_common_private.h>
#include <sqsh_error.h>
#include <sqsh_mapper_private.h>
#include <sqsh_mapper.h>

#include <errno.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <unistd.h>

#define TO_PTR(x) ((void *)(uintptr_t)(x))
Expand Down
28 changes: 28 additions & 0 deletions test/doctest/meson.build
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
markdown = files(
'../../README.md',
'../../doc/guide.md',
'../../libsqsh/README.md',
)

foreach m : markdown
name = m.full_path().underscorify()
src = custom_target(
name + '.c',
input: m,
output: name + '.c',
command: [
md2code,
'-i', 'sqsh.h',
'-i', 'assert.h',
'-i', 'stdlib.h',
'@INPUT@',
'@OUTPUT@',
],
)
exe = executable(
name,
sources: [src],
dependencies: [libsqsh_dep],
build_by_default: true,
)
endforeach
6 changes: 6 additions & 0 deletions test/meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,12 @@ subdir('libsqsh')

subdir('fuzzer')

# https://github.com/Gottox/md2code
md2code = find_program('md2code', required: false)
if md2code.found()
subdir('doctest')
endif

if get_option('test') == 'extended'
subdir('tools')
endif

0 comments on commit 34f7444

Please sign in to comment.