1228753Smm/*- 2228753Smm * Copyright (c) 2003-2007 Tim Kientzle 3228753Smm * All rights reserved. 4228753Smm * 5228753Smm * Redistribution and use in source and binary forms, with or without 6228753Smm * modification, are permitted provided that the following conditions 7228753Smm * are met: 8228753Smm * 1. Redistributions of source code must retain the above copyright 9228753Smm * notice, this list of conditions and the following disclaimer. 10228753Smm * 2. Redistributions in binary form must reproduce the above copyright 11228753Smm * notice, this list of conditions and the following disclaimer in the 12228753Smm * documentation and/or other materials provided with the distribution. 13228753Smm * 14228753Smm * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR 15228753Smm * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 16228753Smm * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 17228753Smm * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, 18228753Smm * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 19228753Smm * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 20228753Smm * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 21228753Smm * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22228753Smm * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 23228753Smm * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24228753Smm */ 25228753Smm#include "test.h" 26229592Smm__FBSDID("$FreeBSD$"); 27228753Smm 28228753Smm#if ARCHIVE_VERSION_NUMBER >= 1009000 29228753Smm 30228753Smm#define UMASK 022 31228753Smm/* 32228753Smm * When comparing mode values, ignore high-order bits 33228753Smm * that are set on some OSes. This should cover the bits 34228753Smm * we're interested in (standard mode bits + file type bits) 35228753Smm * while ignoring extra markers such as Haiku/BeOS index 36228753Smm * flags. 37228753Smm */ 38228753Smm#define MODE_MASK 0777777 39228753Smm 40228753Smmstatic void create(struct archive_entry *ae, const char *msg) 41228753Smm{ 42228753Smm struct archive *ad; 43228753Smm struct stat st; 44228753Smm 45228753Smm /* Write the entry to disk. */ 46228753Smm assert((ad = archive_write_disk_new()) != NULL); 47228753Smm failure("%s", msg); 48228753Smm assertEqualIntA(ad, 0, archive_write_header(ad, ae)); 49228753Smm assertEqualIntA(ad, 0, archive_write_finish_entry(ad)); 50228753Smm#if ARCHIVE_VERSION_NUMBER < 2000000 51228753Smm archive_write_finish(ad); 52228753Smm#else 53228753Smm assertEqualInt(0, archive_write_finish(ad)); 54228753Smm#endif 55228753Smm /* Test the entries on disk. */ 56228753Smm assert(0 == stat(archive_entry_pathname(ae), &st)); 57228753Smm failure("%s", msg); 58228753Smm 59228753Smm#if !defined(_WIN32) || defined(__CYGWIN__) 60228753Smm /* When verifying a dir, ignore the S_ISGID bit, as some systems set 61228753Smm * that automatically. */ 62228753Smm if (archive_entry_filetype(ae) == AE_IFDIR) 63228753Smm st.st_mode &= ~S_ISGID; 64228753Smm assertEqualInt(st.st_mode & MODE_MASK, 65228753Smm archive_entry_mode(ae) & ~UMASK & MODE_MASK); 66228753Smm#endif 67228753Smm} 68228753Smm 69228753Smmstatic void create_reg_file(struct archive_entry *ae, const char *msg) 70228753Smm{ 71228753Smm static const char data[]="abcdefghijklmnopqrstuvwxyz"; 72228753Smm struct archive *ad; 73228753Smm 74228753Smm /* Write the entry to disk. */ 75228753Smm assert((ad = archive_write_disk_new()) != NULL); 76228753Smm archive_write_disk_set_options(ad, ARCHIVE_EXTRACT_TIME); 77228753Smm failure("%s", msg); 78228753Smm /* 79228753Smm * A touchy API design issue: archive_write_data() does (as of 80228753Smm * 2.4.12) enforce the entry size as a limit on the data 81228753Smm * written to the file. This was not enforced prior to 82228753Smm * 2.4.12. The change was prompted by the refined 83228753Smm * hardlink-restore semantics introduced at that time. In 84228753Smm * short, libarchive needs to know whether a "hardlink entry" 85228753Smm * is going to overwrite the contents so that it can know 86228753Smm * whether or not to open the file for writing. This implies 87228753Smm * that there is a fundamental semantic difference between an 88228753Smm * entry with a zero size and one with a non-zero size in the 89228753Smm * case of hardlinks and treating the hardlink case 90228753Smm * differently from the regular file case is just asking for 91228753Smm * trouble. So, a zero size must always mean that no data 92228753Smm * will be accepted, which is consistent with the file size in 93228753Smm * the entry being a maximum size. 94228753Smm */ 95228753Smm archive_entry_set_size(ae, sizeof(data)); 96228753Smm archive_entry_set_mtime(ae, 123456789, 0); 97228753Smm assertEqualIntA(ad, 0, archive_write_header(ad, ae)); 98228753Smm assertEqualInt(sizeof(data), archive_write_data(ad, data, sizeof(data))); 99228753Smm assertEqualIntA(ad, 0, archive_write_finish_entry(ad)); 100228753Smm#if ARCHIVE_VERSION_NUMBER < 2000000 101228753Smm archive_write_finish(ad); 102228753Smm#else 103228753Smm assertEqualInt(0, archive_write_finish(ad)); 104228753Smm#endif 105228753Smm /* Test the entries on disk. */ 106228753Smm assertIsReg(archive_entry_pathname(ae), archive_entry_mode(ae) & 0777); 107228753Smm assertFileSize(archive_entry_pathname(ae), sizeof(data)); 108228753Smm /* test_write_disk_times has more detailed tests of this area. */ 109228753Smm assertFileMtime(archive_entry_pathname(ae), 123456789, 0); 110228753Smm failure("No atime given, so atime should get set to current time"); 111228753Smm assertFileAtimeRecent(archive_entry_pathname(ae)); 112228753Smm} 113228753Smm 114228753Smmstatic void create_reg_file2(struct archive_entry *ae, const char *msg) 115228753Smm{ 116228753Smm const int datasize = 100000; 117228753Smm char *data; 118228753Smm struct archive *ad; 119228753Smm int i; 120228753Smm 121228753Smm data = malloc(datasize); 122228753Smm for (i = 0; i < datasize; i++) 123228753Smm data[i] = (char)(i % 256); 124228753Smm 125228753Smm /* Write the entry to disk. */ 126228753Smm assert((ad = archive_write_disk_new()) != NULL); 127228753Smm failure("%s", msg); 128228753Smm /* 129228753Smm * See above for an explanation why this next call 130228753Smm * is necessary. 131228753Smm */ 132228753Smm archive_entry_set_size(ae, datasize); 133228753Smm assertEqualIntA(ad, 0, archive_write_header(ad, ae)); 134228753Smm for (i = 0; i < datasize - 999; i += 1000) { 135228753Smm assertEqualIntA(ad, ARCHIVE_OK, 136228753Smm archive_write_data_block(ad, data + i, 1000, i)); 137228753Smm } 138228753Smm assertEqualIntA(ad, 0, archive_write_finish_entry(ad)); 139228753Smm assertEqualInt(0, archive_write_finish(ad)); 140228753Smm 141228753Smm /* Test the entries on disk. */ 142228753Smm assertIsReg(archive_entry_pathname(ae), archive_entry_mode(ae) & 0777); 143228753Smm assertFileSize(archive_entry_pathname(ae), i); 144228753Smm assertFileContents(data, datasize, archive_entry_pathname(ae)); 145228753Smm free(data); 146228753Smm} 147228753Smm 148228753Smmstatic void create_reg_file3(struct archive_entry *ae, const char *msg) 149228753Smm{ 150228753Smm static const char data[]="abcdefghijklmnopqrstuvwxyz"; 151228753Smm struct archive *ad; 152228753Smm struct stat st; 153228753Smm 154228753Smm /* Write the entry to disk. */ 155228753Smm assert((ad = archive_write_disk_new()) != NULL); 156228753Smm failure("%s", msg); 157228753Smm /* Set the size smaller than the data and verify the truncation. */ 158228753Smm archive_entry_set_size(ae, 5); 159228753Smm assertEqualIntA(ad, 0, archive_write_header(ad, ae)); 160228753Smm assertEqualInt(5, archive_write_data(ad, data, sizeof(data))); 161228753Smm assertEqualIntA(ad, 0, archive_write_finish_entry(ad)); 162228753Smm#if ARCHIVE_VERSION_NUMBER < 2000000 163228753Smm archive_write_finish(ad); 164228753Smm#else 165228753Smm assertEqualInt(0, archive_write_finish(ad)); 166228753Smm#endif 167228753Smm /* Test the entry on disk. */ 168228753Smm assert(0 == stat(archive_entry_pathname(ae), &st)); 169228753Smm failure("st.st_mode=%o archive_entry_mode(ae)=%o", 170228753Smm st.st_mode, archive_entry_mode(ae)); 171228753Smm#if !defined(_WIN32) || defined(__CYGWIN__) 172228753Smm assertEqualInt(st.st_mode, (archive_entry_mode(ae) & ~UMASK)); 173228753Smm#endif 174228753Smm assertEqualInt(st.st_size, 5); 175228753Smm} 176228753Smm 177228753Smm 178228753Smmstatic void create_reg_file4(struct archive_entry *ae, const char *msg) 179228753Smm{ 180228753Smm static const char data[]="abcdefghijklmnopqrstuvwxyz"; 181228753Smm struct archive *ad; 182228753Smm struct stat st; 183228753Smm 184228753Smm /* Write the entry to disk. */ 185228753Smm assert((ad = archive_write_disk_new()) != NULL); 186228753Smm /* Leave the size unset. The data should not be truncated. */ 187228753Smm assertEqualIntA(ad, 0, archive_write_header(ad, ae)); 188228753Smm assertEqualInt(ARCHIVE_OK, 189228753Smm archive_write_data_block(ad, data, sizeof(data), 0)); 190228753Smm assertEqualIntA(ad, 0, archive_write_finish_entry(ad)); 191228753Smm#if ARCHIVE_VERSION_NUMBER < 2000000 192228753Smm archive_write_finish(ad); 193228753Smm#else 194228753Smm assertEqualInt(0, archive_write_finish(ad)); 195228753Smm#endif 196228753Smm /* Test the entry on disk. */ 197228753Smm assert(0 == stat(archive_entry_pathname(ae), &st)); 198228753Smm failure("st.st_mode=%o archive_entry_mode(ae)=%o", 199228753Smm st.st_mode, archive_entry_mode(ae)); 200228753Smm#if !defined(_WIN32) || defined(__CYGWIN__) 201228753Smm assertEqualInt(st.st_mode, (archive_entry_mode(ae) & ~UMASK)); 202228753Smm#endif 203228753Smm failure(msg); 204228753Smm assertEqualInt(st.st_size, sizeof(data)); 205228753Smm} 206228753Smm 207228753Smm#if defined(_WIN32) && !defined(__CYGWIN__) 208228753Smmstatic void create_reg_file_win(struct archive_entry *ae, const char *msg) 209228753Smm{ 210228753Smm static const char data[]="abcdefghijklmnopqrstuvwxyz"; 211228753Smm struct archive *ad; 212228753Smm struct stat st; 213228753Smm char *p, *fname; 214228753Smm size_t l; 215228753Smm 216228753Smm /* Write the entry to disk. */ 217228753Smm assert((ad = archive_write_disk_new()) != NULL); 218228753Smm archive_write_disk_set_options(ad, ARCHIVE_EXTRACT_TIME); 219228753Smm failure("%s", msg); 220228753Smm archive_entry_set_size(ae, sizeof(data)); 221228753Smm archive_entry_set_mtime(ae, 123456789, 0); 222228753Smm assertEqualIntA(ad, 0, archive_write_header(ad, ae)); 223228753Smm assertEqualInt(sizeof(data), archive_write_data(ad, data, sizeof(data))); 224228753Smm assertEqualIntA(ad, 0, archive_write_finish_entry(ad)); 225228753Smm#if ARCHIVE_VERSION_NUMBER < 2000000 226228753Smm archive_write_finish(ad); 227228753Smm#else 228228753Smm assertEqualInt(0, archive_write_finish(ad)); 229228753Smm#endif 230228753Smm /* Test the entries on disk. */ 231228753Smm l = strlen(archive_entry_pathname(ae)); 232228753Smm fname = malloc(l + 1); 233228753Smm assert(NULL != fname); 234228753Smm strcpy(fname, archive_entry_pathname(ae)); 235228753Smm /* Replace unusable characters in Windows to '_' */ 236228753Smm for (p = fname; *p != '\0'; p++) 237228753Smm if (*p == ':' || *p == '*' || *p == '?' || 238228753Smm *p == '"' || *p == '<' || *p == '>' || *p == '|') 239228753Smm *p = '_'; 240228753Smm assert(0 == stat(fname, &st)); 241228753Smm failure("st.st_mode=%o archive_entry_mode(ae)=%o", 242228753Smm st.st_mode, archive_entry_mode(ae)); 243228753Smm assertEqualInt(st.st_size, sizeof(data)); 244228753Smm} 245228753Smm#endif /* _WIN32 && !__CYGWIN__ */ 246228753Smm#endif 247228753Smm 248228753SmmDEFINE_TEST(test_write_disk) 249228753Smm{ 250228753Smm#if ARCHIVE_VERSION_NUMBER < 1009000 251228753Smm skipping("archive_write_disk interface"); 252228753Smm#else 253228753Smm struct archive_entry *ae; 254228753Smm 255228753Smm /* Force the umask to something predictable. */ 256228753Smm assertUmask(UMASK); 257228753Smm 258228753Smm /* A regular file. */ 259228753Smm assert((ae = archive_entry_new()) != NULL); 260228753Smm archive_entry_copy_pathname(ae, "file"); 261228753Smm archive_entry_set_mode(ae, S_IFREG | 0755); 262228753Smm create_reg_file(ae, "Test creating a regular file"); 263228753Smm archive_entry_free(ae); 264228753Smm 265228753Smm /* Another regular file. */ 266228753Smm assert((ae = archive_entry_new()) != NULL); 267228753Smm archive_entry_copy_pathname(ae, "file2"); 268228753Smm archive_entry_set_mode(ae, S_IFREG | 0755); 269228753Smm create_reg_file2(ae, "Test creating another regular file"); 270228753Smm archive_entry_free(ae); 271228753Smm 272228753Smm /* A regular file with a size restriction */ 273228753Smm assert((ae = archive_entry_new()) != NULL); 274228753Smm archive_entry_copy_pathname(ae, "file3"); 275228753Smm archive_entry_set_mode(ae, S_IFREG | 0755); 276228753Smm create_reg_file3(ae, "Regular file with size restriction"); 277228753Smm archive_entry_free(ae); 278228753Smm 279228753Smm /* A regular file with an unspecified size */ 280228753Smm assert((ae = archive_entry_new()) != NULL); 281228753Smm archive_entry_copy_pathname(ae, "file3"); 282228753Smm archive_entry_set_mode(ae, S_IFREG | 0755); 283228753Smm create_reg_file4(ae, "Regular file with unspecified size"); 284228753Smm archive_entry_free(ae); 285228753Smm 286228753Smm /* A regular file over an existing file */ 287228753Smm assert((ae = archive_entry_new()) != NULL); 288228753Smm archive_entry_copy_pathname(ae, "file"); 289228753Smm archive_entry_set_mode(ae, S_IFREG | 0724); 290228753Smm create(ae, "Test creating a file over an existing file."); 291228753Smm archive_entry_free(ae); 292228753Smm 293228753Smm /* A directory. */ 294228753Smm assert((ae = archive_entry_new()) != NULL); 295228753Smm archive_entry_copy_pathname(ae, "dir"); 296228753Smm archive_entry_set_mode(ae, S_IFDIR | 0555); 297228753Smm create(ae, "Test creating a regular dir."); 298228753Smm archive_entry_free(ae); 299228753Smm 300228753Smm /* A directory over an existing file. */ 301228753Smm assert((ae = archive_entry_new()) != NULL); 302228753Smm archive_entry_copy_pathname(ae, "file"); 303228753Smm archive_entry_set_mode(ae, S_IFDIR | 0742); 304228753Smm create(ae, "Test creating a dir over an existing file."); 305228753Smm archive_entry_free(ae); 306228753Smm 307228753Smm /* A file over an existing dir. */ 308228753Smm assert((ae = archive_entry_new()) != NULL); 309228753Smm archive_entry_copy_pathname(ae, "file"); 310228753Smm archive_entry_set_mode(ae, S_IFREG | 0744); 311228753Smm create(ae, "Test creating a file over an existing dir."); 312228753Smm archive_entry_free(ae); 313228753Smm 314228753Smm#if defined(_WIN32) && !defined(__CYGWIN__) 315228753Smm /* A file with unusable characters in its file name. */ 316228753Smm assert((ae = archive_entry_new()) != NULL); 317228753Smm archive_entry_copy_pathname(ae, "f:i*l?e\"f<i>l|e"); 318228753Smm archive_entry_set_mode(ae, S_IFREG | 0755); 319228753Smm create_reg_file_win(ae, "Test creating a regular file" 320228753Smm " with unusable characters in its file name"); 321228753Smm archive_entry_free(ae); 322228753Smm 323228753Smm /* A file with unusable characters in its directory name. */ 324228753Smm assert((ae = archive_entry_new()) != NULL); 325228753Smm archive_entry_copy_pathname(ae, "d:i*r?e\"c<t>o|ry/file1"); 326228753Smm archive_entry_set_mode(ae, S_IFREG | 0755); 327228753Smm create_reg_file_win(ae, "Test creating a regular file" 328228753Smm " with unusable characters in its file name"); 329228753Smm archive_entry_free(ae); 330228753Smm#endif /* _WIN32 && !__CYGWIN__ */ 331228753Smm#endif 332228753Smm} 333