]> CyberLeo.Net >> Repos - FreeBSD/stable/10.git/blob - contrib/libarchive/libarchive/test/test_write_disk_hardlink.c
MFC r368207,368607:
[FreeBSD/stable/10.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 authoritative entry
41  * has the correct permission and the non-authoritative 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         assertEqualInt(ARCHIVE_WARN, archive_write_data(ad, data, 1));
161         assertEqualIntA(ad, 0, archive_write_finish_entry(ad));
162         archive_entry_free(ae);
163
164         /* Link. */
165         assert((ae = archive_entry_new()) != NULL);
166         archive_entry_copy_pathname(ae, "link4b");
167         archive_entry_set_mode(ae, S_IFREG | 0755);
168         archive_entry_set_size(ae, sizeof(data));
169         archive_entry_copy_hardlink(ae, "link4a");
170         assertEqualIntA(ad, 0, r = archive_write_header(ad, ae));
171         if (r > ARCHIVE_FAILED) {
172                 assertEqualInt(sizeof(data),
173                     archive_write_data(ad, data, sizeof(data)));
174                 assertEqualIntA(ad, 0, archive_write_finish_entry(ad));
175         }
176         archive_entry_free(ae);
177         assertEqualInt(0, archive_write_free(ad));
178
179         /* Test the entries on disk. */
180
181         /* Test #1 */
182         /* If the hardlink was successfully created and the archive
183          * doesn't carry data for it, we consider it to be
184          * non-authoritative for meta data as well.  This is consistent
185          * with GNU tar and BSD pax.  */
186         assertIsReg("link1a", 0755 & ~UMASK);
187         assertFileSize("link1a", sizeof(data));
188         assertFileNLinks("link1a", 2);
189         assertIsHardlink("link1a", "link1b");
190
191         /* Test #2: Should produce identical results to test #1 */
192         /* Note that marking a hardlink with size = 0 is treated the
193          * same as having an unset size.  This is partly for backwards
194          * compatibility (we used to not have unset tracking, so
195          * relied on size == 0) and partly to match the model used by
196          * common file formats that store a size of zero for
197          * hardlinks. */
198         assertIsReg("link2a", 0755 & ~UMASK);
199         assertFileSize("link2a", sizeof(data));
200         assertFileNLinks("link2a", 2);
201         assertIsHardlink("link2a", "link2b");
202
203         /* Test #3 */
204         assertIsReg("link3a", 0755 & ~UMASK);
205         assertFileSize("link3a", sizeof(data));
206         assertFileNLinks("link3a", 2);
207         assertIsHardlink("link3a", "link3b");
208
209         /* Test #4 */
210         assertIsReg("link4a", 0755 & ~UMASK);
211         assertFileNLinks("link4a", 2);
212         assertFileSize("link4a", sizeof(data));
213         assertIsHardlink("link4a", "link4b");
214 #endif
215 }