]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - lib/libarchive/archive_write_set_format_mtree.c
Merge r491,493,500,507,510,530,543 from libarchive.googlecode.com:
[FreeBSD/FreeBSD.git] / lib / libarchive / archive_write_set_format_mtree.c
1 /*-
2  * Copyright (c) 2008 Joerg Sonnenberger
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
26 #include "archive_platform.h"
27 __FBSDID("$FreeBSD$");
28
29 #include <errno.h>
30 #include <stdlib.h>
31 #include <string.h>
32
33 #include "archive.h"
34 #include "archive_entry.h"
35 #include "archive_private.h"
36 #include "archive_write_private.h"
37
38 struct mtree_writer {
39         struct archive_entry *entry;
40         struct archive_string buf;
41         int first;
42 };
43
44 static int
45 mtree_safe_char(char c)
46 {
47         if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z'))
48                 return 1;
49         if (c >= '0' && c <= '9')
50                 return 1;
51         if (c == 35 || c == 61 || c == 92)
52                 return 0; /* #, = and \ are always quoted */
53         
54         if (c >= 33 && c <= 47) /* !"$%&'()*+,-./ */
55                 return 1;
56         if (c >= 58 && c <= 64) /* :;<>?@ */
57                 return 1;
58         if (c >= 91 && c <= 96) /* []^_` */
59                 return 1;
60         if (c >= 123 && c <= 126) /* {|}~ */
61                 return 1;
62         return 0;
63 }
64
65 static void
66 mtree_quote(struct mtree_writer *mtree, const char *str)
67 {
68         const char *start;
69         char buf[4];
70         unsigned char c;
71
72         for (start = str; *str != '\0'; ++str) {
73                 if (mtree_safe_char(*str))
74                         continue;
75                 if (start != str)
76                         archive_strncat(&mtree->buf, start, str - start);
77                 c = (unsigned char)*str;
78                 buf[0] = '\\';
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);
83                 start = str + 1;
84         }
85
86         if (start != str)
87                 archive_strncat(&mtree->buf, start, str - start);
88 }
89
90 static int
91 archive_write_mtree_header(struct archive_write *a,
92     struct archive_entry *entry)
93 {
94         struct mtree_writer *mtree= a->format_data;
95         const char *path;
96
97         mtree->entry = archive_entry_clone(entry);
98         path = archive_entry_pathname(mtree->entry);
99
100         if (mtree->first) {
101                 mtree->first = 0;
102                 archive_strcat(&mtree->buf, "#mtree\n");
103         }
104
105         mtree_quote(mtree, path);
106
107         return (ARCHIVE_OK);
108 }
109
110 #if 0
111 static void
112 strappend_bin(struct archive_string *s, const unsigned char *bin, int n)
113 {
114         static const char hex[] = "0123456789abcdef";
115         int i;
116
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]);
120         }
121 }
122 #endif
123
124 static int
125 archive_write_mtree_finish_entry(struct archive_write *a)
126 {
127         struct mtree_writer *mtree = a->format_data;
128         struct archive_entry *entry;
129         const char *name;
130         int ret;
131
132         entry = mtree->entry;
133         if (entry == NULL) {
134                 archive_set_error(&a->archive, ARCHIVE_ERRNO_PROGRAMMER,
135                     "Finished entry without being open first.");
136                 return (ARCHIVE_FATAL);
137         }
138         mtree->entry = NULL;
139
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));
144
145         if ((name = archive_entry_gname(entry)) != NULL) {
146                 archive_strcat(&mtree->buf, " gname=");
147                 mtree_quote(mtree, name);
148         }
149         if ((name = archive_entry_uname(entry)) != NULL) {
150                 archive_strcat(&mtree->buf, " uname=");
151                 mtree_quote(mtree, name);
152         }
153         if ((name = archive_entry_fflags_text(entry)) != NULL) {
154                 archive_strcat(&mtree->buf, " flags=");
155                 mtree_quote(mtree, name);
156         }
157
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));
164
165         switch (archive_entry_filetype(entry)) {
166         case AE_IFLNK:
167                 archive_strcat(&mtree->buf, " type=link link=");
168                 mtree_quote(mtree, archive_entry_symlink(entry));
169                 archive_strcat(&mtree->buf, "\n");
170                 break;
171         case AE_IFSOCK:
172                 archive_strcat(&mtree->buf, " type=socket\n");
173                 break;
174         case AE_IFCHR:
175                 archive_string_sprintf(&mtree->buf,
176                     " type=char device=native,%d,%d\n",
177                     archive_entry_rdevmajor(entry),
178                     archive_entry_rdevminor(entry));
179                 break;
180         case AE_IFBLK:
181                 archive_string_sprintf(&mtree->buf,
182                     " type=block device=native,%d,%d\n",
183                     archive_entry_rdevmajor(entry),
184                     archive_entry_rdevminor(entry));
185                 break;
186         case AE_IFDIR:
187                 archive_strcat(&mtree->buf, " type=dir\n");
188                 break;
189         case AE_IFIFO:
190                 archive_strcat(&mtree->buf, " type=fifo\n");
191                 break;
192         case AE_IFREG:
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));
196                 break;
197         }
198
199         archive_entry_free(entry);
200
201         if (mtree->buf.length > 32768) {
202                 ret = (a->compressor.write)(a, mtree->buf.s, mtree->buf.length);
203                 archive_string_empty(&mtree->buf);
204         } else
205                 ret = ARCHIVE_OK;
206
207         return (ret == ARCHIVE_OK ? ret : ARCHIVE_FATAL);
208 }
209
210 static int
211 archive_write_mtree_finish(struct archive_write *a)
212 {
213         struct mtree_writer *mtree= a->format_data;
214
215         archive_write_set_bytes_in_last_block(&a->archive, 1);
216
217         return (a->compressor.write)(a, mtree->buf.s, mtree->buf.length);
218 }
219
220 static ssize_t
221 archive_write_mtree_data(struct archive_write *a, const void *buff, size_t n)
222 {
223         (void)a; /* UNUSED */
224         (void)buff; /* UNUSED */
225         return n;
226 }
227
228 static int
229 archive_write_mtree_destroy(struct archive_write *a)
230 {
231         struct mtree_writer *mtree= a->format_data;
232
233         if (mtree == NULL)
234                 return (ARCHIVE_OK);
235
236         archive_entry_free(mtree->entry);
237         archive_string_free(&mtree->buf);
238         free(mtree);
239         a->format_data = NULL;
240         return (ARCHIVE_OK);
241 }
242
243 int
244 archive_write_set_format_mtree(struct archive *_a)
245 {
246         struct archive_write *a = (struct archive_write *)_a;
247         struct mtree_writer *mtree;
248
249         if (a->format_destroy != NULL)
250                 (a->format_destroy)(a);
251
252         if ((mtree = malloc(sizeof(*mtree))) == NULL) {
253                 archive_set_error(&a->archive, ENOMEM,
254                     "Can't allocate mtree data");
255                 return (ARCHIVE_FATAL);
256         }
257
258         mtree->entry = NULL;
259         mtree->first = 1;
260         archive_string_init(&mtree->buf);
261         a->format_data = mtree;
262         a->format_destroy = archive_write_mtree_destroy;
263
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";
272
273         return (ARCHIVE_OK);
274 }