Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,20 @@ file3.MTS
on seperate lines. Empty lines or lines, which do not resolve to a file where
a stat call succeeds, are ignored.

Simple "range" expressions are supported in -concat- files. This way, you can slice an input file (and even reorder it!). \
The line format is `path:offset:length`, with both `offset` and `length` being optional. \
Do remember that the same file can be specified multiple times, and it will get concatenated multiple times, as expected. \
The order in which the new file is created is the same as in the -concat- file.

Some examples:
```
file1.bin // use the entire file
file1.bin:10 // use file1.bin again, but starting at offset 10
file2.bin:50:100 // use file2.bin, but only 100 bytes starting at offset 50 (inclusive).
file3.bin::1 // use file3.bin, but only the very first byte
file1.bin // use file1.bin in its entirety again
```

You will need to install libfuse-dev to compile:

```
Expand Down
87 changes: 78 additions & 9 deletions src/concatfs.c
Original file line number Diff line number Diff line change
Expand Up @@ -44,13 +44,25 @@
#include <unistd.h>
#include <sys/types.h>
#include <dirent.h>
#include <stdbool.h>

#ifndef PATH_MAX
#define PATH_MAX 4096
#endif

#define OFF_T_MAX ((((off_t)1 << (sizeof(off_t) * 8 - 2)) - 1) * 2 + 1)

#define MIN(a, b) (((a) < (b)) ? (a) : (b))
#define MAX(a, b) (((a) > (b)) ? (a) : (b))
#define CLAMP(x, m, M) (MIN((M), MAX((x), (m))))

static char src_dir[PATH_MAX];

struct chunk {
struct chunk * next;

int fd;
off_t startOffset;
off_t fsize;
};

Expand Down Expand Up @@ -136,13 +148,67 @@ static struct concat_file * open_files_erase(int fd)
return rv;
}


// tries to parse lines formatted like [path]:[start offset]:[length], with both [start offset] and :[length] being optional
// regex equivalent: ^(?<path>[^:]+)(:(?<startOffset>\d+)?(:(?<length>\d+)?)?)?$
static bool try_parse_line_offsets(char* line, off_t* startOffset, off_t* length)
{
struct stat stbuf;
bool statOk = false;
char* offsetsLineStart;
char t;
off_t s = -1;
off_t l = OFF_T_MAX;

if (line == NULL || line[0] == '\0') return false;

// find the point between path and offsets
offsetsLineStart = strchr(line, ':');

// cut the string into "two" strings (path \0 offsets) if needed, and stat() the path
if (offsetsLineStart != NULL)
{
t = *offsetsLineStart;
*offsetsLineStart = '\0';
}
statOk = (stat(line, &stbuf) == 0);
/*if (offsetsLineStart != NULL)
{
// restore the string
*offsetsLineStart = t;
}*/
if (!statOk) return false;
if (stbuf.st_size < 1) return false; // can't really use files with 0 size

// try to parse the numbers
if (offsetsLineStart != NULL)
{
const char* lengthLineStart;

// read the start offset
sscanf(offsetsLineStart + 1, "%jd", &s);
// find the length number and parse it
lengthLineStart = strchr(offsetsLineStart + 1, ':');
if (lengthLineStart != NULL)
{
sscanf(lengthLineStart + 1, "%jd", &l);
}
}

s = CLAMP(s, 0, stbuf.st_size - 1);
l = CLAMP(l, 1, stbuf.st_size - s);

*startOffset = s;
*length = l;
return true;
}

static struct concat_file * open_concat_file(int fd, const char * path)
{
struct concat_file * rv = 0;
char bpath[PATH_MAX+1];
char fpath[PATH_MAX+1];
char * base_dir;
struct stat stbuf;
struct chunk * c = 0;

FILE * fp;
Expand Down Expand Up @@ -171,6 +237,8 @@ static struct concat_file * open_concat_file(int fd, const char * path)
while (fgets(fpath, sizeof(fpath), fp)) {
char tpath[PATH_MAX];
struct chunk * c_n;
off_t startOffset = 0;
off_t length = 0;

fpath[strlen(fpath) - 1] = 0;

Expand All @@ -179,16 +247,15 @@ static struct concat_file * open_concat_file(int fd, const char * path)
} else {
snprintf(tpath, sizeof(tpath), "%s/%s",base_dir, fpath);
}
if (stat(tpath, &stbuf) == 0) {
rv->fsize += stbuf.st_size;
} else {
continue;
}

if (!try_parse_line_offsets(tpath, &startOffset, &length)) continue;
rv->fsize += length;

if (fd >= 0) {
c_n = (struct chunk *) calloc(sizeof(struct chunk), 1);

c_n->fsize = stbuf.st_size;
c_n->startOffset = startOffset;
c_n->fsize = length;
c_n->fd = open(tpath, O_RDONLY);

if (c) {
Expand Down Expand Up @@ -266,7 +333,8 @@ static int read_concat_file(int fd, void *buf, size_t count, off_t offset)
}

for (; c && count > c->fsize - offset; c = c->next) {
ssize_t rv = pread(c->fd, buf, c->fsize - offset, offset);
ssize_t rv;
rv = pread(c->fd, buf, c->fsize - offset, offset + c->startOffset);

if (rv == c->fsize - offset) {
buf += rv;
Expand All @@ -282,7 +350,8 @@ static int read_concat_file(int fd, void *buf, size_t count, off_t offset)
}

if (c && count > 0) {
ssize_t rv = pread(c->fd, buf, count, offset);
ssize_t rv;
rv = pread(c->fd, buf, count, offset + c->startOffset);

if (rv < 0) {
return -errno;
Expand Down