1/*
2 * Copyright (c) 2004 Rob Braun
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 * 3. Neither the name of Rob Braun nor the names of its contributors
14 *    may be used to endorse or promote products derived from this software
15 *    without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27 * POSSIBILITY OF SUCH DAMAGE.
28 */
29/*
30 * 26-Oct-2004
31 * DRI: Rob Braun <bbraun@synack.net>
32 * Ported from xar-unsaxy 16-Apr-2005
33 */
34/*
35 * Portions Copyright 2006, Apple Computer, Inc.
36 * Christopher Ryan <ryanc@apple.com>
37*/
38
39#include "config.h"
40#ifndef HAVE_ASPRINTF
41#include "asprintf.h"
42#endif
43#include <stdio.h>
44#include <unistd.h>
45#include "xar.h"
46#include "arcmod.h"
47#include <errno.h>
48#include <string.h>
49#include <fcntl.h>
50#include <sys/types.h>
51#include <sys/ioctl.h>
52#include "ext2.h"
53
54#ifdef HAVE_EXT2FS_EXT2_FS_H
55#include <ext2fs/ext2_fs.h>
56#else
57#if defined(HAVE_LINUX_EXT2_FS_H)
58typedef uint32_t u32;
59typedef uint8_t u8;
60#include <linux/ext2_fs.h>
61#endif
62#endif
63
64#define XAR_EXT2_FORK "ext2"
65
66#if defined(HAVE_EXT2FS_EXT2_FS_H) || defined(HAVE_LINUX_EXT2_FS_H)
67static void x_addprop(xar_file_t f, const char *name) {
68	char opt[1024];
69	memset(opt, 0, sizeof(opt));
70	snprintf(opt, sizeof(opt)-1, "%s/%s", XAR_ATTR_FORK, name);
71	xar_prop_set(f, opt, NULL);
72	xar_attr_set(f, opt, "fstype", "ext2");
73	return;
74}
75#endif
76
77int xar_ext2attr_archive(xar_t x, xar_file_t f, const char* file, const char *buffer, size_t len)
78{
79	int ret = 0;
80
81	/* if archiving from a buffer, then there is no place to get extattr */
82	if ( len )
83		return 0;
84
85#if defined(HAVE_EXT2FS_EXT2_FS_H) || defined(HAVE_LINUX_EXT2_FS_H)
86	int fd, flags=0, version;
87	char *vstr;
88	const char *opt;
89
90        xar_prop_get(f, "type", &opt);
91        if(!opt) return 0;
92        if( strcmp(opt, "file") != 0 ) {
93                if( strcmp(opt, "hardlink") != 0 )
94                	if( strcmp(opt, "directory") != 0 )
95				return 0;
96	}
97
98	fd = open(file, O_RDONLY);
99	if( fd < 0 ) {
100		return 0;
101	}
102	if( ioctl(fd, EXT2_IOC_GETVERSION, &version) < 0 ) {
103		ret = 0;
104		goto BAIL;
105	}
106	if( ioctl(fd, EXT2_IOC_GETFLAGS, &flags) < 0 ) {
107		ret = 0;
108		goto BAIL;
109	}
110
111	if( flags == 0 ) goto BAIL;
112
113	xar_prop_set(f, XAR_EXT2_FORK, NULL);
114	asprintf(&vstr, "%d", version);
115	xar_attr_set(f, XAR_EXT2_FORK, "version", vstr);
116	free(vstr);
117
118	if(! (flags & ~EXT2_SECRM_FL) )
119		x_addprop(f, "SecureDeletion");
120	if(! (flags & ~EXT2_UNRM_FL) )
121		x_addprop(f, "Undelete");
122	if(! (flags & ~EXT2_COMPR_FL) )
123		x_addprop(f, "Compress");
124	if(! (flags & ~EXT2_SYNC_FL) )
125		x_addprop(f, "Synchronous");
126	if(! (flags & ~EXT2_IMMUTABLE_FL) )
127		x_addprop(f, "Immutable");
128	if(! (flags & ~EXT2_APPEND_FL) )
129		x_addprop(f, "AppendOnly");
130	if(! (flags & ~EXT2_NODUMP_FL) )
131		x_addprop(f, "NoDump");
132	if(! (flags & ~EXT2_NOATIME_FL) )
133		x_addprop(f, "NoAtime");
134	if(! (flags & ~EXT2_DIRTY_FL) )
135		x_addprop(f, "CompDirty");
136	if(! (flags & ~EXT2_COMPRBLK_FL) )
137		x_addprop(f, "CompBlock");
138#ifdef EXT2_NOCOMPR_FL
139	if(! (flags & ~EXT2_NOCOMPR_FL) )
140		x_addprop(f, "NoCompBlock");
141#endif
142	if(! (flags & ~EXT2_ECOMPR_FL) )
143		x_addprop(f, "CompError");
144	if(! (flags & ~EXT2_BTREE_FL) )
145		x_addprop(f, "BTree");
146	if(! (flags & ~EXT2_INDEX_FL) )
147		x_addprop(f, "HashIndexed");
148	if(! (flags & ~EXT2_IMAGIC_FL) )
149		x_addprop(f, "iMagic");
150#ifdef EXT3_JOURNAL_DATA_FL
151	if(! (flags & ~EXT3_JOURNAL_DATA_FL) )
152		x_addprop(f, "Journaled");
153#endif
154	if(! (flags & ~EXT2_NOTAIL_FL) )
155		x_addprop(f, "NoTail");
156	if(! (flags & ~EXT2_DIRSYNC_FL) )
157		x_addprop(f, "DirSync");
158	if(! (flags & ~EXT2_TOPDIR_FL) )
159		x_addprop(f, "TopDir");
160	if(! (flags & ~EXT2_RESERVED_FL) )
161		x_addprop(f, "Reserved");
162
163BAIL:
164	close(fd);
165#endif
166	return ret;
167}
168
169#if defined(HAVE_EXT2FS_EXT2_FS_H) || defined(HAVE_LINUX_EXT2_FS_H)
170static int32_t e2prop_get(xar_file_t f, const char *name, char **value) {
171	char v[1024];
172
173	memset(v, 0, sizeof(v));
174	snprintf(v, sizeof(v)-1, "%s/%s", XAR_ATTR_FORK, name);
175	return xar_prop_get(f, v, (const char**)value);
176}
177#endif
178
179int xar_ext2attr_extract(xar_t x, xar_file_t f, const char* file, char *buffer, size_t len)
180{
181	/* if extracting to a buffer, then there is no place to write extattr */
182	if ( len )
183		return 0;
184
185#if defined(HAVE_EXT2FS_EXT2_FS_H) || defined(HAVE_LINUX_EXT2_FS_H)
186	int fd = -1, version, flags = 0;
187	char *tmp;
188
189	if( xar_prop_get(f, XAR_EXT2_FORK, NULL) == 0 ) {
190		const char *temp;
191		temp = xar_attr_get(f, XAR_EXT2_FORK, "version");
192		version = strtol(temp, NULL, 10);
193		fd = open(file, O_RDONLY);
194		if( fd < 0 )
195			return 0;
196		ioctl(fd, EXT2_IOC_SETVERSION, &version);
197	}
198
199	if( xar_prop_get(f, XAR_ATTR_FORK, NULL)  ) {
200		if( fd >= 0 ) close(fd);
201		return 0;
202	}
203
204	if( e2prop_get(f, "SecureDeletion", (char **)&tmp) == 0 )
205		flags |= EXT2_SECRM_FL;
206	if( e2prop_get(f, "Undelete", (char **)&tmp) == 0 )
207		flags |= EXT2_UNRM_FL ;
208	if( e2prop_get(f, "Compress", (char **)&tmp) == 0 )
209		flags |= EXT2_COMPR_FL ;
210	if( e2prop_get(f, "Synchronous", (char **)&tmp) == 0 )
211		flags |= EXT2_SYNC_FL ;
212	if( e2prop_get(f, "SystemImmutable", (char **)&tmp) == 0 )
213		flags |= EXT2_IMMUTABLE_FL ;
214	if( e2prop_get(f, "AppendOnly", (char **)&tmp) == 0 )
215		flags |= EXT2_APPEND_FL ;
216	if( e2prop_get(f, "NoDump", (char **)&tmp) == 0 )
217		flags |= EXT2_NODUMP_FL ;
218	if( e2prop_get(f, "NoAtime", (char **)&tmp) == 0 )
219		flags |= EXT2_NOATIME_FL ;
220	if( e2prop_get(f, "CompDirty", (char **)&tmp) == 0 )
221		flags |= EXT2_DIRTY_FL ;
222	if( e2prop_get(f, "CompBlock", (char **)&tmp) == 0 )
223		flags |= EXT2_COMPRBLK_FL ;
224#ifdef EXT2_NOCOMPR_FL
225	if( e2prop_get(f, "NoCompBlock", (char **)&tmp) == 0 )
226		flags |= EXT2_NOCOMPR_FL ;
227#endif
228	if( e2prop_get(f, "CompError", (char **)&tmp) == 0 )
229		flags |= EXT2_ECOMPR_FL ;
230	if( e2prop_get(f, "BTree", (char **)&tmp) == 0 )
231		flags |= EXT2_BTREE_FL ;
232	if( e2prop_get(f, "HashIndexed", (char **)&tmp) == 0 )
233		flags |= EXT2_INDEX_FL ;
234	if( e2prop_get(f, "iMagic", (char **)&tmp) == 0 )
235		flags |= EXT2_IMAGIC_FL ;
236#ifdef EXT3_JOURNAL_DATA_FL
237	if( e2prop_get(f, "Journaled", (char **)&tmp) == 0 )
238		flags |= EXT3_JOURNAL_DATA_FL ;
239#endif
240	if( e2prop_get(f, "NoTail", (char **)&tmp) == 0 )
241		flags |= EXT2_NOTAIL_FL ;
242	if( e2prop_get(f, "DirSync", (char **)&tmp) == 0 )
243		flags |= EXT2_DIRSYNC_FL ;
244	if( e2prop_get(f, "TopDir", (char **)&tmp) == 0 )
245		flags |= EXT2_TOPDIR_FL ;
246
247	if( fd < 0 ) {
248		fd = open(file, O_RDONLY);
249		if( fd < 0 )
250			return 0;
251	}
252
253	ioctl(fd, EXT2_IOC_SETFLAGS, &flags);
254	close(fd);
255#endif
256	return 0;
257}
258