Skip to content

Commit

Permalink
Merge pull request #259 from Gottox/improve/ls-better-escape
Browse files Browse the repository at this point in the history
Improve/ls better escape
  • Loading branch information
Gottox authored Jun 8, 2024
2 parents dd5cc41 + 4c5c43c commit a41dec9
Show file tree
Hide file tree
Showing 10 changed files with 184 additions and 89 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/codecov.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,6 @@ jobs:
run: |
ninja -C build coverage-xml
- name: Upload coverage reports to Codecov
uses: codecov/codecov-action@v3
uses: codecov/codecov-action@v4
env:
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
36 changes: 36 additions & 0 deletions test/tools/ls/escape.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
#!/bin/sh -ex

######################################################################
# @author Enno Boland ([email protected])
# @file escape.sh
# @created Monday Nov 20, 2023 18:24:05 CET

#
# @description This script creates a squashfs image, mounts it, and
# repacks it from the mounted path.
######################################################################

: "${BUILD_DIR:?BUILD_DIR is not set}"
: "${MKSQUASHFS:?MKSQUASHFS is not set}"
: "${SOURCE_ROOT:?SOURCE_ROOT is not set}"
: "${SQSH_LS:?SQSH_UNPACK is not set}"

MKSQUASHFS_OPTS="-no-xattrs -noappend -all-root -mkfs-time 0"

WORK_DIR="$BUILD_DIR/escape"

mkdir -p "$WORK_DIR"
cd "$WORK_DIR"

mkdir -p "$PWD/empty"

printf "dir\e d 777 0 0\n" > "$PWD/escape.pseudo";

# shellcheck disable=SC2086
$MKSQUASHFS "$PWD/empty" "$PWD/escape.squashfs" -pf "$PWD/escape.pseudo" \
$MKSQUASHFS_OPTS
result="$($SQSH_LS -r --escape "$PWD/escape.squashfs")"
[ "$result" = "$(printf "%s" "/dir\e")" ]

result="$($SQSH_LS -r --raw "$PWD/escape.squashfs")"
[ "$result" = "$(printf "/dir\e")" ]
1 change: 1 addition & 0 deletions test/tools/meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ sqsh_extended_test = [
'ls/large-tree.sh',
'ls/large-tree-lookup.sh',
'ls/utc.sh',
'ls/escape.sh',
]
sqsh_extended_fs_test = [
'fs/large-file.sh',
Expand Down
2 changes: 1 addition & 1 deletion test/tools/unpack/repack.sh
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ $MKSQUASHFS "$SOURCE_ROOT/libsqsh" "original.squashfs" $MKSQUASHFS_OPTS

mkdir -p "unpack"

$SQSH_UNPACK "$PWD/original.squashfs" / "$PWD/unpack"
$SQSH_UNPACK -Ve "$PWD/original.squashfs" / "$PWD/unpack"

# shellcheck disable=SC2086
$MKSQUASHFS "unpack" "repacked.squashfs" $MKSQUASHFS_OPTS
Expand Down
4 changes: 4 additions & 0 deletions tools/include/sqshtools_common.h
Original file line number Diff line number Diff line change
Expand Up @@ -50,4 +50,8 @@
struct SqshArchive *
open_archive(const char *image_path, uint64_t offset, int *err);

void print_raw(const char *segment, size_t segment_size);

void print_escaped(const char *segment, size_t segment_size);

#endif /* TOOLS_COMMON_H */
8 changes: 8 additions & 0 deletions tools/man/sqsh-ls.1.in
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,14 @@ output of the \fBls -l\fR command.
.BR \-u ", " \fB\-\-utc
When running with \fB-l\fR use UTC timestamps instead of local time.

.TP
.BR \-R ", " \fB\-\-raw
Do not escape filenames, even if the output is a terminal.

.TP
.BR \-e ", " \fB\-\-escape
Escape filenames, even if the output is not a terminal.

.TP
.BR \-v ", " \fB\-\-version
Print the version of \fBsqsh-ls\fR and exit.
Expand Down
8 changes: 8 additions & 0 deletions tools/man/sqsh-unpack.1.in
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,14 @@ group ID of the current user.
.BR \-V ", " \fB\-\-verbose\fR
Print more verbose output during unpacking.

.TP
.BR \-R ", " \fB\-\-raw
When in verbose do not escape filenames, even if the output is a terminal.

.TP
.BR \-R ", " \fB\-\-escape
When in verbose escape filenames, even if the output is not a terminal.

.SH ARGUMENTS
.TP
.BR FILESYSTEM
Expand Down
62 changes: 62 additions & 0 deletions tools/src/common.c
Original file line number Diff line number Diff line change
Expand Up @@ -52,3 +52,65 @@ open_archive(const char *image_path, uint64_t offset, int *err) {

return sqsh_archive_open(image_path, &config, err);
}

void
print_raw(const char *segment, size_t segment_size) {
fwrite(segment, 1, segment_size, stdout);
}

void
print_escaped(const char *segment, size_t segment_size) {
for (size_t i = 0; i < segment_size; i++) {
switch (segment[i]) {
case '\n':
fputs("\\n", stdout);
break;
case '\r':
fputs("\\r", stdout);
break;
case '\t':
fputs("\\t", stdout);
break;
case '\\':
fputs("\\\\", stdout);
break;
case '\x1b':
fputs("\\e", stdout);
break;
case 0x01:
case 0x02:
case 0x03:
case 0x04:
case 0x05:
case 0x06:
case 0x07:
case 0x08:
case 0x0b:
case 0x0c:
case 0x0e:
case 0x0f:
case 0x10:
case 0x11:
case 0x12:
case 0x13:
case 0x14:
case 0x15:
case 0x16:
case 0x17:
case 0x18:
case 0x19:
case 0x1a:
case 0x1c:
case 0x1d:
case 0x1e:
case 0x1f:
case 0x20:
case 0x7f:
printf("\\x%02x", segment[i]);
break;
default:
putchar(segment[i]);
break;
}
}
}
124 changes: 43 additions & 81 deletions tools/src/ls.c
Original file line number Diff line number Diff line change
Expand Up @@ -49,85 +49,30 @@ static bool recursive = false;
static bool utc = false;
static int (*print_item)(const char *, const struct SqshTreeTraversal *) =
print_simple;
static void (*print_segment)(const char *segment, size_t segment_size) =
print_raw;

static int
usage(char *arg0) {
printf("usage: %s [-o OFFSET] [-r] [-l] [-u] FILESYSTEM [PATH]\n", arg0);
printf("usage: %s [-o OFFSET] [-rluRe] FILESYSTEM [PATH]\n", arg0);
printf(" %s -v\n", arg0);
return EXIT_FAILURE;
}

static void
print_mode(
int mode, int r_mask, int w_mask, int x_mask, int s_mask,
char *buffer, int mode, int r_mask, int w_mask, int x_mask, int s_mask,
const char *s_chars) {
const char *x_chars = (mode & s_mask) ? s_chars : "-x";

putchar((mode & r_mask) ? 'r' : '-');
putchar((mode & w_mask) ? 'w' : '-');
putchar((mode & x_mask) ? x_chars[1] : x_chars[0]);
}

static void
print_segment(const char *segment, size_t segment_size) {
for (size_t i = 0; i < segment_size; i++) {
switch (segment[i]) {
case '\n':
fputs("\\n", stdout);
break;
case '\r':
fputs("\\r", stdout);
break;
case '\t':
fputs("\\t", stdout);
break;
case '\\':
fputs("\\\\", stdout);
break;
case '\x1b':
fputs("\\e", stdout);
break;
case 0x01:
case 0x02:
case 0x03:
case 0x04:
case 0x05:
case 0x06:
case 0x07:
case 0x08:
case 0x0b:
case 0x0c:
case 0x0e:
case 0x0f:
case 0x10:
case 0x11:
case 0x12:
case 0x13:
case 0x14:
case 0x15:
case 0x16:
case 0x17:
case 0x18:
case 0x19:
case 0x1a:
case 0x1c:
case 0x1d:
case 0x1e:
case 0x1f:
case 0x20:
case 0x7f:
printf("\\x%02x", segment[i]);
break;
default:
putchar(segment[i]);
break;
}
}
buffer[0] = (mode & r_mask) ? 'r' : '-';
buffer[1] = (mode & w_mask) ? 'w' : '-';
buffer[2] = (mode & x_mask) ? x_chars[1] : x_chars[0];
}

static void
print_path(const char *path, const struct SqshTreeTraversal *traversal) {
fputs(path, stdout);
print_segment(path, strlen(path));
size_t segment_count = sqsh_tree_traversal_depth(traversal);
const char *segment;
size_t segment_size;
Expand Down Expand Up @@ -158,7 +103,7 @@ print_detail(const char *path, const struct SqshTreeTraversal *traversal) {
time_t mtime = sqsh_file_modified_time(file);
struct tm tm_info_buf = {0};
const struct tm *tm_info;
char time_buffer[128] = {0};
char buffer[128] = "";
tm_info = utc ? gmtime_r(&mtime, &tm_info_buf)
: localtime_r(&mtime, &tm_info_buf);
if (tm_info == NULL) {
Expand All @@ -167,47 +112,52 @@ print_detail(const char *path, const struct SqshTreeTraversal *traversal) {

switch (sqsh_file_type(file)) {
case SQSH_FILE_TYPE_UNKNOWN:
putchar('?');
buffer[0] = '?';
break;
case SQSH_FILE_TYPE_DIRECTORY:
putchar('d');
buffer[0] = 'd';
break;
case SQSH_FILE_TYPE_FILE:
putchar('-');
buffer[0] = '-';
break;
case SQSH_FILE_TYPE_SYMLINK:
putchar('l');
buffer[0] = 'l';
break;
case SQSH_FILE_TYPE_BLOCK:
putchar('b');
buffer[0] = 'b';
break;
case SQSH_FILE_TYPE_CHAR:
putchar('c');
buffer[0] = 'c';
break;
case SQSH_FILE_TYPE_FIFO:
putchar('p');
buffer[0] = 'p';
break;
case SQSH_FILE_TYPE_SOCKET:
putchar('s');
buffer[0] = 's';
break;
}

mode = sqsh_file_permission(file);
print_mode(mode, S_IRUSR, S_IWUSR, S_IXUSR, S_ISUID, "Ss");
print_mode(mode, S_IRGRP, S_IWGRP, S_IXGRP, S_ISGID, "Ss");
print_mode(mode, S_IROTH, S_IWOTH, S_IXOTH, S_ISVTX, "Tt");
print_mode(&buffer[1], mode, S_IRUSR, S_IWUSR, S_IXUSR, S_ISUID, "Ss");
print_mode(&buffer[4], mode, S_IRGRP, S_IWGRP, S_IXGRP, S_ISGID, "Ss");
print_mode(&buffer[7], mode, S_IROTH, S_IWOTH, S_IXOTH, S_ISVTX, "Tt");

strftime(time_buffer, sizeof(time_buffer), "%a, %d %b %Y %T %z", tm_info);
sqsh_index_t index = 10;
snprintf(
&buffer[index], sizeof(buffer) - index, " %6u %6u %10" PRIu64,
sqsh_file_uid(file), sqsh_file_gid(file), sqsh_file_size(file));

printf(" %6u %6u %10" PRIu64 " %s ", sqsh_file_uid(file),
sqsh_file_gid(file), sqsh_file_size(file), time_buffer);
index = strlen(buffer);
strftime(
&buffer[index], sizeof(buffer) - index, " %a, %d %b %Y %T %z ",
tm_info);
fputs(buffer, stdout);

print_path(path, traversal);

if (sqsh_file_type(file) == SQSH_FILE_TYPE_SYMLINK) {
fputs(" -> ", stdout);
fwrite(sqsh_file_symlink(file), sqsh_file_symlink_size(file),
sizeof(char), stdout);
print_segment(sqsh_file_symlink(file), sqsh_file_symlink_size(file));
}

putchar('\n');
Expand Down Expand Up @@ -271,14 +221,16 @@ ls_path(struct SqshArchive *archive, char *path) {
return rv;
}

static const char opts[] = "o:vrhlu";
static const char opts[] = "o:vrhluRe";
static const struct option long_opts[] = {
{"offset", required_argument, NULL, 'o'},
{"version", no_argument, NULL, 'v'},
{"recursive", no_argument, NULL, 'r'},
{"help", no_argument, NULL, 'h'},
{"long", no_argument, NULL, 'l'},
{"utc", no_argument, NULL, 'u'},
{"raw", no_argument, NULL, 'R'},
{"escape", no_argument, NULL, 'e'},
{0},
};

Expand All @@ -291,6 +243,10 @@ main(int argc, char *argv[]) {
struct SqshArchive *archive;
uint64_t offset = 0;

if (isatty(fileno(stdout))) {
print_segment = print_escaped;
}

while ((opt = getopt_long(argc, argv, opts, long_opts, NULL)) != -1) {
switch (opt) {
case 'o':
Expand All @@ -308,6 +264,12 @@ main(int argc, char *argv[]) {
case 'u':
utc = true;
break;
case 'R':
print_segment = print_raw;
break;
case 'e':
print_segment = print_escaped;
break;
default:
return usage(argv[0]);
}
Expand Down
Loading

0 comments on commit a41dec9

Please sign in to comment.