Path: blob/main/contrib/libarchive/cpio/test/test_format_newc.c
39507 views
/*-1* SPDX-License-Identifier: BSD-2-Clause2*3* Copyright (c) 2003-2007 Tim Kientzle4* All rights reserved.5*/6#include "test.h"78/* Number of bytes needed to pad 'n' to multiple of 'block', assuming9* that 'block' is a power of two. This trick can be more easily10* remembered as -n & (block - 1), but many compilers quite reasonably11* warn about "-n" when n is an unsigned value. (~(n) + 1) is the12* same thing, but written in a way that won't offend anyone. */13#define PAD(n, block) ((~(n) + 1) & ((block) - 1))1415static int16is_hex(const char *p, size_t l)17{18while (l > 0) {19if ((*p >= '0' && *p <= '9')20|| (*p >= 'a' && *p <= 'f')21|| (*p >= 'A' && *p <= 'F'))22{23--l;24++p;25} else26return (0);2728}29return (1);30}3132/* Convert up to 8 hex characters to unsigned 32-bit decimal integer */33static uint32_t34from_hex(const char *p, size_t l)35{36uint32_t r = 0;3738while (l > 0) {39r *= 16;40if (*p >= 'a' && *p <= 'f')41r += *p + 10 - 'a';42else if (*p >= 'A' && *p <= 'F')43r += *p + 10 - 'A';44else45r += *p - '0';46--l;47++p;48}49return (r);50}5152#if !defined(_WIN32) || defined(__CYGWIN__)53static int54nlinks(const char *p)55{56struct stat st;57assertEqualInt(0, stat(p, &st));58return st.st_nlink;59}60#endif6162DEFINE_TEST(test_format_newc)63{64FILE *list;65int r;66uint32_t devmajor, devminor, ino, gid, uid;67time_t t, t2, now;68char *p, *e;69size_t s;70uint64_t fs, ns;71char result[1024];7273assertUmask(0);7475#if !defined(_WIN32)76uid = getuid();77#endif7879/*80* Create an assortment of files.81* TODO: Extend this to cover more filetypes.82*/83list = fopen("list", "w");8485/* "file1" */86assertMakeFile("file1", 0644, "1234567890");87fprintf(list, "file1\n");8889/* "hardlink" */90assertMakeHardlink("hardlink", "file1");91fprintf(list, "hardlink\n");9293/* Another hardlink, but this one won't be archived. */94assertMakeHardlink("hardlink2", "file1");9596/* "symlink" */97if (canSymlink()) {98assertMakeSymlink("symlink", "file1", 0);99fprintf(list, "symlink\n");100}101102/* "dir" */103assertMakeDir("dir", 0775);104fprintf(list, "dir\n");105106/* Setup result message. */107memset(result, 0, sizeof(result));108if (is_LargeInode("file1")) {109strncat(result,110"bsdcpio: file1: large inode number truncated: ",111sizeof(result) - strlen(result) -1);112strncat(result, strerror(ERANGE),113sizeof(result) - strlen(result) -1);114strncat(result, "\n",115sizeof(result) - strlen(result) -1);116}117if (canSymlink() && is_LargeInode("symlink")) {118strncat(result,119"bsdcpio: symlink: large inode number truncated: ",120sizeof(result) - strlen(result) -1);121strncat(result, strerror(ERANGE),122sizeof(result) - strlen(result) -1);123strncat(result, "\n",124sizeof(result) - strlen(result) -1);125}126if (is_LargeInode("dir")) {127strncat(result,128"bsdcpio: dir: large inode number truncated: ",129sizeof(result) - strlen(result) -1);130strncat(result, strerror(ERANGE),131sizeof(result) - strlen(result) -1);132strncat(result, "\n",133sizeof(result) - strlen(result) -1);134}135if (is_LargeInode("hardlink")) {136strncat(result,137"bsdcpio: hardlink: large inode number truncated: ",138sizeof(result) - strlen(result) -1);139strncat(result, strerror(ERANGE),140sizeof(result) - strlen(result) -1);141strncat(result, "\n",142sizeof(result) - strlen(result) -1);143}144145/* Record some facts about what we just created: */146now = time(NULL); /* They were all created w/in last two seconds. */147148/* Use the cpio program to create an archive. */149fclose(list);150r = systemf("%s -o --format=newc <list >newc.out 2>newc.err",151testprog);152if (!assertEqualInt(r, 0))153return;154155/* Verify that nothing went to stderr. */156if (canSymlink()) {157strncat(result, "2 blocks\n", sizeof(result) - strlen(result) -1);158} else {159strncat(result, "1 block\n", sizeof(result) - strlen(result) -1);160}161assertTextFileContents(result, "newc.err");162163/* Verify that stdout is a well-formed cpio file in "newc" format. */164p = slurpfile(&s, "newc.out");165assertEqualInt(s, canSymlink() ? 1024 : 512);166e = p;167168/*169* Some of these assertions could be stronger, but it's170* a little tricky because they depend on the local environment.171*/172173/* First entry is "file1" */174assert(is_hex(e, 110)); /* Entire header is octal digits. */175assertEqualMem(e + 0, "070701", 6); /* Magic */176ino = from_hex(e + 6, 8); /* ino */177#if defined(_WIN32) && !defined(__CYGWIN__)178/* Group members bits and others bits do not work. */179assertEqualInt(0x8180, from_hex(e + 14, 8) & 0xffc0); /* Mode */180#else181assertEqualInt(0x81a4, from_hex(e + 14, 8)); /* Mode */182#endif183#if defined(_WIN32)184uid = from_hex(e + 22, 8);185#else186assertEqualInt(from_hex(e + 22, 8), uid); /* uid */187#endif188gid = from_hex(e + 30, 8); /* gid */189assertEqualMem(e + 38, "00000003", 8); /* nlink */190t = from_hex(e + 46, 8); /* mtime */191failure("t=%#08jx now=%#08jx=%jd", (uintmax_t)t, (uintmax_t)now,192(intmax_t)now);193assert(t <= now); /* File wasn't created in future. */194failure("t=%#08jx now - 2=%#08jx=%jd", (uintmax_t)t, (uintmax_t)now - 2,195(intmax_t)now - 2);196assert(t >= now - 2); /* File was created w/in last 2 secs. */197failure("newc format stores body only with last appearance of a link\n"198" first appearance should be empty, so this file size\n"199" field should be zero");200assertEqualInt(0, from_hex(e + 54, 8)); /* File size */201fs = (uint64_t)from_hex(e + 54, 8);202fs += PAD(fs, 4);203devmajor = from_hex(e + 62, 8); /* devmajor */204devminor = from_hex(e + 70, 8); /* devminor */205assert(is_hex(e + 78, 8)); /* rdevmajor */206assert(is_hex(e + 86, 8)); /* rdevminor */207assertEqualMem(e + 94, "00000006", 8); /* Name size */208ns = (uint64_t)from_hex(e + 94, 8);209ns += PAD(ns + 2, 4);210assertEqualInt(0, from_hex(e + 102, 8)); /* check field */211assertEqualMem(e + 110, "file1\0", 6); /* Name contents */212/* Since there's another link, no file contents here. */213/* But add in file size so that an error here doesn't cascade. */214e += 110 + fs + ns;215216if (canSymlink()) {217/* "symlink" pointing to "file1" */218assert(is_hex(e, 110));219assertEqualMem(e + 0, "070701", 6); /* Magic */220assert(is_hex(e + 6, 8)); /* ino */221#if defined(_WIN32) && !defined(__CYGWIN__)222/* Mode: Group members bits and others bits do not work. */223assertEqualInt(0xa180, from_hex(e + 14, 8) & 0xffc0);224#else225assertEqualInt(0xa1ff, from_hex(e + 14, 8)); /* Mode */226#endif227assertEqualInt(from_hex(e + 22, 8), uid); /* uid */228assertEqualInt(gid, from_hex(e + 30, 8)); /* gid */229assertEqualMem(e + 38, "00000001", 8); /* nlink */230t2 = from_hex(e + 46, 8); /* mtime */231failure("First entry created at t=%#08jx this entry created"232" at t2=%#08jx", (uintmax_t)t, (uintmax_t)t2);233assert(t2 == t || t2 == t + 1); /* Almost same as first entry. */234assertEqualMem(e + 54, "00000005", 8); /* File size */235fs = (uint64_t)from_hex(e + 54, 8);236fs += PAD(fs, 4);237assertEqualInt(devmajor, from_hex(e + 62, 8)); /* devmajor */238assertEqualInt(devminor, from_hex(e + 70, 8)); /* devminor */239assert(is_hex(e + 78, 8)); /* rdevmajor */240assert(is_hex(e + 86, 8)); /* rdevminor */241assertEqualMem(e + 94, "00000008", 8); /* Name size */242ns = (uint64_t)from_hex(e + 94, 8);243ns += PAD(ns + 2, 4);244assertEqualInt(0, from_hex(e + 102, 8)); /* check field */245assertEqualMem(e + 110, "symlink\0\0\0", 10); /* Name contents */246assertEqualMem(e + 110 + ns, "file1\0\0\0", 8); /* symlink target */247e += 110 + fs + ns;248}249250/* "dir" */251assert(is_hex(e, 110));252assertEqualMem(e + 0, "070701", 6); /* Magic */253assert(is_hex(e + 6, 8)); /* ino */254#if defined(_WIN32) && !defined(__CYGWIN__)255/* Group members bits and others bits do not work. */256assertEqualInt(0x41c0, from_hex(e + 14, 8) & 0xffc0); /* Mode */257#else258/* Mode: sgid bit sometimes propagates from parent dirs, ignore it. */259assertEqualInt(040775, from_hex(e + 14, 8) & ~02000);260#endif261assertEqualInt(uid, from_hex(e + 22, 8)); /* uid */262assertEqualInt(gid, from_hex(e + 30, 8)); /* gid */263#if !defined(_WIN32) || defined(__CYGWIN__)264assertEqualInt(nlinks("dir"), from_hex(e + 38, 8)); /* nlinks */265#endif266t2 = from_hex(e + 46, 8); /* mtime */267failure("First entry created at t=%#08jx this entry created at"268"t2=%#08jx", (uintmax_t)t, (uintmax_t)t2);269assert(t2 == t || t2 == t + 1); /* Almost same as first entry. */270assertEqualMem(e + 54, "00000000", 8); /* File size */271fs = (uint64_t)from_hex(e + 54, 8);272fs += PAD(fs, 4);273assertEqualInt(devmajor, from_hex(e + 62, 8)); /* devmajor */274assertEqualInt(devminor, from_hex(e + 70, 8)); /* devminor */275assert(is_hex(e + 78, 8)); /* rdevmajor */276assert(is_hex(e + 86, 8)); /* rdevminor */277assertEqualMem(e + 94, "00000004", 8); /* Name size */278ns = (uint64_t)from_hex(e + 94, 8);279ns += PAD(ns + 2, 4);280assertEqualInt(0, from_hex(e + 102, 8)); /* check field */281assertEqualMem(e + 110, "dir\0\0\0", 6); /* Name contents */282e += 110 + fs + ns;283284/* Hardlink identical to "file1" */285/* Since we only wrote two of the three links to this286* file, this link should get deferred by the hardlink logic. */287assert(is_hex(e, 110));288assertEqualMem(e + 0, "070701", 6); /* Magic */289failure("If these aren't the same, then the hardlink detection failed to match them.");290assertEqualInt(ino, from_hex(e + 6, 8)); /* ino */291#if defined(_WIN32) && !defined(__CYGWIN__)292/* Group members bits and others bits do not work. */293assertEqualInt(0x8180, from_hex(e + 14, 8) & 0xffc0); /* Mode */294#else295assertEqualInt(0x81a4, from_hex(e + 14, 8)); /* Mode */296#endif297assertEqualInt(from_hex(e + 22, 8), uid); /* uid */298assertEqualInt(gid, from_hex(e + 30, 8)); /* gid */299assertEqualMem(e + 38, "00000003", 8); /* nlink */300t2 = from_hex(e + 46, 8); /* mtime */301failure("First entry created at t=%#08jx this entry created at"302"t2=%#08jx", (uintmax_t)t, (uintmax_t)t2);303assert(t2 == t || t2 == t + 1); /* Almost same as first entry. */304assertEqualInt(10, from_hex(e + 54, 8)); /* File size */305fs = (uint64_t)from_hex(e + 54, 8);306fs += PAD(fs, 4);307assertEqualInt(devmajor, from_hex(e + 62, 8)); /* devmajor */308assertEqualInt(devminor, from_hex(e + 70, 8)); /* devminor */309assert(is_hex(e + 78, 8)); /* rdevmajor */310assert(is_hex(e + 86, 8)); /* rdevminor */311assertEqualMem(e + 94, "00000009", 8); /* Name size */312ns = (uint64_t)from_hex(e + 94, 8);313ns += PAD(ns + 2, 4);314assertEqualInt(0, from_hex(e + 102, 8)); /* check field */315assertEqualMem(e + 110, "hardlink\0\0", 10); /* Name contents */316assertEqualMem(e + 110 + ns, "1234567890\0\0", 12); /* File contents */317e += 110 + ns + fs;318319/* Last entry is end-of-archive marker. */320assert(is_hex(e, 110));321assertEqualMem(e + 0, "070701", 6); /* Magic */322assertEqualMem(e + 8, "00000000", 8); /* ino */323assertEqualMem(e + 14, "00000000", 8); /* mode */324assertEqualMem(e + 22, "00000000", 8); /* uid */325assertEqualMem(e + 30, "00000000", 8); /* gid */326assertEqualMem(e + 38, "00000001", 8); /* nlink */327assertEqualMem(e + 46, "00000000", 8); /* mtime */328assertEqualMem(e + 54, "00000000", 8); /* size */329assertEqualMem(e + 62, "00000000", 8); /* devmajor */330assertEqualMem(e + 70, "00000000", 8); /* devminor */331assertEqualMem(e + 78, "00000000", 8); /* rdevmajor */332assertEqualMem(e + 86, "00000000", 8); /* rdevminor */333assertEqualInt(11, from_hex(e + 94, 8)); /* name size */334assertEqualMem(e + 102, "00000000", 8); /* check field */335assertEqualMem(e + 110, "TRAILER!!!\0\0", 12); /* Name */336337free(p);338}339340341