1/*- 2 * Copyright (c) 2003-2007 Tim Kientzle 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR 15 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 16 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 17 * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, 18 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 19 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 20 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 21 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 23 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 */ 25#include "test.h" 26__FBSDID("$FreeBSD$"); 27 28#if defined(_WIN32) && !defined(__CYGWIN__) 29/* Execution bits, Group members bits and others bits do not work. */ 30#define UMASK 0177 31#define E_MASK (~0177) 32#else 33#define UMASK 022 34#define E_MASK (~0) 35#endif 36 37/* 38 * Exercise hardlink recreation. 39 * 40 * File permissions are chosen so that the authoritive entry 41 * has the correct permission and the non-authoritive versions 42 * are just writeable files. 43 */ 44DEFINE_TEST(test_write_disk_hardlink) 45{ 46#if defined(__HAIKU__) 47 skipping("archive_write_disk_hardlink; hardlinks are not supported on bfs"); 48#else 49 static const char data[]="abcdefghijklmnopqrstuvwxyz"; 50 struct archive *ad; 51 struct archive_entry *ae; 52 int r; 53 54 /* Force the umask to something predictable. */ 55 assertUmask(UMASK); 56 57 /* Write entries to disk. */ 58 assert((ad = archive_write_disk_new()) != NULL); 59 60 /* 61 * First, use a tar-like approach; a regular file, then 62 * a separate "hardlink" entry. 63 */ 64 65 /* Regular file. */ 66 assert((ae = archive_entry_new()) != NULL); 67 archive_entry_copy_pathname(ae, "link1a"); 68 archive_entry_set_mode(ae, S_IFREG | 0755); 69 archive_entry_set_size(ae, sizeof(data)); 70 assertEqualIntA(ad, 0, archive_write_header(ad, ae)); 71 assertEqualInt(sizeof(data), 72 archive_write_data(ad, data, sizeof(data))); 73 assertEqualIntA(ad, 0, archive_write_finish_entry(ad)); 74 archive_entry_free(ae); 75 76 /* Link. Size of zero means this doesn't carry data. */ 77 assert((ae = archive_entry_new()) != NULL); 78 archive_entry_copy_pathname(ae, "link1b"); 79 archive_entry_set_mode(ae, S_IFREG | 0642); 80 archive_entry_set_size(ae, 0); 81 archive_entry_copy_hardlink(ae, "link1a"); 82 assertEqualIntA(ad, 0, r = archive_write_header(ad, ae)); 83 if (r >= ARCHIVE_WARN) { 84 assertEqualInt(ARCHIVE_WARN, 85 archive_write_data(ad, data, sizeof(data))); 86 assertEqualIntA(ad, 0, archive_write_finish_entry(ad)); 87 } 88 archive_entry_free(ae); 89 90 /* 91 * Repeat tar approach test, but use unset to mark the 92 * hardlink as having no data. 93 */ 94 95 /* Regular file. */ 96 assert((ae = archive_entry_new()) != NULL); 97 archive_entry_copy_pathname(ae, "link2a"); 98 archive_entry_set_mode(ae, S_IFREG | 0755); 99 archive_entry_set_size(ae, sizeof(data)); 100 assertEqualIntA(ad, 0, archive_write_header(ad, ae)); 101 assertEqualInt(sizeof(data), 102 archive_write_data(ad, data, sizeof(data))); 103 assertEqualIntA(ad, 0, archive_write_finish_entry(ad)); 104 archive_entry_free(ae); 105 106 /* Link. Unset size means this doesn't carry data. */ 107 assert((ae = archive_entry_new()) != NULL); 108 archive_entry_copy_pathname(ae, "link2b"); 109 archive_entry_set_mode(ae, S_IFREG | 0642); 110 archive_entry_unset_size(ae); 111 archive_entry_copy_hardlink(ae, "link2a"); 112 assertEqualIntA(ad, 0, r = archive_write_header(ad, ae)); 113 if (r >= ARCHIVE_WARN) { 114 assertEqualInt(ARCHIVE_WARN, 115 archive_write_data(ad, data, sizeof(data))); 116 assertEqualIntA(ad, 0, archive_write_finish_entry(ad)); 117 } 118 archive_entry_free(ae); 119 120 /* 121 * Second, try an old-cpio-like approach; a regular file, then 122 * another identical one (which has been marked hardlink). 123 */ 124 125 /* Regular file. */ 126 assert((ae = archive_entry_new()) != NULL); 127 archive_entry_copy_pathname(ae, "link3a"); 128 archive_entry_set_mode(ae, S_IFREG | 0600); 129 archive_entry_set_size(ae, sizeof(data)); 130 assertEqualIntA(ad, 0, archive_write_header(ad, ae)); 131 assertEqualInt(sizeof(data), archive_write_data(ad, data, sizeof(data))); 132 assertEqualIntA(ad, 0, archive_write_finish_entry(ad)); 133 archive_entry_free(ae); 134 135 /* Link. */ 136 assert((ae = archive_entry_new()) != NULL); 137 archive_entry_copy_pathname(ae, "link3b"); 138 archive_entry_set_mode(ae, S_IFREG | 0755); 139 archive_entry_set_size(ae, sizeof(data)); 140 archive_entry_copy_hardlink(ae, "link3a"); 141 assertEqualIntA(ad, 0, r = archive_write_header(ad, ae)); 142 if (r > ARCHIVE_WARN) { 143 assertEqualInt(sizeof(data), 144 archive_write_data(ad, data, sizeof(data))); 145 assertEqualIntA(ad, 0, archive_write_finish_entry(ad)); 146 } 147 archive_entry_free(ae); 148 149 /* 150 * Finally, try a new-cpio-like approach, where the initial 151 * regular file is empty and the hardlink has the data. 152 */ 153 154 /* Regular file. */ 155 assert((ae = archive_entry_new()) != NULL); 156 archive_entry_copy_pathname(ae, "link4a"); 157 archive_entry_set_mode(ae, S_IFREG | 0600); 158 archive_entry_set_size(ae, 0); 159 assertEqualIntA(ad, 0, archive_write_header(ad, ae)); 160#if ARCHIVE_VERSION_NUMBER < 3000000 161 assertEqualInt(ARCHIVE_WARN, archive_write_data(ad, data, 1)); 162#else 163 assertEqualInt(-1, archive_write_data(ad, data, 1)); 164#endif 165 assertEqualIntA(ad, 0, archive_write_finish_entry(ad)); 166 archive_entry_free(ae); 167 168 /* Link. */ 169 assert((ae = archive_entry_new()) != NULL); 170 archive_entry_copy_pathname(ae, "link4b"); 171 archive_entry_set_mode(ae, S_IFREG | 0755); 172 archive_entry_set_size(ae, sizeof(data)); 173 archive_entry_copy_hardlink(ae, "link4a"); 174 assertEqualIntA(ad, 0, r = archive_write_header(ad, ae)); 175 if (r > ARCHIVE_FAILED) { 176 assertEqualInt(sizeof(data), 177 archive_write_data(ad, data, sizeof(data))); 178 assertEqualIntA(ad, 0, archive_write_finish_entry(ad)); 179 } 180 archive_entry_free(ae); 181 assertEqualInt(0, archive_write_finish(ad)); 182 183 /* Test the entries on disk. */ 184 185 /* Test #1 */ 186 /* If the hardlink was successfully created and the archive 187 * doesn't carry data for it, we consider it to be 188 * non-authoritive for meta data as well. This is consistent 189 * with GNU tar and BSD pax. */ 190 assertIsReg("link1a", 0755 & ~UMASK); 191 assertFileSize("link1a", sizeof(data)); 192 assertFileNLinks("link1a", 2); 193 assertIsHardlink("link1a", "link1b"); 194 195 /* Test #2: Should produce identical results to test #1 */ 196 /* Note that marking a hardlink with size = 0 is treated the 197 * same as having an unset size. This is partly for backwards 198 * compatibility (we used to not have unset tracking, so 199 * relied on size == 0) and partly to match the model used by 200 * common file formats that store a size of zero for 201 * hardlinks. */ 202 assertIsReg("link2a", 0755 & ~UMASK); 203 assertFileSize("link2a", sizeof(data)); 204 assertFileNLinks("link2a", 2); 205 assertIsHardlink("link2a", "link2b"); 206 207 /* Test #3 */ 208 assertIsReg("link3a", 0755 & ~UMASK); 209 assertFileSize("link3a", sizeof(data)); 210 assertFileNLinks("link3a", 2); 211 assertIsHardlink("link3a", "link3b"); 212 213 /* Test #4 */ 214 assertIsReg("link4a", 0755 & ~UMASK); 215 assertFileNLinks("link4a", 2); 216 assertFileSize("link4a", sizeof(data)); 217 assertIsHardlink("link4a", "link4b"); 218#endif 219} 220