2 * Copyright (c) 2008 Joerg Sonnenberger
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 #include "archive_platform.h"
27 __FBSDID("$FreeBSD$");
34 #include "archive_entry.h"
35 #include "archive_private.h"
36 #include "archive_write_private.h"
39 struct archive_entry *entry;
40 struct archive_string buf;
45 mtree_safe_char(char c)
47 if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z'))
49 if (c >= '0' && c <= '9')
51 if (c == 35 || c == 61 || c == 92)
52 return 0; /* #, = and \ are always quoted */
54 if (c >= 33 && c <= 47) /* !"$%&'()*+,-./ */
56 if (c >= 58 && c <= 64) /* :;<>?@ */
58 if (c >= 91 && c <= 96) /* []^_` */
60 if (c >= 123 && c <= 126) /* {|}~ */
66 mtree_quote(struct mtree_writer *mtree, const char *str)
72 for (start = str; *str != '\0'; ++str) {
73 if (mtree_safe_char(*str))
76 archive_strncat(&mtree->buf, start, str - start);
77 c = (unsigned char)*str;
79 buf[1] = (c / 64) + '0';
80 buf[2] = (c / 8 % 8) + '0';
81 buf[3] = (c % 8) + '0';
82 archive_strncat(&mtree->buf, buf, 4);
87 archive_strncat(&mtree->buf, start, str - start);
91 archive_write_mtree_header(struct archive_write *a,
92 struct archive_entry *entry)
94 struct mtree_writer *mtree= a->format_data;
97 mtree->entry = archive_entry_clone(entry);
98 path = archive_entry_pathname(mtree->entry);
102 archive_strcat(&mtree->buf, "#mtree\n");
105 mtree_quote(mtree, path);
112 strappend_bin(struct archive_string *s, const unsigned char *bin, int n)
114 static const char hex[] = "0123456789abcdef";
117 for (i = 0; i < n; i++) {
118 archive_strappend_char(s, hex[bin[i] >> 4]);
119 archive_strappend_char(s, hex[bin[i] & 0x0f]);
125 archive_write_mtree_finish_entry(struct archive_write *a)
127 struct mtree_writer *mtree = a->format_data;
128 struct archive_entry *entry;
132 entry = mtree->entry;
134 archive_set_error(&a->archive, ARCHIVE_ERRNO_PROGRAMMER,
135 "Finished entry without being open first.");
136 return (ARCHIVE_FATAL);
140 if (archive_entry_nlink(entry) != 1 &&
141 archive_entry_filetype(entry) != AE_IFDIR)
142 archive_string_sprintf(&mtree->buf,
143 " nlink=%u", archive_entry_nlink(entry));
145 if ((name = archive_entry_gname(entry)) != NULL) {
146 archive_strcat(&mtree->buf, " gname=");
147 mtree_quote(mtree, name);
149 if ((name = archive_entry_uname(entry)) != NULL) {
150 archive_strcat(&mtree->buf, " uname=");
151 mtree_quote(mtree, name);
153 if ((name = archive_entry_fflags_text(entry)) != NULL) {
154 archive_strcat(&mtree->buf, " flags=");
155 mtree_quote(mtree, name);
158 archive_string_sprintf(&mtree->buf,
159 " time=%jd mode=%o gid=%jd uid=%jd",
160 (intmax_t)archive_entry_mtime(entry),
161 archive_entry_mode(entry) & 07777,
162 (intmax_t)archive_entry_gid(entry),
163 (intmax_t)archive_entry_uid(entry));
165 switch (archive_entry_filetype(entry)) {
167 archive_strcat(&mtree->buf, " type=link link=");
168 mtree_quote(mtree, archive_entry_symlink(entry));
169 archive_strcat(&mtree->buf, "\n");
172 archive_strcat(&mtree->buf, " type=socket\n");
175 archive_string_sprintf(&mtree->buf,
176 " type=char device=native,%d,%d\n",
177 archive_entry_rdevmajor(entry),
178 archive_entry_rdevminor(entry));
181 archive_string_sprintf(&mtree->buf,
182 " type=block device=native,%d,%d\n",
183 archive_entry_rdevmajor(entry),
184 archive_entry_rdevminor(entry));
187 archive_strcat(&mtree->buf, " type=dir\n");
190 archive_strcat(&mtree->buf, " type=fifo\n");
193 default: /* Handle unknown file types as regular files. */
194 archive_string_sprintf(&mtree->buf, " type=file size=%jd\n",
195 (intmax_t)archive_entry_size(entry));
199 archive_entry_free(entry);
201 if (mtree->buf.length > 32768) {
202 ret = (a->compressor.write)(a, mtree->buf.s, mtree->buf.length);
203 archive_string_empty(&mtree->buf);
207 return (ret == ARCHIVE_OK ? ret : ARCHIVE_FATAL);
211 archive_write_mtree_finish(struct archive_write *a)
213 struct mtree_writer *mtree= a->format_data;
215 archive_write_set_bytes_in_last_block(&a->archive, 1);
217 return (a->compressor.write)(a, mtree->buf.s, mtree->buf.length);
221 archive_write_mtree_data(struct archive_write *a, const void *buff, size_t n)
223 (void)a; /* UNUSED */
224 (void)buff; /* UNUSED */
229 archive_write_mtree_destroy(struct archive_write *a)
231 struct mtree_writer *mtree= a->format_data;
236 archive_entry_free(mtree->entry);
237 archive_string_free(&mtree->buf);
239 a->format_data = NULL;
244 archive_write_set_format_mtree(struct archive *_a)
246 struct archive_write *a = (struct archive_write *)_a;
247 struct mtree_writer *mtree;
249 if (a->format_destroy != NULL)
250 (a->format_destroy)(a);
252 if ((mtree = malloc(sizeof(*mtree))) == NULL) {
253 archive_set_error(&a->archive, ENOMEM,
254 "Can't allocate mtree data");
255 return (ARCHIVE_FATAL);
260 archive_string_init(&mtree->buf);
261 a->format_data = mtree;
262 a->format_destroy = archive_write_mtree_destroy;
264 a->pad_uncompressed = 0;
265 a->format_name = "mtree";
266 a->format_write_header = archive_write_mtree_header;
267 a->format_finish = archive_write_mtree_finish;
268 a->format_write_data = archive_write_mtree_data;
269 a->format_finish_entry = archive_write_mtree_finish_entry;
270 a->archive.archive_format = ARCHIVE_FORMAT_MTREE;
271 a->archive.archive_format_name = "mtree";