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