/* SPDX-License-Identifier: GPL-3.0-or-later */ /* * describe.c * * Copyright (C) 2019 David Oberhollenzer */ #include "rdsquashfs.h" static char *get_name(const sqfs_tree_node_t *n) { char *name; int ret; ret = sqfs_tree_node_get_path(n, &name); if (ret != 0) { sqfs_perror(NULL, "Recovering file path of tree node", ret); return NULL; } if (canonicalize_name(name) != 0) { fprintf(stderr, "Error sanitizing file path '%s'\n", name); sqfs_free(name); return NULL; } return name; } static void print_stub(const char *type, const char *name, const sqfs_tree_node_t *n) { const char *start, *ptr; printf("%s ", type); if (strchr(name, ' ') == NULL && strchr(name, '"') == NULL) { fputs(name, stdout); } else { fputc('"', stdout); ptr = strchr(name, '"'); if (ptr != NULL) { start = name; do { fwrite(start, 1, ptr - start, stdout); fputs("\\\"", stdout); start = ptr + 1; ptr = strchr(start, '"'); } while (ptr != NULL); fputs(start, stdout); } else { fputs(name, stdout); } fputc('"', stdout); } printf(" 0%o %u %u", (unsigned int)n->inode->base.mode & (~S_IFMT), n->uid, n->gid); } static int print_simple(const char *type, const sqfs_tree_node_t *n, const char *extra) { char *name = get_name(n); if (name == NULL) return -1; print_stub(type, name, n); sqfs_free(name); if (extra != NULL) printf(" %s", extra); fputc('\n', stdout); return 0; } static int print_file(const sqfs_tree_node_t *n, const char *unpack_root) { char *name, *srcpath; name = get_name(n); if (name == NULL) return -1; #if defined(_WIN32) || defined(__WINDOWS__) srcpath = fix_win32_filename(name); if (srcpath == NULL) { fprintf(stderr, "Error sanitizing windows name '%s'\n", name); sqfs_free(name); return -1; } if (strcmp(name, srcpath) == 0) { free(srcpath); srcpath = NULL; } #else srcpath = NULL; #endif print_stub("file", name, n); if (unpack_root == NULL && srcpath != NULL) { printf(" %s", srcpath); } else if (unpack_root != NULL) { printf(" %s/%s", unpack_root, srcpath == NULL ? name : srcpath); } fputc('\n', stdout); free(srcpath); sqfs_free(name); return 0; } int describe_tree(const sqfs_tree_node_t *root, const char *unpack_root) { const sqfs_tree_node_t *n; if (!is_filename_sane((const char *)root->name)) { fprintf(stderr, "Encountered illegal file name '%s'\n", root->name); return -1; } switch (root->inode->base.mode & S_IFMT) { case S_IFSOCK: return print_simple("sock", root, NULL); case S_IFLNK: return print_simple("slink", root, (const char *)root->inode->extra); case S_IFIFO: return print_simple("pipe", root, NULL); case S_IFREG: return print_file(root, unpack_root); case S_IFCHR: case S_IFBLK: { char buffer[32]; sqfs_u32 devno; if (root->inode->base.type == SQFS_INODE_EXT_BDEV || root->inode->base.type == SQFS_INODE_EXT_CDEV) { devno = root->inode->data.dev_ext.devno; } else { devno = root->inode->data.dev.devno; } sprintf(buffer, "%c %u %u", S_ISCHR(root->inode->base.mode) ? 'c' : 'b', major(devno), minor(devno)); return print_simple("nod", root, buffer); } case S_IFDIR: if (root->name[0] != '\0') { if (print_simple("dir", root, NULL)) return -1; } for (n = root->children; n != NULL; n = n->next) { if (describe_tree(n, unpack_root)) return -1; } break; default: break; } return 0; }