From 842b0d24e304c57506ca83c147119dac29485bf9 Mon Sep 17 00:00:00 2001 From: Rob Landley Date: Thu, 2 Sep 2021 22:22:31 -0500 Subject: [PATCH] Cleanup pass on file.c, add more tests. --- tests/file.test | 101 ++++++++++++++------ tests/files/elf/fdstatic | Bin 0 -> 9056 bytes toys/posix/file.c | 202 ++++++++++++++++++--------------------- 3 files changed, 162 insertions(+), 141 deletions(-) create mode 100755 tests/files/elf/fdstatic diff --git a/tests/file.test b/tests/file.test index 5e7cccc9..bd023ace 100755 --- a/tests/file.test +++ b/tests/file.test @@ -4,61 +4,72 @@ #testing "name" "command" "result" "infile" "stdin" -touch empty -echo "#!/bin/bash" > bash.script -echo "#! /bin/bash" > bash.script2 -echo "#! /usr/bin/env python" > test.py -echo "Hello, world!" > ascii -echo "6465780a3033350038ca8f6ce910f94e" | xxd -r -p > android.dex -ln -s $FILES/java.class symlink +test_line() { + ONE="$1"; shift; TWO="\"$FILES\"/$1 | sed 's/^.*: //'"; shift + testcmd "$ONE" "$TWO" "$@" +} + +ln -s "$FILES"/java.class symlink LINK=$(readlink symlink) -ln -s $FILES/java.klass dangler +ln -s "$FILES"/java.klass dangler BROKEN=$(readlink dangler) -echo "cafebabe000000020100000700000003000040000000d9300000000e0100000c8000000200014000000098500000000e" | xxd -r -p > universal +mkdir directory testing "directory" "file ." ".: directory\n" "" "" +rmdir directory +touch empty testing "empty" "file empty" "empty: empty\n" "" "" -testing "bash.script" "file bash.script | grep -o ' script'" " script\n" "" "" -testing "bash.script with spaces" "file bash.script2 | grep -o ' script'" " script\n" "" "" -testing "env python script" "file test.py | egrep -o '(python|script)' | sort" \ - "python\nscript\n" "" "" -testing "ascii" "file ascii" "ascii: ASCII text\n" "" "" +rm -f empty + +testing "script" "file input | grep -o ' script'" " script\n" "#!/bin/bash\n" "" +testing "script with spaces" "file input | grep -o ' script'" " script\n" \ + "#! /bin/bash\n" "" +testing "env script" "file input | egrep -o '(python|script)' | sort" \ + "python\nscript\n" "#! /usr/bin/env python\n" "" +testing "ascii" "file input" "input: ASCII text\n" "Hello, world!\n" "" testing "utf-8" \ - "file $FILES/utf8/japan.txt | egrep -o '(UTF-8|text)' | LANG=c sort" \ + "file \"$FILES\"/utf8/japan.txt | egrep -o '(UTF-8|text)' | LANG=c sort" \ "UTF-8\ntext\n" "" "" + +# TODO each of these has multiple options we could test testing "java class" \ - "file $FILES/java.class | egrep -o '(Java class|version 53.0)'"\ + "file \"$FILES\"/java.class | egrep -o '(Java class|version 53.0)'"\ "Java class\nversion 53.0\n" "" "" -testing "mach-o universal" \ - "file universal" \ - "universal: Mach-O universal binary with 2 architectures: x86-64,arm64\n" "" "" -testing "tar file" "file $FILES/tar/tar.tar | sed 's|$FILES/||'" \ - "tar/tar.tar: POSIX tar archive (GNU)\n" "" "" -testing "gzip data" "file $FILES/tar/tar.tgz | grep -o 'gzip compressed data'" \ + +echo "cafebabe000000020100000700000003000040000000d9300000000e0100000c8000000200014000000098500000000e" | xxd -r -p > universal +testcmd "mach-o universal" "universal" \ + "universal: Mach-O universal binary with 2 architectures: [x86_64] [arm64]\n" "" "" +rm universal + +test_line "tar file" "tar/tar.tar" "POSIX tar archive (GNU)\n" "" "" +testing "gzip data" "file \"$FILES\"/tar/tar.tgz | grep -o 'gzip compressed data'" \ "gzip compressed data\n" "" "" -testing "bzip2 data" "file $FILES/tar/tar.tbz2 | sed 's|$FILES/||'" \ - "tar/tar.tbz2: bzip2 compressed data, block size = 900k\n" "" "" -testing "7z file" "file $FILES/tar/tar.7z | sed 's|$FILES/||'" \ - "tar/tar.7z: 7-zip archive data, version 0.4\n" "" "" +test_line "bzip2 data" "tar/tar.tbz2" \ + "bzip2 compressed data, block size = 900k\n" "" "" +test_line "7z file" "tar/tar.7z" "7-zip archive data, version 0.4\n" "" "" testing "zip file" \ "file $FILES/zip/example.zip | egrep -o '(Zip archive data|at least v1.0 to extract)'" \ "Zip archive data\nat least v1.0 to extract\n" "" "" + echo R0lGODlhIAAgAMZHAAAAABYWFiYmJioqKi4uLjIy | base64 -d > gif testing "gif file" "file gif" "gif: GIF image data, version 89a, 32 x 32\n" "" "" rm -f gif # TODO: check in a genuine minimal .dex + +echo "6465780a3033350038ca8f6ce910f94e" | xxd -r -p > android.dex testing "Android .dex" "file android.dex | egrep -o '(dex file|version 035)'" \ "dex file\nversion 035\n" "" "" +rm -f android.dex # These actually test a lot of the ELF code: 32-/64-bit, arm/arm64, PT_INTERP, # the two kinds of NDK ELF note, BuildID, and stripped/not stripped. -toyonly testing "Android NDK full ELF note" \ - "file $FILES/elf/ndk-elf-note-full | sed 's/^.*: //'" \ +toyonly test_line "Android NDK full ELF note" "elf/ndk-elf-note-full" \ "ELF shared object, 64-bit LSB arm64, dynamic (/system/bin/linker64), for Android 24, built by NDK r19b (5304403), BuildID=0c712b8af424d57041b85326f0000fadad38ee0a, not stripped\n" "" "" -toyonly testing "Android NDK short ELF note" \ - "file $FILES/elf/ndk-elf-note-short | sed 's/^.*: //'" \ +toyonly test_line "Android NDK short ELF note" "elf/ndk-elf-note-short" \ "ELF shared object, 32-bit LSB arm, dynamic (/system/bin/linker), for Android 28, BuildID=da6a5f4ca8da163b9339326e626d8a3c, stripped\n" "" "" +toyonly test_line "ELF static fdpic" "elf/fdstatic" \ + "ELF executable (fdpic), 32-bit MSB sh, static, stripped\n" "" "" testing "broken symlink" "file dangler" "dangler: broken symbolic link to $BROKEN\n" "" "" testing "symlink" "file symlink" "symlink: symbolic link to $LINK\n" "" "" @@ -79,4 +90,32 @@ zero_dev="1/5" testing "/dev/zero" "file /dev/zero" "/dev/zero: character special ($zero_dev)\n" "" "" testing "- \nhello/ 0 0 0 644 6 `\nworld')\n" "" +testcmd 'cpio' 'input' 'input: ASCII cpio archive (SVR4 with no CRC)\n' \ + '07070103344745000081A4000003E800' '' + +#TODO block fifo socket +#can't stat (unopenable) +#file +# readerror +# elf +# png (grayscale, color RGB, indexed color, grayscale with alpha, color RGBA +# X x X x-bit/{non-}interlaced +# gif87 +# jpeg +# xz +# Ogg (buncha types) +# wav audio (buncha types) +# truetype font/collection +# Opentype font +# LLVM IR bitcode +# PEM certificate +# pe32 +# BMP +# Linux perf +# Android sparse image file +# Android boot image +# Android DTB/DTBO +# Android Binary XML +# #! shell script diff --git a/tests/files/elf/fdstatic b/tests/files/elf/fdstatic new file mode 100755 index 0000000000000000000000000000000000000000..f8d01ec3449a68b4d9d725e3f61481a0d0d295d1 GIT binary patch literal 9056 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 Ay8r+H literal 0 HcmV?d00001 diff --git a/toys/posix/file.c b/toys/posix/file.c index 48a1c37a..45e614dd 100644 --- a/toys/posix/file.c +++ b/toys/posix/file.c @@ -25,7 +25,6 @@ config FILE GLOBALS( int max_name_len; - off_t len; ) @@ -33,14 +32,13 @@ GLOBALS( // anyway, so calculate struct offsets manually. (It's a fixed ABI.) static void do_elf_file(int fd) { - int endian = toybuf[5], bits = toybuf[4], i, j, dynamic = 0, stripped = 1, - phentsize, phnum, shsize, shnum; - int64_t (*elf_int)(void *ptr, unsigned size); - char *map = 0; - long phoff, shoff; + unsigned endian = toybuf[5], bits = toybuf[4]-1, i, j, dynamic = 0, + stripped = 1, phentsize, phnum, shsize, shnum, bail = 0; + int64_t (*elf_int)(void *ptr, unsigned size) = (endian==2)?peek_be:peek_le; + char *map = MAP_FAILED; + unsigned long phoff, shoff; printf("ELF "); - elf_int = (endian==2) ? peek_be : peek_le; // executable type i = elf_int(toybuf+16, 2); @@ -48,35 +46,32 @@ static void do_elf_file(int fd) else if (i == 2) printf("executable"); else if (i == 3) printf("shared object"); else if (i == 4) printf("core dump"); - else printf("(bad type %d)", i); - if (elf_int(toybuf+36+12*(bits==2), 4) & 0x8000) printf(" (fdpic)"); + else { + printf("(bad type %d)", i); + bail++; + } + if (elf_int(toybuf+36+12*!!bits, 4) & 0x8000) printf(" (fdpic)"); printf(", "); // "64-bit" - if (bits == 1) printf("32-bit "); - else if (bits == 2) printf("64-bit "); - else { + if (bits&~1) { printf("(bad class %d) ", bits); - bits = 0; - } + bail++; + } else printf("%d-bit ", 32<TT.len || phnum*phentsize>TT.len-phoff) goto bad; + // Read the phdrs for dynamic vs static. (Note: fields reordered on 64 bit) + if (phoff>TT.len || phnum*phentsize>TT.len-phoff) goto bad; for (i = 0; i2) continue; // 2 = PT_DYNAMIC, 3 = PT_INTERP, 4 = PT_NOTE + dynamic |= p_type==2; + p_offset = elf_int(phdr+(4<TT.len || p_offset>TT.len-p_filesz) goto bad; + // TODO: if (int)<0 prints endlessly, could go off end of map? printf(", dynamic (%.*s)", (int)p_filesz, map+p_offset); } } @@ -129,18 +122,17 @@ static void do_elf_file(int fd) // We need to read the shdrs for stripped/unstripped and any notes. // Notes are in program headers *and* section headers, but some files don't - // contain program headers, so we prefer to check here. - // (Note: fields got reordered for 64 bit) + // contain program headers, so check here. (Note: fields reordered on 64 bit) if (shoff<0 || shoff>TT.len || shnum*shsize>TT.len-shoff) goto bad; for (i = 0; imap+TT.len-(8+4*(bits+1))) goto bad; + if (shdr>map+TT.len-(8+(4<TT.len || sh_size>TT.len-sh_offset) goto bad; if (sh_type == 2 /*SHT_SYMTAB*/) { @@ -167,11 +159,9 @@ static void do_elf_file(int fd) // Does the claimed size of this note actually fit in the section? if (notesz > sh_size) goto bad; - if (n_namesz==4 && !memcmp(note+12, "GNU", 4)) { - if (n_type==3 /*NT_GNU_BUILD_ID*/) { - printf(", BuildID="); - for (j = 0; j < n_descsz; ++j) printf("%02x", note[16 + j]); - } + if (n_namesz==4 && !memcmp(note+12, "GNU", 4) && n_type==3) { + printf(", BuildID="); + for (j = 0; j= 4) { printf(", for Android %d", (int)elf_int(note+20, 4)); @@ -191,7 +181,7 @@ static void do_elf_file(int fd) bad: xputc('\n'); - if (map && map != MAP_FAILED) munmap(map, TT.len); + if (map != MAP_FAILED) munmap(map, TT.len); } static void do_regular_file(int fd, char *name) @@ -206,7 +196,7 @@ static void do_regular_file(int fd, char *name) if (!len) xputs("empty"); // 45 bytes: https://www.muppetlabs.com/~breadbox/software/tiny/teensy.html else if (len>=45 && strstart(&s, "\177ELF")) do_elf_file(fd); - else if (len>=8 && strstart(&s, "!\n")) xputs("ar archive"); + else if (strstart(&s, "!\n")) xputs("ar archive"); else if (len>28 && strstart(&s, "\x89PNG\x0d\x0a\x1a\x0a")) { // PNG is big-endian: https://www.w3.org/TR/PNG/#7Integers-and-byte-order int chunk_length = peek_be(s, 4); @@ -221,10 +211,8 @@ static void do_regular_file(int fd, char *name) "grayscale with alpha", 0, "color RGBA"}; if (s[9]=(count*20)) { // https://eclecticlight.co/2020/07/28/universal-binaries-inside-fat-headers/ xprintf("Mach-O universal binary with %u architecture%s:", count, count == 1 ? "" : "s"); - s += 4; - len -= 8; - for (i = 0; i < count && len >= 20; i++) { - char *name = "unknown"; - + for (i = 0, s += 4; i < count; i++, s += 20) { arch = peek_be(s, 4); if (arch == 0x00000007) name = "i386"; - else if (arch == 0x01000007) name = "x86-64"; + else if (arch == 0x01000007) name = "x86_64"; else if (arch == 0x0000000c) name = "arm"; else if (arch == 0x0100000c) name = "arm64"; - xprintf("%c%s", i?',':' ', name); - s += 20; - len -= 20; + else name = "unknown"; + xprintf(" [%s]", name); } xprintf("\n"); } else { @@ -275,7 +258,7 @@ static void do_regular_file(int fd, char *name) // https://people.freebsd.org/~kientzle/libarchive/man/cpio.5.txt // the lengths for cpio are size of header + 9 bytes, since any valid // cpio archive ends with a record for "TARGET!!!" - else if (len>85 && strstart(&s, "07070")) { + else if (len>6 && strstart(&s, "07070")) { char *cpioformat = "unknown type"; if (*s == '7') cpioformat = "pre-SVR4 or odc"; @@ -367,15 +350,14 @@ static void do_regular_file(int fd, char *name) else if (format == 0xfffe) xprintf("extensible"); else xprintf("unknown format %d", format); xputc('\n'); - } else if (len>12 && !memcmp(s, "\x00\x01\x00\x00", 4)) { - xputs("TrueType font"); - } else if (len>12 && !memcmp(s, "ttcf\x00", 5)) { + } else if (len>12 && peek_be(s, 4)==0x10000) xputs("TrueType font"); + else if (len>12 && !memcmp(s, "ttcf\x00", 5)) { xprintf("TrueType font collection, version %d, %d fonts\n", (int)peek_be(s+4, 2), (int)peek_be(s+8, 4)); // https://docs.microsoft.com/en-us/typography/opentype/spec/otff - } else if (len>12 && !memcmp(s, "OTTO", 4)) xputs("OpenType font"); - else if (len>4 && !memcmp(s, "BC\xc0\xde", 4)) xputs("LLVM IR bitcode"); + } else if (len>12 && strstart(&s, "OTTO")) xputs("OpenType font"); + else if (strstart(&s, "BC\xc0\xde")) xputs("LLVM IR bitcode"); else if (strstart(&s,"-----BEGIN CERTIFICATE-----")) xputs("PEM certificate"); // https://msdn.microsoft.com/en-us/library/windows/desktop/ms680547(v=vs.85).aspx @@ -385,38 +367,36 @@ static void do_regular_file(int fd, char *name) (peek_le(s+magic+22, 2)&0x2000)?"(DLL) ":""); if (peek_le(s+magic+20, 2)>70) { char *types[] = {0, "native", "GUI", "console", "OS/2", "driver", "CE", - "EFI", "EFI boot", "EFI runtime", "EFI ROM", "XBOX", 0, "boot"}; + "EFI", "EFI boot", "EFI runtime", "EFI ROM", "XBOX", 0, "boot"}, *nn; unsigned type = peek_le(s+magic+92, 2); - char *name = (type 0x32 && !memcmp(s, "BM", 2) && !memcmp(s+6, "\0\0\0\0", 4)) { - int w = peek_le(s+0x12,4), h = peek_le(s+0x16,4), bpp = peek_le(s+0x1c,2); - - xprintf("BMP image, %d x %d, %d bpp\n", w, h, bpp); + } else if (len>0x32 && !memcmp(s, "BM", 2) && !peek_be(s+6, 4)) { + xprintf("BMP image, %d x %d, %d bpp\n", (int)peek_le(s+18, 4), + (int)peek_le(s+22,4), (int)peek_le(s+28, 2)); // https://github.com/torvalds/linux/blob/master/tools/perf/Documentation/perf.data-file-format.txt - } else if (len>=104 && !memcmp(s, "PERFILE2", 8)) { - xputs("Linux perf data"); + } else if (len>=104 && strstart(&s, "PERFILE2")) xputs("Linux perf data"); // https://android.googlesource.com/platform/system/core/+/master/libsparse/sparse_format.h - } else if (len>28 && peek_le(s, 4) == 0xed26ff3a) { + else if (len>28 && peek_le(s, 4) == 0xed26ff3a) { xprintf("Android sparse image v%d.%d, %d %d-byte blocks (%d chunks)\n", - (int) peek_le(s+4, 2), (int) peek_le(s+6, 2), (int) peek_le(s+16, 4), - (int) peek_le(s+12, 4), (int) peek_le(s+20, 4)); + (int)peek_le(s+4, 2), (int)peek_le(s+6, 2), (int)peek_le(s+16, 4), + (int)peek_le(s+12, 4), (int)peek_le(s+20, 4)); // https://android.googlesource.com/platform/system/tools/mkbootimg/+/refs/heads/master/include/bootimg/bootimg.h } else if (len>1632 && !memcmp(s, "ANDROID!", 8)) { - xprintf("Android boot image v%d\n", (int) peek_le(s+40, 4)); + xprintf("Android boot image v%d\n", (int)peek_le(s+40, 4)); // https://source.android.com/devices/architecture/dto/partitions } else if (len>32 && peek_be(s, 4) == 0xd7b7ab1e) { - xprintf("Android DTB/DTBO v%d, %d entries\n", (int) peek_be(s+28, 4), - (int) peek_be(s+16, 4)); + xprintf("Android DTB/DTBO v%d, %d entries\n", (int)peek_be(s+28, 4), + (int)peek_be(s+16, 4)); // frameworks/base/core/java/com/android/internal/util/BinaryXmlSerializer.java } else if (len>4 && !memcmp(s, "ABX", 3)) { @@ -457,11 +437,8 @@ void file_main(void) { char **arg; - for (arg = toys.optargs; *arg; ++arg) { - int name_len = strlen(*arg); - - if (name_len > TT.max_name_len) TT.max_name_len = name_len; - } + for (arg = toys.optargs; *arg; ++arg) + TT.max_name_len = maxof(strlen(*arg), TT.max_name_len); // Can't use loopfiles here because it doesn't call function when can't open for (arg = toys.optargs; *arg; arg++) { @@ -473,31 +450,36 @@ void file_main(void) xprintf("%s: %*s", name, (int)(TT.max_name_len - strlen(name)), ""); sb.st_size = 0; - if (fd || !(FLAG(L) ? stat : lstat)(name, &sb)) { - if (!fd && !FLAG(s) && (S_ISBLK(sb.st_mode) || S_ISCHR(sb.st_mode))) { - sprintf(what = toybuf, "%s special (%u/%u)", - S_ISBLK(sb.st_mode) ? "block" : "character", - dev_major(sb.st_rdev), dev_minor(sb.st_rdev)); - } else if (fd || S_ISREG(sb.st_mode)) { - TT.len = sb.st_size; - // This test identifies an empty file we don't have permission to read - if (!fd && !sb.st_size) what = "empty"; - else if ((fd = openro(name, O_RDONLY)) != -1) { - do_regular_file(fd, name); - if (fd) close(fd); - continue; - } - } else if (S_ISFIFO(sb.st_mode)) what = "fifo"; - else if (S_ISDIR(sb.st_mode)) what = "directory"; - else if (S_ISSOCK(sb.st_mode)) what = "socket"; - else if (S_ISLNK(sb.st_mode)) { - char *lnk = xreadlink(name); - - sprintf(what = toybuf, "%ssymbolic link to %s", - stat(name, &sb) ? "broken " : "", lnk); - free(lnk); + if (!fd && (FLAG(L) ? stat : lstat)(name, &sb)) { + xprintf("cannot open: %s\n", strerror(errno)); + + continue; + } + + if (!fd && !FLAG(s) && (S_ISBLK(sb.st_mode) || S_ISCHR(sb.st_mode))) { + sprintf(what = toybuf, "%s special (%u/%u)", + S_ISBLK(sb.st_mode) ? "block" : "character", + dev_major(sb.st_rdev), dev_minor(sb.st_rdev)); + } else if (fd || S_ISREG(sb.st_mode)) { + TT.len = sb.st_size; + // This test identifies an empty file we don't have permission to read + if (!fd && !sb.st_size) what = "empty"; + else if ((fd = openro(name, O_RDONLY)) != -1) { + do_regular_file(fd, name); + if (fd) close(fd); + + continue; } - xputs(what); - } else xprintf("cannot open: %s\n", strerror(errno)); + } else if (S_ISFIFO(sb.st_mode)) what = "fifo"; + else if (S_ISDIR(sb.st_mode)) what = "directory"; + else if (S_ISSOCK(sb.st_mode)) what = "socket"; + else if (S_ISLNK(sb.st_mode)) { + char *lnk = xreadlink(name); + + sprintf(what = toybuf, "%ssymbolic link to %s", + stat(name, &sb) ? "broken " : "", lnk); + free(lnk); + } + xputs(what); } } -- 2.39.2