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 */ 33/* 34 * Portions Copyright 2006, Apple Computer, Inc. 35 * Christopher Ryan <ryanc@apple.com> 36*/ 37 38#include "config.h" 39#include <stdio.h> 40#include <unistd.h> 41#include <libgen.h> 42#include "xar.h" 43#include "arcmod.h" 44#include "b64.h" 45#include <errno.h> 46#include <string.h> 47#include "util.h" 48#include "linuxattr.h" 49#include "io.h" 50 51#ifdef HAVE_SYS_PARAM_H 52#include <sys/param.h> 53#endif 54 55#ifdef HAVE_SYS_STATFS_H /* Nonexistant future OS needs this */ 56#include <sys/statfs.h> 57#endif 58 59#ifdef HAVE_SYS_MOUNT_H 60#include <sys/mount.h> 61#endif 62 63#ifdef HAVE_SYS_XATTR_H 64#include <sys/xattr.h> 65#endif 66 67#ifndef EXT3_SUPER_MAGIC 68#define EXT3_SUPER_MAGIC 0xEF53 69#endif 70 71#ifndef JFS_SUPER_MAGIC 72#define JFS_SUPER_MAGIC 0x3153464a 73#endif 74 75#ifndef REISERFS_SUPER_MAGIC 76#define REISERFS_SUPER_MAGIC 0x52654973 77#endif 78 79#ifndef XFS_SUPER_MAGIC 80#define XFS_SUPER_MAGIC 0x58465342 81#endif 82 83#if defined(HAVE_SYS_XATTR_H) && defined(HAVE_LGETXATTR) && !defined(__APPLE__) 84 85struct _linuxattr_context{ 86 const char *file; 87 const char *attrname; 88 xar_ea_t ea; 89 void *buf; 90 int off; 91 int bufsz; 92}; 93 94#define LINUXATTR_CONTEXT(x) ((struct _linuxattr_context *)(x)) 95 96int32_t xar_linuxattr_read(xar_t x, xar_file_t f, void * buf, size_t len, void *context) { 97 98 if( !LINUXATTR_CONTEXT(context)->buf ) { 99 int r; 100 LINUXATTR_CONTEXT(context)->bufsz = 1024; 101AGAIN2: 102 LINUXATTR_CONTEXT(context)->buf = malloc(LINUXATTR_CONTEXT(context)->bufsz); 103 if(!LINUXATTR_CONTEXT(context)->buf) 104 goto AGAIN2; 105 memset(LINUXATTR_CONTEXT(context)->buf, 0, LINUXATTR_CONTEXT(context)->bufsz); 106 r = lgetxattr(LINUXATTR_CONTEXT(context)->file, LINUXATTR_CONTEXT(context)->attrname, LINUXATTR_CONTEXT(context)->buf, LINUXATTR_CONTEXT(context)->bufsz); 107 if( r < 0 ) { 108 switch(errno) { 109 case ERANGE: LINUXATTR_CONTEXT(context)->bufsz *= 2; free(LINUXATTR_CONTEXT(context)->buf); goto AGAIN2; 110 case ENOTSUP: free(LINUXATTR_CONTEXT(context)->buf); return 0; 111 default: break; 112 }; 113 return -1; 114 } 115 LINUXATTR_CONTEXT(context)->bufsz = r; 116 } 117 118 if( (LINUXATTR_CONTEXT(context)->bufsz-LINUXATTR_CONTEXT(context)->off) <= len ) { 119 int32_t ret; 120 ret = LINUXATTR_CONTEXT(context)->bufsz - LINUXATTR_CONTEXT(context)->off; 121 memcpy(buf, ((char *)LINUXATTR_CONTEXT(context)->buf)+LINUXATTR_CONTEXT(context)->off, ret); 122 LINUXATTR_CONTEXT(context)->off += ret; 123 return(ret); 124 } else { 125 memcpy(buf, ((char *)LINUXATTR_CONTEXT(context)->buf)+LINUXATTR_CONTEXT(context)->off, len); 126 LINUXATTR_CONTEXT(context)->buf = ((char *)LINUXATTR_CONTEXT(context)->buf) + len; 127 return len; 128 } 129} 130 131int32_t xar_linuxattr_write(xar_t x, xar_file_t f, void *buf, size_t len, void *context) { 132 return lsetxattr(LINUXATTR_CONTEXT(context)->file, LINUXATTR_CONTEXT(context)->attrname, buf, len, 0); 133} 134#endif 135 136int32_t xar_linuxattr_archive(xar_t x, xar_file_t f, const char* file, const char *buffer, size_t len) 137{ 138#if defined(HAVE_SYS_XATTR_H) && defined(HAVE_LGETXATTR) && !defined(__APPLE__) 139 char *i, *buf = NULL; 140 int ret, retval=0, bufsz = 1024; 141 struct statfs sfs; 142 char *fsname = NULL; 143 struct _linuxattr_context context; 144 145 memset(&context,0,sizeof(struct _linuxattr_context)); 146 147 /* data from buffers don't have linuxattr */ 148 if(len) 149 return 0; 150 if( file == NULL ) 151 return 0; 152 153 if( !xar_check_prop(x, "ea") ) 154 return 0; 155 156TRYAGAIN: 157 buf = malloc(bufsz); 158 if(!buf) 159 goto TRYAGAIN; 160 ret = llistxattr(file, buf, bufsz); 161 if( ret < 0 ) { 162 switch(errno) { 163 case ERANGE: bufsz = bufsz*2; free(buf); goto TRYAGAIN; 164 case ENOTSUP: retval = 0; goto BAIL; 165 default: retval = -1; goto BAIL; 166 }; 167 } 168 if( ret == 0 ) goto BAIL; 169 170 memset(&sfs, 0, sizeof(sfs)); 171 statfs(file, &sfs); 172 173 switch(sfs.f_type) { 174 case EXT3_SUPER_MAGIC: fsname = "ext3"; break; /* assume ext3 */ 175 case JFS_SUPER_MAGIC: fsname = "jfs" ; break; 176 case REISERFS_SUPER_MAGIC:fsname = "reiser" ; break; 177 case XFS_SUPER_MAGIC: fsname = "xfs" ; break; 178 default: retval=0; goto BAIL; 179 }; 180 181 for( i=buf; (i-buf) < ret; i += strlen(i)+1 ) { 182 xar_ea_t e; 183 184 context.bufsz = 0; 185 context.off = 0; 186 context.buf = NULL; 187 context.file = file; 188 e = xar_ea_new(f, i); 189 xar_ea_pset(f, e, "fstype", fsname); 190 context.attrname = i; 191 context.ea = e; 192 XAR(x)->attrcopy_to_heap(x, f, xar_ea_root(e), xar_linuxattr_read,&context); 193 free(context.buf); 194 context.attrname = NULL; 195 } 196 197BAIL: 198 free(buf); 199 return retval; 200#endif 201 return 0; 202} 203 204int32_t xar_linuxattr_extract(xar_t x, xar_file_t f, const char* file, char *buffer, size_t len) 205{ 206#if defined HAVE_SYS_XATTR_H && defined(HAVE_LSETXATTR) && !defined(__APPLE__) 207 const char *fsname = "bogus"; 208 struct statfs sfs; 209 int eaopt = 0; 210 struct _linuxattr_context context; 211 xar_prop_t p; 212 213 memset(&context,0,sizeof(struct _linuxattr_context)); 214 215 /* data buffers, can't store linux attrs */ 216 if(len){ 217 return 0; 218 } 219 220 /* Check for EA extraction behavior */ 221 222 memset(&sfs, 0, sizeof(sfs)); 223 if( statfs(file, &sfs) != 0 ) { 224 char *tmp, *bname; 225 tmp = strdup(file); 226 bname = dirname(tmp); 227 statfs(bname, &sfs); 228 free(tmp); 229 } 230 switch(sfs.f_type) { 231 case EXT3_SUPER_MAGIC: fsname = "ext3"; break; /* assume ext3 */ 232 case JFS_SUPER_MAGIC: fsname = "jfs" ; break; 233 case REISERFS_SUPER_MAGIC:fsname = "reiser" ; break; 234 case XFS_SUPER_MAGIC: fsname = "xfs" ; break; 235 }; 236 237 for(p = xar_prop_pfirst(f); p; p = xar_prop_pnext(p)) { 238 const char *fs = NULL; 239 const char *prop; 240 const char *eaname = NULL; 241 xar_prop_t tmpp; 242 prop = xar_prop_getkey(p); 243 244 if( strncmp(prop, XAR_EA_FORK, strlen(XAR_EA_FORK)) != 0 ) 245 continue; 246 if( strlen(prop) != strlen(XAR_EA_FORK) ) 247 continue; 248 249 tmpp = xar_prop_pget(p, "fstype"); 250 if( tmpp ) 251 fs = xar_prop_getvalue(tmpp); 252 if( !eaopt && fs && strcmp(fs, fsname) != 0 ) { 253 continue; 254 } 255 if( !fs ) 256 continue; 257 258 tmpp = xar_prop_pget(p, "name"); 259 if( tmpp ) 260 eaname = xar_prop_getvalue(tmpp); 261 262 context.file = file; 263 context.attrname = eaname; 264 XAR(x)->attrcopy_from_heap(x, f, p, xar_linuxattr_write, &context); 265 266 } 267 268#endif 269 return 0; 270} 271