2 * Copyright (c) 2003-2007 Tim Kientzle
3 * Copyright (c) 2006 Rudolf Marek SYSGO s.r.o.
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
16 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18 * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
19 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 #include "archive_platform.h"
28 __FBSDID("$FreeBSD: src/lib/libarchive/archive_write_set_format_cpio_newc.c,v 1.4 2008/03/15 11:04:45 kientzle Exp $");
42 #include "archive_entry.h"
43 #include "archive_private.h"
44 #include "archive_write_private.h"
46 static ssize_t
archive_write_newc_data(struct archive_write
*,
47 const void *buff
, size_t s
);
48 static int archive_write_newc_finish(struct archive_write
*);
49 static int archive_write_newc_destroy(struct archive_write
*);
50 static int archive_write_newc_finish_entry(struct archive_write
*);
51 static int archive_write_newc_header(struct archive_write
*,
52 struct archive_entry
*);
53 static int format_hex(int64_t, void *, int);
54 static int64_t format_hex_recursive(int64_t, char *, int);
57 uint64_t entry_bytes_remaining
;
61 struct cpio_header_newc
{
79 * Set output format to 'cpio' format.
82 archive_write_set_format_cpio_newc(struct archive
*_a
)
84 struct archive_write
*a
= (struct archive_write
*)_a
;
87 /* If someone else was already registered, unregister them. */
88 if (a
->format_destroy
!= NULL
)
89 (a
->format_destroy
)(a
);
91 cpio
= (struct cpio
*)malloc(sizeof(*cpio
));
93 archive_set_error(&a
->archive
, ENOMEM
, "Can't allocate cpio data");
94 return (ARCHIVE_FATAL
);
96 memset(cpio
, 0, sizeof(*cpio
));
97 a
->format_data
= cpio
;
99 a
->pad_uncompressed
= 1;
100 a
->format_write_header
= archive_write_newc_header
;
101 a
->format_write_data
= archive_write_newc_data
;
102 a
->format_finish_entry
= archive_write_newc_finish_entry
;
103 a
->format_finish
= archive_write_newc_finish
;
104 a
->format_destroy
= archive_write_newc_destroy
;
105 a
->archive
.archive_format
= ARCHIVE_FORMAT_CPIO_SVR4_NOCRC
;
106 a
->archive
.archive_format_name
= "SVR4 cpio nocrc";
111 archive_write_newc_header(struct archive_write
*a
, struct archive_entry
*entry
)
114 const char *p
, *path
;
116 struct cpio_header_newc h
;
119 cpio
= (struct cpio
*)a
->format_data
;
122 path
= archive_entry_pathname(entry
);
123 pathlength
= strlen(path
) + 1; /* Include trailing null. */
125 memset(&h
, 0, sizeof(h
));
126 format_hex(0x070701, &h
.c_magic
, sizeof(h
.c_magic
));
127 format_hex(archive_entry_devmajor(entry
), &h
.c_devmajor
, sizeof(h
.c_devmajor
));
128 format_hex(archive_entry_devminor(entry
), &h
.c_devminor
, sizeof(h
.c_devminor
));
129 if (archive_entry_ino(entry
) > 0xffffffff) {
130 archive_set_error(&a
->archive
, ERANGE
, "large inode number truncated");
134 format_hex(archive_entry_ino(entry
) & 0xffffffff, &h
.c_ino
, sizeof(h
.c_ino
));
135 format_hex(archive_entry_mode(entry
), &h
.c_mode
, sizeof(h
.c_mode
));
136 format_hex(archive_entry_uid(entry
), &h
.c_uid
, sizeof(h
.c_uid
));
137 format_hex(archive_entry_gid(entry
), &h
.c_gid
, sizeof(h
.c_gid
));
138 format_hex(archive_entry_nlink(entry
), &h
.c_nlink
, sizeof(h
.c_nlink
));
139 if (archive_entry_filetype(entry
) == AE_IFBLK
140 || archive_entry_filetype(entry
) == AE_IFCHR
) {
141 format_hex(archive_entry_rdevmajor(entry
), &h
.c_rdevmajor
, sizeof(h
.c_rdevmajor
));
142 format_hex(archive_entry_rdevminor(entry
), &h
.c_rdevminor
, sizeof(h
.c_rdevminor
));
144 format_hex(0, &h
.c_rdevmajor
, sizeof(h
.c_rdevmajor
));
145 format_hex(0, &h
.c_rdevminor
, sizeof(h
.c_rdevminor
));
147 format_hex(archive_entry_mtime(entry
), &h
.c_mtime
, sizeof(h
.c_mtime
));
148 format_hex(pathlength
, &h
.c_namesize
, sizeof(h
.c_namesize
));
149 format_hex(0, &h
.c_checksum
, sizeof(h
.c_checksum
));
151 /* Non-regular files don't store bodies. */
152 if (archive_entry_filetype(entry
) != AE_IFREG
)
153 archive_entry_set_size(entry
, 0);
155 /* Symlinks get the link written as the body of the entry. */
156 p
= archive_entry_symlink(entry
);
157 if (p
!= NULL
&& *p
!= '\0')
158 format_hex(strlen(p
), &h
.c_filesize
, sizeof(h
.c_filesize
));
160 format_hex(archive_entry_size(entry
),
161 &h
.c_filesize
, sizeof(h
.c_filesize
));
163 ret
= (a
->compressor
.write
)(a
, &h
, sizeof(h
));
164 if (ret
!= ARCHIVE_OK
)
165 return (ARCHIVE_FATAL
);
167 /* Pad pathname to even length. */
168 ret
= (a
->compressor
.write
)(a
, path
, pathlength
);
169 if (ret
!= ARCHIVE_OK
)
170 return (ARCHIVE_FATAL
);
171 pad
= 0x3 & - (pathlength
+ sizeof(struct cpio_header_newc
));
173 ret
= (a
->compressor
.write
)(a
, "\0\0\0", pad
);
174 if (ret
!= ARCHIVE_OK
)
175 return (ARCHIVE_FATAL
);
177 cpio
->entry_bytes_remaining
= archive_entry_size(entry
);
178 cpio
->padding
= 3 & (-cpio
->entry_bytes_remaining
);
180 /* Write the symlink now. */
181 if (p
!= NULL
&& *p
!= '\0') {
182 ret
= (a
->compressor
.write
)(a
, p
, strlen(p
));
183 if (ret
!= ARCHIVE_OK
)
184 return (ARCHIVE_FATAL
);
185 pad
= 0x3 & -strlen(p
);
186 ret
= (a
->compressor
.write
)(a
, "\0\0\0", pad
);
193 archive_write_newc_data(struct archive_write
*a
, const void *buff
, size_t s
)
198 cpio
= (struct cpio
*)a
->format_data
;
199 if (s
> cpio
->entry_bytes_remaining
)
200 s
= cpio
->entry_bytes_remaining
;
202 ret
= (a
->compressor
.write
)(a
, buff
, s
);
203 cpio
->entry_bytes_remaining
-= s
;
211 * Format a number into the specified field.
214 format_hex(int64_t v
, void *p
, int digits
)
219 max
= (((int64_t)1) << (digits
* 4)) - 1;
220 if (v
>= 0 && v
<= max
) {
221 format_hex_recursive(v
, (char *)p
, digits
);
224 format_hex_recursive(max
, (char *)p
, digits
);
231 format_hex_recursive(int64_t v
, char *p
, int s
)
235 v
= format_hex_recursive(v
, p
+1, s
-1);
236 *p
= "0123456789abcdef"[v
& 0xf];
241 archive_write_newc_finish(struct archive_write
*a
)
245 struct archive_entry
*trailer
;
247 cpio
= (struct cpio
*)a
->format_data
;
248 trailer
= archive_entry_new();
249 archive_entry_set_nlink(trailer
, 1);
250 archive_entry_set_pathname(trailer
, "TRAILER!!!");
251 er
= archive_write_newc_header(a
, trailer
);
252 archive_entry_free(trailer
);
257 archive_write_newc_destroy(struct archive_write
*a
)
261 cpio
= (struct cpio
*)a
->format_data
;
263 a
->format_data
= NULL
;
268 archive_write_newc_finish_entry(struct archive_write
*a
)
273 cpio
= (struct cpio
*)a
->format_data
;
275 while (cpio
->entry_bytes_remaining
> 0) {
276 to_write
= cpio
->entry_bytes_remaining
< a
->null_length
?
277 cpio
->entry_bytes_remaining
: a
->null_length
;
278 ret
= (a
->compressor
.write
)(a
, a
->nulls
, to_write
);
279 if (ret
!= ARCHIVE_OK
)
281 cpio
->entry_bytes_remaining
-= to_write
;
283 ret
= (a
->compressor
.write
)(a
, a
->nulls
, cpio
->padding
);