2 * Copyright (c) 2003-2007 Tim Kientzle
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
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.
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.
26 __FBSDID("$FreeBSD$");
31 * Exercise hardlink recreation.
33 * File permissions are chosen so that the authoritive entry
34 * has the correct permission and the non-authoritive versions
35 * are just writeable files.
37 DEFINE_TEST(test_write_disk_hardlink)
39 #if ARCHIVE_VERSION_STAMP < 1009000
40 skipping("archive_write_disk_hardlink tests");
42 static const char data[]="abcdefghijklmnopqrstuvwxyz";
44 struct archive_entry *ae;
47 /* Force the umask to something predictable. */
50 /* Write entries to disk. */
51 assert((ad = archive_write_disk_new()) != NULL);
54 * First, use a tar-like approach; a regular file, then
55 * a separate "hardlink" entry.
59 assert((ae = archive_entry_new()) != NULL);
60 archive_entry_copy_pathname(ae, "link1a");
61 archive_entry_set_mode(ae, S_IFREG | 0755);
62 archive_entry_set_size(ae, sizeof(data));
63 assertEqualIntA(ad, 0, archive_write_header(ad, ae));
64 assertEqualInt(sizeof(data),
65 archive_write_data(ad, data, sizeof(data)));
66 assertEqualIntA(ad, 0, archive_write_finish_entry(ad));
67 archive_entry_free(ae);
69 /* Link. Size of zero means this doesn't carry data. */
70 assert((ae = archive_entry_new()) != NULL);
71 archive_entry_copy_pathname(ae, "link1b");
72 archive_entry_set_mode(ae, S_IFREG | 0642);
73 archive_entry_set_size(ae, 0);
74 archive_entry_copy_hardlink(ae, "link1a");
75 assertEqualIntA(ad, 0, archive_write_header(ad, ae));
76 assertEqualInt(ARCHIVE_WARN,
77 archive_write_data(ad, data, sizeof(data)));
78 assertEqualIntA(ad, 0, archive_write_finish_entry(ad));
79 archive_entry_free(ae);
82 * Repeat tar approach test, but use unset to mark the
83 * hardlink as having no data.
87 assert((ae = archive_entry_new()) != NULL);
88 archive_entry_copy_pathname(ae, "link2a");
89 archive_entry_set_mode(ae, S_IFREG | 0755);
90 archive_entry_set_size(ae, sizeof(data));
91 assertEqualIntA(ad, 0, archive_write_header(ad, ae));
92 assertEqualInt(sizeof(data),
93 archive_write_data(ad, data, sizeof(data)));
94 assertEqualIntA(ad, 0, archive_write_finish_entry(ad));
95 archive_entry_free(ae);
97 /* Link. Unset size means this doesn't carry data. */
98 assert((ae = archive_entry_new()) != NULL);
99 archive_entry_copy_pathname(ae, "link2b");
100 archive_entry_set_mode(ae, S_IFREG | 0642);
101 archive_entry_unset_size(ae);
102 archive_entry_copy_hardlink(ae, "link2a");
103 assertEqualIntA(ad, 0, archive_write_header(ad, ae));
104 assertEqualInt(ARCHIVE_WARN,
105 archive_write_data(ad, data, sizeof(data)));
106 assertEqualIntA(ad, 0, archive_write_finish_entry(ad));
107 archive_entry_free(ae);
110 * Second, try an old-cpio-like approach; a regular file, then
111 * another identical one (which has been marked hardlink).
115 assert((ae = archive_entry_new()) != NULL);
116 archive_entry_copy_pathname(ae, "link3a");
117 archive_entry_set_mode(ae, S_IFREG | 0600);
118 archive_entry_set_size(ae, sizeof(data));
119 assertEqualIntA(ad, 0, archive_write_header(ad, ae));
120 assertEqualInt(sizeof(data), archive_write_data(ad, data, sizeof(data)));
121 assertEqualIntA(ad, 0, archive_write_finish_entry(ad));
122 archive_entry_free(ae);
125 assert((ae = archive_entry_new()) != NULL);
126 archive_entry_copy_pathname(ae, "link3b");
127 archive_entry_set_mode(ae, S_IFREG | 0755);
128 archive_entry_set_size(ae, sizeof(data));
129 archive_entry_copy_hardlink(ae, "link3a");
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);
136 * Finally, try a new-cpio-like approach, where the initial
137 * regular file is empty and the hardlink has the data.
141 assert((ae = archive_entry_new()) != NULL);
142 archive_entry_copy_pathname(ae, "link4a");
143 archive_entry_set_mode(ae, S_IFREG | 0600);
144 archive_entry_set_size(ae, 0);
145 assertEqualIntA(ad, 0, archive_write_header(ad, ae));
146 #if ARCHIVE_VERSION_NUMBER < 3000000
147 assertEqualInt(ARCHIVE_WARN, archive_write_data(ad, data, 1));
149 assertEqualInt(-1, archive_write_data(ad, data, 1));
151 assertEqualIntA(ad, 0, archive_write_finish_entry(ad));
152 archive_entry_free(ae);
155 assert((ae = archive_entry_new()) != NULL);
156 archive_entry_copy_pathname(ae, "link4b");
157 archive_entry_set_mode(ae, S_IFREG | 0755);
158 archive_entry_set_size(ae, sizeof(data));
159 archive_entry_copy_hardlink(ae, "link4a");
160 assertEqualIntA(ad, 0, archive_write_header(ad, ae));
161 assertEqualInt(sizeof(data), archive_write_data(ad, data, sizeof(data)));
162 assertEqualIntA(ad, 0, archive_write_finish_entry(ad));
163 archive_entry_free(ae);
164 #if ARCHIVE_VERSION_NUMBER < 2000000
165 archive_write_finish(ad);
167 assertEqualInt(0, archive_write_finish(ad));
170 /* Test the entries on disk. */
173 assert(0 == stat("link1a", &st));
174 /* If the hardlink was successfully created and the archive
175 * doesn't carry data for it, we consider it to be
176 * non-authoritive for meta data as well. This is consistent
177 * with GNU tar and BSD pax. */
178 assertEqualInt(st.st_mode, (S_IFREG | 0755) & ~UMASK);
179 assertEqualInt(st.st_size, sizeof(data));
180 assertEqualInt(st.st_nlink, 2);
182 assert(0 == stat("link1b", &st2));
183 assertEqualInt(st.st_mode, st2.st_mode);
184 assertEqualInt(st.st_size, st2.st_size);
185 assertEqualInt(st.st_nlink, st2.st_nlink);
186 assertEqualInt(st.st_ino, st2.st_ino);
187 assertEqualInt(st.st_dev, st2.st_dev);
189 /* Test #2: Should produce identical results to test #1 */
190 /* Note that marking a hardlink with size = 0 is treated the
191 * same as having an unset size. This is partly for backwards
192 * compatibility (we used to not have unset tracking, so
193 * relied on size == 0) and partly to match the model used by
194 * common file formats that store a size of zero for
196 assert(0 == stat("link2a", &st));
197 assertEqualInt(st.st_mode, (S_IFREG | 0755) & ~UMASK);
198 assertEqualInt(st.st_size, sizeof(data));
199 assertEqualInt(st.st_nlink, 2);
201 assert(0 == stat("link2b", &st2));
202 assertEqualInt(st.st_mode, st2.st_mode);
203 assertEqualInt(st.st_size, st2.st_size);
204 assertEqualInt(st.st_nlink, st2.st_nlink);
205 assertEqualInt(st.st_ino, st2.st_ino);
206 assertEqualInt(st.st_dev, st2.st_dev);
209 assert(0 == stat("link3a", &st));
210 assertEqualInt(st.st_mode, (S_IFREG | 0755) & ~UMASK);
211 assertEqualInt(st.st_size, sizeof(data));
212 assertEqualInt(st.st_nlink, 2);
214 assert(0 == stat("link3b", &st2));
215 assertEqualInt(st2.st_mode, (S_IFREG | 0755) & ~UMASK);
216 assertEqualInt(st2.st_size, sizeof(data));
217 assertEqualInt(st2.st_nlink, 2);
218 assertEqualInt(st.st_ino, st2.st_ino);
219 assertEqualInt(st.st_dev, st2.st_dev);
222 assert(0 == stat("link4a", &st));
223 assertEqualInt(st.st_mode, (S_IFREG | 0755) & ~UMASK);
224 assertEqualInt(st.st_size, sizeof(data));
225 assertEqualInt(st.st_nlink, 2);
227 assert(0 == stat("link4b", &st2));
228 assertEqualInt(st2.st_mode, (S_IFREG | 0755) & ~UMASK);
229 assertEqualInt(st2.st_size, sizeof(data));
230 assertEqualInt(st2.st_nlink, 2);
231 assertEqualInt(st.st_ino, st2.st_ino);
232 assertEqualInt(st.st_dev, st2.st_dev);