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 /* 29 * Write a file using archive_write_data call, read the file 30 * back and verify the contents. The data written includes large 31 * blocks of nulls, so it should exercise the sparsification logic 32 * if ARCHIVE_EXTRACT_SPARSE is enabled. 33 */ 34 static void 35 verify_write_data(struct archive *a, int sparse) 36 { 37 static const char data[]="abcdefghijklmnopqrstuvwxyz"; 38 struct stat st; 39 struct archive_entry *ae; 40 size_t buff_size = 64 * 1024; 41 char *buff, *p; 42 const char *msg = sparse ? "sparse" : "non-sparse"; 43 FILE *f; 44 45 buff = malloc(buff_size); 46 assert(buff != NULL); 47 if (buff == NULL) 48 return; 49 50 ae = archive_entry_new(); 51 assert(ae != NULL); 52 archive_entry_set_size(ae, 8 * buff_size); 53 archive_entry_set_pathname(ae, "test_write_data"); 54 archive_entry_set_mode(ae, AE_IFREG | 0755); 55 assertEqualIntA(a, 0, archive_write_header(a, ae)); 56 57 /* Use archive_write_data() to write three relatively sparse blocks. */ 58 59 /* First has non-null data at beginning. */ 60 memset(buff, 0, buff_size); 61 memcpy(buff, data, sizeof(data)); 62 failure("%s", msg); 63 assertEqualInt(buff_size, archive_write_data(a, buff, buff_size)); 64 65 /* Second has non-null data in the middle. */ 66 memset(buff, 0, buff_size); 67 memcpy(buff + buff_size / 2 - 3, data, sizeof(data)); 68 failure("%s", msg); 69 assertEqualInt(buff_size, archive_write_data(a, buff, buff_size)); 70 71 /* Third has non-null data at the end. */ 72 memset(buff, 0, buff_size); 73 memcpy(buff + buff_size - sizeof(data), data, sizeof(data)); 74 failure("%s", msg); 75 assertEqualInt(buff_size, archive_write_data(a, buff, buff_size)); 76 77 failure("%s", msg); 78 assertEqualIntA(a, 0, archive_write_finish_entry(a)); 79 80 /* Test the entry on disk. */ 81 assert(0 == stat(archive_entry_pathname(ae), &st)); 82 assertEqualInt(st.st_size, 8 * buff_size); 83 f = fopen(archive_entry_pathname(ae), "rb"); 84 assert(f != NULL); 85 if (f == NULL) { 86 free(buff); 87 return; 88 } 89 90 /* Check first block. */ 91 assertEqualInt(buff_size, fread(buff, 1, buff_size, f)); 92 failure("%s", msg); 93 assertEqualMem(buff, data, sizeof(data)); 94 for (p = buff + sizeof(data); p < buff + buff_size; ++p) { 95 failure("offset: %d, %s", (int)(p - buff), msg); 96 if (!assertEqualInt(0, *p)) 97 break; 98 } 99 100 /* Check second block. */ 101 assertEqualInt(buff_size, fread(buff, 1, buff_size, f)); 102 for (p = buff; p < buff + buff_size; ++p) { 103 failure("offset: %d, %s", (int)(p - buff), msg); 104 if (p == buff + buff_size / 2 - 3) { 105 assertEqualMem(p, data, sizeof(data)); 106 p += sizeof(data); 107 } else if (!assertEqualInt(0, *p)) 108 break; 109 } 110 111 /* Check third block. */ 112 assertEqualInt(buff_size, fread(buff, 1, buff_size, f)); 113 for (p = buff; p < buff + buff_size - sizeof(data); ++p) { 114 failure("offset: %d, %s", (int)(p - buff), msg); 115 if (!assertEqualInt(0, *p)) 116 break; 117 } 118 failure("%s", msg); 119 assertEqualMem(buff + buff_size - sizeof(data), data, sizeof(data)); 120 121 /* XXX more XXX */ 122 123 assertEqualInt(0, fclose(f)); 124 archive_entry_free(ae); 125 free(buff); 126 } 127 128 /* 129 * As above, but using the archive_write_data_block() call. 130 */ 131 static void 132 verify_write_data_block(struct archive *a, int sparse) 133 { 134 static const char data[]="abcdefghijklmnopqrstuvwxyz"; 135 struct stat st; 136 struct archive_entry *ae; 137 size_t buff_size = 64 * 1024; 138 char *buff, *p; 139 const char *msg = sparse ? "sparse" : "non-sparse"; 140 FILE *f; 141 142 buff = malloc(buff_size); 143 assert(buff != NULL); 144 if (buff == NULL) 145 return; 146 147 ae = archive_entry_new(); 148 assert(ae != NULL); 149 archive_entry_set_size(ae, 8 * buff_size); 150 archive_entry_set_pathname(ae, "test_write_data_block"); 151 archive_entry_set_mode(ae, AE_IFREG | 0755); 152 assertEqualIntA(a, 0, archive_write_header(a, ae)); 153 154 /* Use archive_write_data_block() to write three 155 relatively sparse blocks. */ 156 157 /* First has non-null data at beginning. */ 158 memset(buff, 0, buff_size); 159 memcpy(buff, data, sizeof(data)); 160 failure("%s", msg); 161 assertEqualInt(ARCHIVE_OK, 162 archive_write_data_block(a, buff, buff_size, 100)); 163 164 /* Second has non-null data in the middle. */ 165 memset(buff, 0, buff_size); 166 memcpy(buff + buff_size / 2 - 3, data, sizeof(data)); 167 failure("%s", msg); 168 assertEqualInt(ARCHIVE_OK, 169 archive_write_data_block(a, buff, buff_size, buff_size + 200)); 170 171 /* Third has non-null data at the end. */ 172 memset(buff, 0, buff_size); 173 memcpy(buff + buff_size - sizeof(data), data, sizeof(data)); 174 failure("%s", msg); 175 assertEqualInt(ARCHIVE_OK, 176 archive_write_data_block(a, buff, buff_size, buff_size * 2 + 300)); 177 178 failure("%s", msg); 179 assertEqualIntA(a, 0, archive_write_finish_entry(a)); 180 181 /* Test the entry on disk. */ 182 assert(0 == stat(archive_entry_pathname(ae), &st)); 183 assertEqualInt(st.st_size, 8 * buff_size); 184 f = fopen(archive_entry_pathname(ae), "rb"); 185 assert(f != NULL); 186 if (f == NULL) { 187 free(buff); 188 return; 189 } 190 191 /* Check 100-byte gap at beginning */ 192 assertEqualInt(100, fread(buff, 1, 100, f)); 193 failure("%s", msg); 194 for (p = buff; p < buff + 100; ++p) { 195 failure("offset: %d, %s", (int)(p - buff), msg); 196 if (!assertEqualInt(0, *p)) 197 break; 198 } 199 200 /* Check first block. */ 201 assertEqualInt(buff_size, fread(buff, 1, buff_size, f)); 202 failure("%s", msg); 203 assertEqualMem(buff, data, sizeof(data)); 204 for (p = buff + sizeof(data); p < buff + buff_size; ++p) { 205 failure("offset: %d, %s", (int)(p - buff), msg); 206 if (!assertEqualInt(0, *p)) 207 break; 208 } 209 210 /* Check 100-byte gap */ 211 assertEqualInt(100, fread(buff, 1, 100, f)); 212 failure("%s", msg); 213 for (p = buff; p < buff + 100; ++p) { 214 failure("offset: %d, %s", (int)(p - buff), msg); 215 if (!assertEqualInt(0, *p)) 216 break; 217 } 218 219 /* Check second block. */ 220 assertEqualInt(buff_size, fread(buff, 1, buff_size, f)); 221 for (p = buff; p < buff + buff_size; ++p) { 222 failure("offset: %d, %s", (int)(p - buff), msg); 223 if (p == buff + buff_size / 2 - 3) { 224 assertEqualMem(p, data, sizeof(data)); 225 p += sizeof(data); 226 } else if (!assertEqualInt(0, *p)) 227 break; 228 } 229 230 /* Check 100-byte gap */ 231 assertEqualInt(100, fread(buff, 1, 100, f)); 232 failure("%s", msg); 233 for (p = buff; p < buff + 100; ++p) { 234 failure("offset: %d, %s", (int)(p - buff), msg); 235 if (!assertEqualInt(0, *p)) 236 break; 237 } 238 239 /* Check third block. */ 240 assertEqualInt(buff_size, fread(buff, 1, buff_size, f)); 241 for (p = buff; p < buff + buff_size - sizeof(data); ++p) { 242 failure("offset: %d, %s", (int)(p - buff), msg); 243 if (!assertEqualInt(0, *p)) 244 break; 245 } 246 failure("%s", msg); 247 assertEqualMem(buff + buff_size - sizeof(data), data, sizeof(data)); 248 249 /* Check another block size beyond last we wrote. */ 250 assertEqualInt(buff_size, fread(buff, 1, buff_size, f)); 251 failure("%s", msg); 252 for (p = buff; p < buff + buff_size; ++p) { 253 failure("offset: %d, %s", (int)(p - buff), msg); 254 if (!assertEqualInt(0, *p)) 255 break; 256 } 257 258 259 /* XXX more XXX */ 260 261 assertEqualInt(0, fclose(f)); 262 free(buff); 263 archive_entry_free(ae); 264 } 265 266 DEFINE_TEST(test_write_disk_sparse) 267 { 268 struct archive *ad; 269 270 271 /* 272 * The return values, etc, of the write data functions 273 * shouldn't change regardless of whether we've requested 274 * sparsification. (The performance and pattern of actual 275 * write calls to the disk should vary, of course, but the 276 * client program shouldn't see any difference.) 277 */ 278 assert((ad = archive_write_disk_new()) != NULL); 279 archive_write_disk_set_options(ad, 0); 280 verify_write_data(ad, 0); 281 verify_write_data_block(ad, 0); 282 assertEqualInt(0, archive_write_free(ad)); 283 284 assert((ad = archive_write_disk_new()) != NULL); 285 archive_write_disk_set_options(ad, ARCHIVE_EXTRACT_SPARSE); 286 verify_write_data(ad, 1); 287 verify_write_data_block(ad, 1); 288 assertEqualInt(0, archive_write_free(ad)); 289 290 } 291