]> CyberLeo.Net >> Repos - FreeBSD/releng/9.2.git/blob - contrib/libarchive/libarchive/test/test_write_disk_hardlink.c
- Copy stable/9 to releng/9.2 as part of the 9.2-RELEASE cycle.
[FreeBSD/releng/9.2.git] / contrib / libarchive / libarchive / test / test_write_disk_hardlink.c
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  */
44 DEFINE_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 }